Глюк при чтении EEPROM у ATmega8, ATmega32, ATmega128 Добавил(а) microsin
В библиотеке avr-libc WinAVR (релиз 20080610) есть глюк, связанный с чтением EEPROM. В новых версиях WinAVR (например, релиз 20090313) этот глюк уже исправлен.
Глюк связан с неучтенным ERRATA "Reading EEPROM by using ST or STS to set EERE bit triggers unexpected interrupt request". Глюк проявляется на микроконтроллерах ATmega8, ATmega32, ATmega128 (на ATmega16 такого глюка почему-то нет). Проявляется глюк в непредсказуемом переходе в младшие адреса при вызовах подпрограмм c:\WinAVR-20080610\avr\include\avr\eeprom.h -> eeprom_read_byte, eeprom_read_word, eeprom_read_dword, eeprom_read_block. Несколько вызовов могут пройти нормально, но на каком-то определенном адресе может произойти сбой. Я с этой проблемой проковырялся долго, так как сначала думал, что ошибка у меня в программе.
Глюк таится в одной-единственной функции eeprom_read_byte (все остальные, как я понял, используют её вызовы, поэтому глюк наследуется). Код, на C, который есть в подпрограмме eeprom_read_byte (этот код устанавливает бит EERE), компилируется в ассемблерную инструкцию ST, которая и вызывает сбой. Старый глючный код eeprom.h:
__ATTR_PURE__ static __inline__ uint8_t eeprom_read_byte (const uint8_t *__p)
{
do {} while (!eeprom_is_ready ());
#if E2END <= 0xff="" br=""> EEARL = (unsigned)__p;
#else
EEAR = (unsigned)__p;
#endif
EECR |= (1 << EERE);
return EEDR;
}
Исправить проблему можно, если обновить WinAVR. Можно просто вручную поправить код, написав это место на ассемблере (для установки бита EERE надо использовать инструкцию OUT или SBI), например вот так:
__ATTR_PURE__ static __inline__ uint8_t eeprom_read_byte (const uint8_t *__p)
{
do {} while (!eeprom_is_ready ());
#if E2END <= 0xff="" br=""> EEARL = (unsigned)__p;
#else
EEAR = (unsigned)__p;
#endif
////////////////////////////////////////////////////////////
// here fixed ERRATA Bug "Reading EEPROM by using ST or STS
// to set EERE bit triggers unexpected interrupt request"
// EECR |= (1 << EERE);
__asm__ __volatile__ (
"sbi %[__eecr], %[__eere] \n\t"
:
: [__eecr] "i" (_SFR_IO_ADDR(EECR)),
[__eere] "i" (EERE)
);
return EEDR;
}
http://microsin.net/programming/avr-tro ... ouble.htmlПроверьте релиз вашей WinAVR!