Глюк при чтении 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!