В библиотеке 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; }
|