Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Еще одни грабли от IAR AVR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
ArtemKAD
При чтении ЕЕPROM в прерывании нет сохранения регистров адреса/данных(EEAR EEDR). Или что то-же самое - не защищаются от прерываний участок с момента записи EEAR EEDR до собственно подачи комманды чтения/записи.
Результат - при работе с ЕЕPROM в прерывании возможна ситация когда разрушаются адрес или данные в операции чтения/записи из основного цикла. В связи с редкостью подобного события возможен крайне трудноуловимый глюк angry.gif ...
arttab
Какая версия IAR?
Сергей Борщ
Цитата(ArtemKAD @ Jul 19 2006, 22:55) *
При чтении ЕЕPROM в прерывании нет сохранения регистров адреса/данных(EEAR EEDR). Или что то-же самое - не защищаются от прерываний участок с момента записи EEAR EEDR до собственно подачи комманды чтения/записи.
Грабли не в компиляторе.
Вопрос первый: Зачем запрещать прерывания если программа уже находится в прерывании?
Из него плавно вытекает второй: как компилятор определит что в одном случае функция вызвана из прерывания и запрещать не нужно а в другом случае из фона и запрещать нужно?
В том виде в каком оно есть все прекрасно работает из фона _без_ лишних накладных расходов - запретов/разрешений прерываний и сохранения/восстановления регистров. Если уж вы решили извратиться и работать с eeprom в прерывании (что само по себе уже глюк, только алгоритма) то уж будьте добры возьмите на себя труд сделать все эти лишние действия вручную и там где по-вашему они необходимы.

P.S. А еще он за пивом не бегает, вот это меня бесит больше всего.
Семён
Цитата(ArtemKAD @ Jul 19 2006, 23:55) *
При чтении ЕЕPROM в прерывании нет сохранения регистров адреса/данных(EEAR EEDR). Или что то-же самое - не защищаются от прерываний участок с момента записи EEAR EEDR до собственно подачи комманды чтения/записи.
Результат - при работе с ЕЕPROM в прерывании возможна ситация когда разрушаются адрес или данные в операции чтения/записи из основного цикла. В связи с редкостью подобного события возможен крайне трудноуловимый глюк angry.gif ...

Предпочитаю работать с EEPROM вот так из основного цикла программы, когда знаю что, все прерывания запрещены и не что мне не помешает:

void EEPROM_write(unsigned int adres,unsigned char data)
{
while(EECR & (1<<1));
EEAR=adres;
EEDR=data;
EECR |= (1<<2);
EECR |= (1<<1);
}

unsigned char EEPROM_read(unsigned int adres)
{
while(EECR & (1<<1));
EEAR=adres;
EECR |= (1<<0);
return EEDR;
}
ArtemKAD
Цитата(arttab @ Jul 20 2006, 04:42) *
Какая версия IAR?

Последняя не профи.
Цитата
Вопрос первый: Зачем запрещать прерывания если программа уже находится в прерывании?
Из него плавно вытекает второй: как компилятор определит что в одном случае функция вызвана из прерывания и запрещать не нужно а в другом случае из фона и запрещать нужно?

Компилятор должен был запретить прерывания при всех обращениях в основном цикле... Как - это уже отдельная тема. У компилятора более чем один способ решить этот вопрос.
Цитата
Если уж вы решили извратиться и работать с eeprom в прерывании (что само по себе уже глюк, только алгоритма)

Ну, не знал, что чтение в прерывании флагов сохраняемых в EEPROM в каком-то другом месте это глюк cranky.gif ...

Цитата(Семён @ Jul 20 2006, 11:35) *
Предпочитаю работать с EEPROM вот так из основного цикла программы, когда знаю что, все прерывания запрещены и не что мне не помешает:

void EEPROM_write(unsigned int adres,unsigned char data)
{
while(EECR & (1<<1));
EEAR=adres;
EEDR=data;
EECR |= (1<<2);
EECR |= (1<<1);
}

unsigned char EEPROM_read(unsigned int adres)
{
while(EECR & (1<<1));
EEAR=adres;
EECR |= (1<<0);
return EEDR;
}

Вы не поверите - компилятор делает так-же biggrin.gif ... Вот только представте, что произойдет если EEPROM_write было вызвано при не запрещенных прерываниях, а в прерывании вызвано EEPROM_read. И это самое прерывание попало между
EEAR=adres; и EEDR=data;
Результат ясен?

