0

I have used the following code for accessing eeprom :

void EEPROM_write(unsigned int uiAddress,unsigned char ucData)
{
   while(EECR & (1<<EEWE))
   {
      //do nothing
   }

   while(SPMCR & (1<<SPMEN));
   EEAR = uiAddress;
   EEDR = ucData;
   EECR |= (1<<EEMWE);
   EECR |= (1<<EEWE);
}

char EEPROM_read(unsigned int uiAddress)
{
   while(EECR & (1<<EEWE))
   {
      //do nothing
   }

   EEAR = uiAddress;
   EECR |=(1<<EERE);
   return EEDR;
}

void EEPROM_write_str(unsigned int uiAddress,unsigned char* string,unsigned int size)
{
   int i;
   for(i=0;i<size;i++)
   {
      EEPROM_write(uiAddress+i,string[i]);
   }
}

void EEPROM_read_str(unsigned int uiAddress,unsigned char* string,unsigned int size)
{
   int i;
   for(i=0;i<size;i++)
   {
      string[i] = EEPROM_read(uiAddress+i);
   }
}

char str[]="hello ";
char str2[20];

int main()
{
   usart_init(12);
   //EEPROM_write_str(0,str,6);
   EEPROM_read_str(0,str2,6);
   usart_puts(str2,6);
}

In the above code, I first commented the EEPROM_read_str and usart_puts,...flashed it then commented the EEPROM_write_str function and removed comments from the other two and flashed again.despite this, the data does not get stored and the output shown in the terminal is yyyyy (hex- FF). What is the problem here?   (Here USART_puts transmits the string taking the second argument as number of characters)

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
nalostta
  • 43
  • 1
  • 9
  • There is eeprom at address 0? Where do you erase the eeprom before write? – Lundin Aug 08 '17 at 09:48
  • @Lundin It is EEPROM at address 0 to 1023 I guess – nalostta Aug 08 '17 at 10:39
  • @Lundin AVR-s are Hardvare architecture and all memories have separated address spaces. AVR have the option to to it during the write. The cell is erased and written in one go. It called by atmel as an "atomic eeprom write" – 0___________ Aug 10 '17 at 15:01

2 Answers2

0

Working code from my old avr project. I do not use them for years so provide as is, as I do not remember exact meaning of the bits now

void EEPROM_write(uint8_t addr, uint8_t value) {
    while(EECR & (1 << EEPE)) ;             //wait for write enable bit to clear
    EECR &= ~((1 << EEPM1) | (1 << EEPM0)); // (erase & write in one operation)
    EEARL = addr;                           // set the address
    EEDR = value;                           // set value to be written
    EECR |= (1 << EEMPE);                       // set EEPROM Master Write Enable
    EECR |= (1 << EEPE);                        // set EEPROM Master Write Enable
}

