Electronic – How to store the last counting value in EEPROM in ATmega8 after power failure

atmegaavreepromtimer

I written a program to store the last counting value according to ATmega8 datasheet. but it didn't save the last value. The counter variable went to zero after power failure.

Please check the following code.

#define address1 0x00
#define address2 0x02 

//***********************************************************************//
void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
/* Wait for completion of previous write */
 while(EECR & (1<<EEWE));

 /* Set up Address and Data Registers */
 EEAR = uiAddress;
 EEDR = ucData;
 /* Write logical one to EEMWE */
 EECR |= (1<<EEMWE);
 /* Start eeprom write by setting EEWE */
 EECR |= (1<<EEWE);
 }


 unsigned char EEPROM_read(unsigned int uiAddress)
 {
 /* Wait for completion of previous write */
 while(EECR & (1<<EEWE));
 /* Set up Address Register */
 EEAR = uiAddress;
 /* Start eeprom read by writing EERE */
 EECR |= (1<<EERE);
 /* Return data from Data Register */
 return EEDR;
  }

 //**************************************************************************//
  
  int main(void)
  {  
   lcd_init();
   init_timer1();

    
   while(1)
    {
    
    EEPROM_write(address1,second);
    last_value=EEPROM_read(address1);
    
    sprintf(lcd,"Timer:%03d",last_value);
    dis_string(0,0,lcd);            
      } 
    }

    void init_timer1(void)
    {

     TCCR1B |=(1<<CS12); // prescaler set 256;new freq=31250;
     TCCR1B |=(1<<WGM12);  // 8mhz/256=31250; count in 1 sec
     TCNT1=0;         
     OCR1A=31315; //this amount of  tick count in 1 sec;
                  //after counting an interrupt generate;
     TIMSK |=(1<<OCIE1A);     
     sei();
     }

   ISR(TIMER1_COMPA_vect)
   {
   second++;
 
   if(second==60)
  {second=0;
   minute++;
     }
   }

Can anyone help me. need to solve urgently.
Thank you

Best Answer

  1. According to the parts of the code you've posted here you might exhaust EEPROM resource too soon that way. EEPROM has a limited number of erase-write cycles per cell. You are writing every time in a infinite loop without any sort of delay or even checking that your "second" value has been changed since last time. Atmega8 EEPROM cycle limit are listed as 100,000 erase-write cycles.

  2. You are doing read-modify-write when setting EEMWE: EECR |= (1<<EEMWE); But according to a datasheet you have to write zero to EEWE in the same operation. Yes, they listed this code in the datasheet but it's not really correct according to the description above. It will work if you write rarely, as after writing the hardware will clear the EEWE. But if you call this function too often, you might still be reading 1 from this bit and writing it back again resulting a loop of writing nothing due to this. I'd rather suggest changing this line to EECR = (1<<EEMWE);. But there are even better way below.

  3. As you are writing in C there is no need to reinvent the wheel. All EEPROM operations are already included with all C compilers for AVR I know. If you are working with AVR-GCC they have avr/eeprom.h header which adds all of them. See it's description here: https://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html. They have a nice functions eeprom_update_byte(...) which will ensure that the erase-write cycle will only occur if the data has been changed.

  4. Still that will mean that you will write every second. With 100000 writes that's less that 28 hours only. In reality EEPROM can handle much more cycles, but it's not a good thing to rely on that as manufacturer only guarantees those 100K cycles. If you really need to save state every second, you have to implement some sort of wear leveling. Which is usually done by writing to a different address each time in a circular manner. More information on this question are out of scope of this question.

  5. Also check "Preventing EEPROM Corruption" paragraph of the datasheet. If you will be writing to EEPROM during power failure it might cause EEPROM corruption resulting in reading back unidentified value next time. Again there is a lot of ways to circumvent those issues and make it reliable. But those are out of scope of this topic again.