Тоже самое когда без запрета прерывания будет вызван EEPROM_read. Только там последствия сразу не столь разрушительные....
TomaT
Может и бывает нужда такая, но я не очень понимаю зачем рабочие флаги используемые в прерывании тащить из EEPROM? ИМХО это изврат.
Почему их нельзя объявить в ОЗУ, проинициализировать из EEPROM'a и по мере надобности аккуратно сливать их туда в фоне?
Семён
[quote name='ArtemKAD' date='Jul 20 2006, 12:59' post='135966']

[/quote]
Вы не поверите - компилятор делает так-же biggrin.gif ... Вот только представте, что произойдет если EEPROM_write было вызвано при не запрещенных прерываниях, а в прерывании вызвано EEPROM_read. И это самое прерывание попало между
EEAR=adres; и EEDR=data;
Результат ясен?
[/quote]
Почему не поверю, поверю. Эти функции я взял в своё время из каково-то даташата. Но как я писал выше, при работе с EEPROM у меня всегда гарантировано, запрещены прерывания. Во вторых я пытаюсь, как можно меньше его использовать. Если его использую то как правила храню две копии данных с расчитыным для них CRC что-то типа:
struct DATA
{
unsigned char data1;
unsigned char data2;
unsigned char data3;
unsigned char data_crc;
}data;
Сергей Борщ
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *
Компилятор должен был запретить прерывания при всех обращениях в основном цикле... Как - это уже отдельная тема. У компилятора более чем один способ решить этот вопрос.
Огласите хотя бы один способ.
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *
Цитата
Если уж вы решили извратиться и работать с eeprom в прерывании (что само по себе уже глюк, только алгоритма)

Ну, не знал, что чтение в прерывании флагов сохраняемых в EEPROM в каком-то другом месте это глюк cranky.gif ...
Теперь знаете - вы сами на него напоролись. Для обхода приходится запрещать прерывания в основном цикле, хотя без этого можно было обойтись. Обращение к eeprom требует ожидания готовности eeprom, а ожидание чего-либо находясь в прерывании - ошибка алгоритма.
TomaT абсолютно прав. Копии данных, которые могут потребоваться в прерывании надо держать в ОЗУ. И грабли сразу исчезнут.
А главное, компилятор сразу станет не виноват.
ArtemKAD
Цитата(Сергей Борщ @ Jul 20 2006, 12:32) *
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *

Компилятор должен был запретить прерывания при всех обращениях в основном цикле... Как - это уже отдельная тема. У компилятора более чем один способ решить этот вопрос.
Огласите хотя бы один способ.

PUSH/POP-нуть глобальные временные регистры EEAR, EEDR...
Цитата
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *

Цитата
Если уж вы решили извратиться и работать с eeprom в прерывании (что само по себе уже глюк, только алгоритма)

Ну, не знал, что чтение в прерывании флагов сохраняемых в EEPROM в каком-то другом месте это глюк cranky.gif ...
Теперь знаете - вы сами на него напоролись. Для обхода приходится запрещать прерывания в основном цикле, хотя без этого можно было обойтись. Обращение к eeprom требует ожидания готовности eeprom, а ожидание чего-либо находясь в прерывании - ошибка алгоритма.

Даже при разрешенных прерываниях? Даже если ожидаемое событие все равно глобально должно поменять весь алгоритм работы? blink.gif
Цитата
TomaT абсолютно прав. Копии данных, которые могут потребоваться в прерывании надо держать в ОЗУ. И грабли сразу исчезнут.

Исправить эти грабли не сложно - сложнее на них не наступить особенно когда о "такой малости" в доках ни слова...
Сергей Борщ
Цитата(ArtemKAD @ Jul 20 2006, 13:58) *
Цитата(Сергей Борщ @ Jul 20 2006, 12:32) *

Цитата(ArtemKAD @ Jul 20 2006, 12:04) *

Компилятор должен был запретить прерывания при всех обращениях в основном цикле... Как - это уже отдельная тема. У компилятора более чем один способ решить этот вопрос.
Огласите хотя бы один способ.

PUSH/POP-нуть глобальные временные регистры EEAR, EEDR...
Он это должен сделать тогда и только тогда когда вызов идет из прерывания. Во всех остальных случаях это будут ненужные накладные расходы. Как компилятор определит, что вызов делается из прерывания?
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *
Цитата
Обращение к eeprom требует ожидания готовности eeprom, а ожидание чего-либо находясь в прерывании - ошибка алгоритма.

