Home > OS >  AVR internal EEPROM write function is not working properly
AVR internal EEPROM write function is not working properly

Time:09-23

those are the two functions of read and write

////////////EEPROM.c//////////////

void IEEPROM_Write(u16 A_u16Adress, u8 A_u8Data)
{
    /* Wait for completion of previous write */
    while(GET_BIT(EECR,EECR_EEWE)==1);
    /* Set up address and data registers */
    EEAR = A_u16Adress;
    EEDR = A_u8Data;
    /* Write logical one to EEMWE */
    SET_BIT(EECR,EECR_EEMWE);
    _delay_us(10);
    /* Start eeprom write by setting EEWE */
    SET_BIT(EECR,EECR_EEWE);
}


u8 IEEPROM_Read(u16 A_u16Adress)
{
    /* Wait for completion of previous write */
    while(GET_BIT(EECR,EECR_EEWE)==1);
    /* Set up address and data registers */
    EEAR = A_u16Adress;
    /* Start eeprom read by setting EERE */
    SET_BIT(EECR,EECR_EERE);

    return EEDR;
}
////////////EEPROM.h//////////////

#define EEARH (*(volatile u8 *)0x3F)
#define EEARL (*(volatile u8 *)0x3E)
#define EEAR (*(volatile u16 *)0x3E)
#define EECR (*(volatile u8 *)0x3C)
#define EECR_EERE 0
#define EECR_EEWE 1
#define EECR_EEMWE 2
#define EECR_EERIE 3

#define EEDR (*(volatile u8 *)0x3D)
void IEEPROM_Write(u16 A_u16Adress, u8 A_u8Data);
u8 IEEPROM_Read(u16 A_u16Adress);

I followed the instructions of the ATMEGA32 Datasheet but it the code doesn't work I write a number on a byte then I read it and display it on LCD , but it prints 255,

CodePudding user response:

Do not delay between setting EEMWE and setting EEWE. The data sheet says, emphasis by me:

When EEMWE is set, setting EEWE within four clock cycles will write data to the EEPROM at the selected address. If EEMWE is zero, setting EEWE will have no effect. When EEMWE has been written to one by software, hardware clears the bit to zero after four clock cycles.


I removed it but still same problem

Then I assume that SET_BIT is a function or macro that takes more than four clock cycles. You might want to edit your question and show us the definition of it.

Replace it with appropriate code, to make sure that it is equivalent to:

    EECR |= 1 << EEMWE;
    EECR |= 1 << EEWE;

Of course, no interrupts must occur in between.

The data sheet additionally mentions:

The EEPROM can not be programmed during a CPU write to the Flash memory. The software must check that the Flash programming is completed before initiating a new EEPROM write.

Therefore it recommends to wait until SPMEN in SPMCR becomes zero. However, I see this as optional if you are sure that no Flash programming takes place.

CodePudding user response:

EECR register is within the lower IO registers range, which bits can be accessed by single bits using sbi and cbi processor instructions.

Operations like EECR |= 1 << EEMWE will be compiled as a single bit access. But, according to the datasheet you have to

  1. Write a logical one to the EEMPE bit while writing a zero to EEPE in EECR.

  2. Within four clock cycles after setting EEMPE, write a logical one to EEPE.

That means, when sbi is used, a zero will not be written to EEPE. Instead, use assignment:

EECR = (EECR & ~(1 << EEPE)) | (1 << EEMPE)

or simple EECR = (1 << EEMPE) (writing zero to all other bits)

Also, as it was noted, setting EEPE has to be done within 4 cpu clock cycles.

Here is a working example of EEPROM writing code:

void eeprom_write(ee_addr_type addr, uint8_t val) {
  while (EECR & (1 << EEPE)); // wait for the previous EEPROM operation to complete
  uint8_t old_sreg = SREG; // Save flags (including I flag)
  asm volatile("cli":::"memory"); // locking interrupts
  while (EECR & (1 << EEPE)); // just for the case EEPROM operation was started in the interrupt, wait again
  EEAR = addr; 
  EECR |= (1 << EERE); // reading the EEPROM content
  uint8_t d = EEDR;
  if (d != val) { // Programming only if needed
    uint8_t eecr_val;
    if (val == 0xFF) { // If all bits need to be set then 
      eecr_val = (1 << EEPM0); // Erase only mode
    } else if ((d & val) == val) { // If all bits are only changing from 1 to 0 then
      eecr_val = (1 << EEPM1); // Write only mode
    } else {
      eecr_val = 0; // Otherwise erase and write
    }
    EEDR = val;
    EECR = eecr_val | (1<<EEMPE);
    EECR |= (1<<EEPE);
  }
  SREG = old_sreg; // Restoring interrupt flag (enable interrupts only if they were enabled at the beginning)
}

this function exits while EEPROM operation is ongoing, you have to check it is done before reading the EEPROM

SHRINK uint8_t eeprom_read(ee_addr_type addr) {
  while(EECR & (1<<EEPE)); // wait for the previous EEPROM operation to complete
  uint8_t old_sreg = SREG;
  asm volatile("cli":::"memory"); // Lock interrupts
  while(EECR & (1<<EEPE)); 
  EEAR = addr;
  EECR |= (1<<EERE);
  uint8_t res = EEDR;
  SREG = old_sreg; // Restore interrupts
  return res;
}

  • Related