uint8_t EEPROM_read(uint8_t addr) {
    while(EECR & (1 << EEPE)) ;             
    EEARL = addr;                           // set the address
    EECR |= (1 << EERE);
    return EEDR;
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • The problem is not there....when I execute both write and read operations in one go, the data is returned the same, however, resetting the controller leads to an erase of the data... – nalostta Aug 08 '17 at 09:34
  • This code is used in the device sold in ten of thousands - and it always kept the value. The first byte is quite tricky - sometimes it gets destroyed on some series of uC (different batches one is ok anothe not) so avoid the first byte, and remember about power as well. – 0___________ Aug 08 '17 at 09:39
  • Try my one ond chech then – 0___________ Aug 08 '17 at 09:40
  • "The first byte is quite tricky - sometimes it gets destroyed" Eh? Is this some known errata? Otherwise that sounds mighty fishy, I'd suspect timing or eeprom pre-scaler clock bugs. – Lundin Aug 08 '17 at 09:44
  • I had this problem 5+ years ago. Same model from the official distributor - just different batches and on some of them first byte value was lost. I did much deeper investigation but now I do not remember the conclusions - as I have stopped using AVRs several years ago - Cortex uC just started to be cheaper than AVRs, having much more computing power and better peripherals – 0___________ Aug 08 '17 at 09:49
  • @PeterJ I tried, the compiler gives error.it does not recognise EEMPE and EEPE and other such registers.In one file I had read that the newer chips supported these. Guess mine is the older one. – nalostta Aug 08 '17 at 10:28
0

This is from the source code companion files for AVR103 AVR EEPROM Application Note, the definitive publication from the device manufacturer.

char EEPROM_GetChar( unsigned int addr )
{
    do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
    EEAR = addr; // Set EEPROM address register.
    EECR = (1<<EERE); // Start EEPROM read operation.
    return EEDR; // Return the byte read from EEPROM.
}


void EEPROM_PutChar( unsigned int addr, char new_value )
{
    char old_value; // Old EEPROM value.
    char diff_mask; // Difference mask, i.e. old value XOR new value.

    unsigned char old_interrupt; // Stores interrupt flag while programming.
    old_interrupt = __save_interrupt(); // Save interrupt flag state.
    __disable_interrupt(); // Ensure atomic operation for the write operation.

    do {} while( EECR & (1<<EEPE) ); // Wait for completion of previous write.
    #ifndef EEPROM_IGNORE_SELFPROG
    do {} while( SPMCSR & (1<<SELFPRGEN) ); // Wait for completion of SPM.
    #endif

    EEAR = addr; // Set EEPROM address register.
    EECR = (1<<EERE); // Start EEPROM read operation.
    old_value = EEDR; // Get old EEPROM value.
    diff_mask = old_value ^ new_value; // Get bit differences.

    // Check if any bits are changed to '1' in the new value.
    if( diff_mask & new_value ) {
        // Now we know that _some_ bits need to be erased to '1'.

        // Check if any bits in the new value are '0'.
        if( new_value != 0xff ) {
            // Now we know that some bits need to be programmed to '0' also.

            EEDR = new_value; // Set EEPROM data register.
            EECR = (1<<EEMPE) | // Set Master Write Enable bit...
                   (0<<EEPM1) | (0<<EEPM0); // ...and Erase+Write mode.
            EECR |= (1<<EEPE);  // Start Erase+Write operation.
        } else {
            // Now we know that all bits should be erased.

            EECR = (1<<EEMPE) | // Set Master Write Enable bit...
                   (1<<EEPM0);  // ...and Erase-only mode.
            EECR |= (1<<EEPE);  // Start Erase-only operation.
        }
    } else {
        // Now we know that _no_ bits need to be erased to '1'.

        // Check if any bits are changed from '1' in the old value.
        if( diff_mask ) {
            // Now we know that _some_ bits need to the programmed to '0'.

            EEDR = new_value;   // Set EEPROM data register.
            EECR = (1<<EEMPE) | // Set Master Write Enable bit...
                   (1<<EEPM1);  // ...and Write-only mode.
            EECR |= (1<<EEPE);  // Start Write-only operation.
        }
    }

    __restore_interrupt( old_interrupt ); // Restore interrupt flag state.
}


void main()
{
    char t; // Temporary byte.
    unsigned int addr = 0x10; // EEPROM address to use.

    // Test the EEPROM_GetChar() function.
    t = EEPROM_GetChar( addr );

    // Try erasing the whole byte.
    EEPROM_PutChar( addr, 0xff );

    // Try changing a few bits to '0'.
    EEPROM_PutChar( addr, 0x0f );

    // Try changing bits both ways.
    EEPROM_PutChar( addr, 0xf0 );

    // Try changing nothing.
    EEPROM_PutChar( addr, 0xf0 );

    // Restore old value.
    EEPROM_PutChar( addr, t );

    for(;;); // Loop forever.
}
TomServo
  • 7,248
  • 5
  • 30
  • 47
  • My compiler (atmel studio 7 ) shows EEMPE as errors ....it understands the older commands (EEMWE) – nalostta Aug 10 '17 at 15:07
  • That document was written long ago and some register names may have changed slightly in newer AVR parts. Please check your part datasheet for current register names. But rest assured the algorithm has stayed the same. – TomServo Aug 10 '17 at 15:26