Даже при разрешенных прерываниях? Даже если ожидаемое событие все равно глобально должно поменять весь алгоритм работы? blink.gif
?? Ожидается готовность eeprom. Что значит при разрешенных прерываниях? Мы уже внутри обработчика.
Цитата
Исправить эти грабли не сложно - сложнее на них не наступить особенно когда о "такой малости" в доках ни слова...
Нет, компилятор тут не при чем. Он физически не может тут ничем помочь. Если уж если вам так хочется поизвращаться - напишите обертку для функции чтения из прерывания.
xemul
Цитата(ArtemKAD @ Jul 20 2006, 14:58) *
Даже если ожидаемое событие все равно глобально должно поменять весь алгоритм работы? blink.gif

И что? Взвести флажок и спокойно его обработать как асинхронное событие. Подобная обработка непосредственно в прерывании гарантирует Вам кучку головной боли, хотя, конечно, событие будет обработано на несколько микросекунд раньшеsmile.gif.
ArtemKAD
Цитата(Сергей Борщ @ Jul 20 2006, 14:17) *
Цитата(ArtemKAD @ Jul 20 2006, 13:58) *

Цитата(Сергей Борщ @ Jul 20 2006, 12:32) *

Цитата(ArtemKAD @ Jul 20 2006, 12:04) *

Компилятор должен был запретить прерывания при всех обращениях в основном цикле... Как - это уже отдельная тема. У компилятора более чем один способ решить этот вопрос.
Огласите хотя бы один способ.

PUSH/POP-нуть глобальные временные регистры EEAR, EEDR...
Он это должен сделать тогда и только тогда когда вызов идет из прерывания. Во всех остальных случаях это будут ненужные накладные расходы. Как компилятор определит, что вызов делается из прерывания?

Вы сами руцями указываете ему, что процедура является обработчиком...
Цитата
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *

Цитата
Обращение к eeprom требует ожидания готовности eeprom, а ожидание чего-либо находясь в прерывании - ошибка алгоритма.

Даже при разрешенных прерываниях? Даже если ожидаемое событие все равно глобально должно поменять весь алгоритм работы? blink.gif
?? Ожидается готовность eeprom. Что значит при разрешенных прерываниях? Мы уже внутри обработчика.

Именно так. Внутри обработчика (предворительно исключив собственную рекурсию если она могла быть) разрешается прерывание. Чего тут непонятного blink.gif ?
Сергей Борщ
Цитата(ArtemKAD @ Jul 20 2006, 14:49) *
Вы сами руцями указываете ему, что процедура является обработчиком...

Ну так напишите обертку и вручную используйте. Компилятор-то тут при чем?

Цитата(ArtemKAD @ Jul 20 2006, 12:04) *
Цитата
?? Ожидается готовность eeprom. Что значит при разрешенных прерываниях? Мы уже внутри обработчика.

Именно так. Внутри обработчика (предворительно исключив собственную рекурсию если она могла быть) разрешается прерывание. Чего тут непонятного blink.gif ?
Опс. Еще и вложенные прерывания организовать там, где можно просто тупо взять данные из копии в ОЗУ. Тогда не удивительно, что "грабли" :-)
ArtemKAD
Цитата(Сергей Борщ @ Jul 20 2006, 15:05) *
Цитата(ArtemKAD @ Jul 20 2006, 14:49) *

Вы сами руцями указываете ему, что процедура является обработчиком...

Ну так напишите обертку и вручную используйте. Компилятор-то тут при чем?
"Грабли" на то и грабли - мирный инструмент пока не получишь от него по носу... a14.gif Я уже говорил - исправить не сложно, сложно заметить...
Цитата
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *

Цитата
?? Ожидается готовность eeprom. Что значит при разрешенных прерываниях? Мы уже внутри обработчика.

Именно так. Внутри обработчика (предворительно исключив собственную рекурсию если она могла быть) разрешается прерывание. Чего тут непонятного blink.gif ?
Опс. Еще и вложенные прерывания организовать там, где можно просто тупо взять данные из копии в ОЗУ. Тогда не удивительно, что "грабли" :-)
Это не "грабли" - при вложении прерываний сразу ожидаешь неприятностей и особо обращаешь внимание на это место.
Ну а по поводу "там, где можно просто тупо взять" - просто и тупо иногда обработка того прерывания и без ЕЕPROM занимает сотни милисекунд. Оставлять запрещенными прерывания на подобное время мне как-то влом biggrin.gif .
IgorKossak
Судя по всему, никто из отвечавших здесь не заглянул сюда.
Что касается компилятора, то он и не должен строить предположения насчёт прерываний.
Для него EEPROM и система прерываний - две разные сути. Если пользователю вдруг захотелось эти сути объединить в своей задаче (требованиях), то пусть он (пользователь) этим и займётся, причём тут компилятор.
Кроме того, работа с EEPROM может влиять\зависеть не только от системы прерываний, но и на\от системы самопрограммирования. Что прикажете компилятору делать в этом случае? Опять будете обвешивать его ярлыками с "граблями" за то что не оправдал Ваших надежд?
xemul
Цитата
Судя по всему, никто из отвечавших здесь не заглянул сюда.

Угуsmile.gif. Я, если предполагается возможность попытки одновременной записи в EEPROM или записи более 1 байта, организую простенькую очередь и запись с верификацией. Состояние записи и состояние очереди проверяются по программному таймеру 8,2 мс (мне так удобнее). Если необходима и возможна запись в EEPROM, на время ее старта прерывания, естественно, запрещаются.
Все это давно работает на PIC'ах (потому и удобнее). На AVR сейчас плавно пытаюсь переползти, ощущения пока двойственные. И тоже нет флага четности. Может сразу в MSP податься?smile.gif
TomaT
Цитата(ArtemKAD @ Jul 20 2006, 14:58) *
...
Исправить эти грабли не сложно - сложнее на них не наступить особенно когда о "такой малости" в доках ни слова...


Выдержка из атмеловского даташита: 1111493779.gif
Caution: An interrupt between step 5 and step 6 will make the write cycle fail, since the
EEPROM Master Write Enable will time-out. If an interrupt routine accessing the
EEPROM is interrupting another EEPROM access, the EEAR or EEDR Register will be
modified, causing the interrupted EEPROM access to fail. It is recommended to have
the Global Interrupt Flag cleared during all the steps to avoid these problems.
ArtemKAD
Цитата(IgorKossak @ Jul 21 2006, 12:30) *
Судя по всему, никто из отвечавших здесь не заглянул сюда.

Уже заглянул blush.gif . Действительно нечто похожее уже обсуждали и в прикрепленном файле грабли были убраны.
Цитата
Что касается компилятора, то он и не должен строить предположения насчёт прерываний.
Для него EEPROM и система прерываний - две разные сути. Если пользователю вдруг захотелось эти сути объединить в своей задаче (требованиях), то пусть он (пользователь) этим и займётся, причём тут компилятор.

Там суть в глобальных ресурсах - сохраняет-же он при входе в прерывание SREG, так чем EEAR и EEDR хуже?
Цитата(TomaT @ Jul 21 2006, 13:46) *
Выдержка из атмеловского даташита: 1111493779.gif
Caution: An interrupt between step 5 and step 6 will make the write cycle fail, since the
EEPROM Master Write Enable will time-out. If an interrupt routine accessing the
EEPROM is interrupting another EEPROM access, the EEAR or EEDR Register will be
modified, causing the interrupted EEPROM access to fail. It is recommended to have
the Global Interrupt Flag cleared during all the steps to avoid these problems.

Тем более IAR-овцы должны были на эту выдержку обратить внимание sad.gif .
Сергей Борщ
Цитата(ArtemKAD @ Jul 21 2006, 23:29) *
Цитата
Что касается компилятора, то он и не должен строить предположения насчёт прерываний.
Для него EEPROM и система прерываний - две разные сути. Если пользователю вдруг захотелось эти сути объединить в своей задаче (требованиях), то пусть он (пользователь) этим и займётся, причём тут компилятор.

Там суть в глобальных ресурсах - сохраняет-же он при входе в прерывание SREG, так чем EEAR и EEDR хуже?
Поразительное упорство. А регисты таймера, портов, UARTa, АЦП и прочей периферии компилятор не должен сохранять при входе в прерывание? Нет? А чем они лучше чем EEAR, EEDR?

Цитата(ArtemKAD @ Jul 21 2006, 23:29) *
Цитата(TomaT @ Jul 21 2006, 13:46) *

Выдержка из атмеловского даташита: 1111493779.gif

Тем более IAR-овцы должны были на эту выдержку обратить внимание sad.gif .
Да не надо валить с больной головы на здоровую. Вам пять человек пытаются объяснить, что компилятор тут не при чем. Это не ИАРовцы, а Вы должны были прочитать эту выдержку и обратить на нее внимание. Ибо только Вам известно где Вы работаете с EEPROM - в прерывании, в основном цикле или и там и там. В двух случаях из упомянутых трех никаких "срадств защиты" на которых Вы настаиваете не требуется. И только в третьем случае нужно предохраняться. Но компилятор не имеет _никакой_ возможности определить какой метод пользуете Вы в своей программе. А поскольку обычно (грамотно) используют первые два подхода, то нет никакого резона перестраховываться и генерить лишний код на случай если кому-то придет в голову поизвращаться.
ArtemKAD
Цитата(Сергей Борщ @ Jul 22 2006, 13:03) *
Цитата(ArtemKAD @ Jul 21 2006, 23:29) *

Там суть в глобальных ресурсах - сохраняет-же он при входе в прерывание SREG, так чем EEAR и EEDR хуже?
Поразительное упорство.

smile.gif Я знаю smile.gif
Цитата
А регисты таймера, портов, UARTa, АЦП и прочей периферии компилятор не должен сохранять при входе в прерывание? Нет? А чем они лучше чем EEAR, EEDR?

Тем, что с этой самой переферией приходится работать самому. Т.е. ее в программе рассматриваешь как набор этих самых регистров. Т.е. в программе таймер ты видишь не как таймер, а как регистры. А ЕЕPROM компилятор представляет как ПАМЯТЬ в которую можно писать и из которой можно читать. Использование "потрохов" для работы с EEPROM для корректной работы выглядит как-то странно.
По сути похожий пример - при вызове библиотечной процедуры ей КАК-ТО передаются параметры и она что-то куда-то возвращает. А теперь представь, как-бы ты посмотрел на IAR, если-бы вызов процедуры в прерывании разрушал параметры вызова этой-же процедуры в основном цикле.
Сергей Борщ
Цитата(ArtemKAD @ Jul 22 2006, 13:42) *
Цитата(Сергей Борщ @ Jul 22 2006, 13:03) *

Цитата(ArtemKAD @ Jul 21 2006, 23:29) *

Там суть в глобальных ресурсах - сохраняет-же он при входе в прерывание SREG, так чем EEAR и EEDR хуже?
Поразительное упорство.

smile.gif Я знаю smile.gif
:-) Но все равно "не выйдет из тебя путёвого старика" :-)
Цитата
Цитата
А регисты таймера, портов, UARTa, АЦП и прочей периферии компилятор не должен сохранять при входе в прерывание? Нет? А чем они лучше чем EEAR, EEDR?

Тем, что с этой самой переферией приходится работать самому. Т.е. ее в программе рассматриваешь как набор этих самых регистров. Т.е. в программе таймер ты видишь не как таймер, а как регистры. А ЕЕPROM компилятор представляет как ПАМЯТЬ в которую можно писать и из которой можно читать.
Да, но об особенностях работы с этой памятью ты должен позаботиться сам. Тебя не удивляет ведь, что компилятор не запрещает прерывания при доступе к многобайтовым volatile - переменным? А ведь прерывание может изменить эту переменную посередине чтения в основном цикле. Хочешь атомарный доступ - ручками. Не хочешь - тебе виднее. Когда компиляторы научатся бегать за пивом я уволюсь - ибо тогда программы они смогут писать без меня и подавно.
Цитата
По сути похожий пример - при вызове библиотечной процедуры ей КАК-ТО передаются параметры и она что-то куда-то возвращает. А теперь представь, как-бы ты посмотрел на IAR, если-бы вызов процедуры в прерывании разрушал параметры вызова этой-же процедуры в основном цикле.
Попробуй вызвать таким манером библиотечную функцию strtok(). Получишь именно только что тобой описанное. Тебя это удивляет? Меня нет. Я знаю, что эта функция нереентерабельная (как и многие другие _библиотечные_ функции).

Резюмирую: компилятор в твоих граблях не виноват. Он еще много чего не умеет делать сам ибо это в принципе не возможно. Потому-то к нему программист в комплекте должен быть.
SasaVitebsk
Цитата(ArtemKAD @ Jul 20 2006, 12:04) *
Вы не поверите - компилятор делает так-же biggrin.gif ... Вот только представте, что произойдет если EEPROM_write было вызвано при не запрещенных прерываниях, а в прерывании вызвано EEPROM_read. И это самое прерывание попало между
EEAR=adres; и EEDR=data;
Результат ясен?

Тоже самое когда без запрета прерывания будет вызван EEPROM_read. Только там последствия сразу не столь разрушительные....


Кстати аналогичное может произойти не только с EEPROM. И не только в СИ. smile.gif

В своё время я нарвался на очень редко проявляющуюся ошибку. При выяснении причин выяснилось что в фоне я делаю сравнение 16-ти битного указателя кольцевого буфера (для определения XON/XOFF) Ну а в прерывании он изменяется. Так вот, если прерывание вызывается м/у сравнением 1-го и 2-ого байта, а в это время в прерывании осуществляется переход по кольцу ... то возникала ошибка. smile.gif

Поэтому если в прерывании изменяются какие-нибудь длинные переменные, то при работе с ними в голове надо или синхронизировать или запрещать прерывания.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.