Search code examples
cmemorymicrocontrollereeprom

Storing data in EEPROM, MICROCONTROLLER


I'm working with a MCF51EM256 Freescale microcontroller and I've some problems to store some data in the EEPROM to make it persistent.

I need to store this struct in EEPROM:

typedef struct {
  ui64_s Ea_ps; 
  ui64_s Ea_ng;  
  ui64_s Er_q1;
  ui64_s Er_q2;
  ui64_s Er_q3;
  ui64_s Er_q4;
  uint16 F_ea;
  uint16 F_er;
}Ws_EnergyAcc64;

Where:

typedef union{    
  uint64 v;
  uint32 p[2];  
} ui64_s;

and:

typedef unsigned long long int uint64;
typedef unsigned long int uint32;
typedef unsigned short int uint16;

In order to do this, I've implemented this functions:

void Save_EEPROM_WsEnergyAcc(long addr, Ws_EnergyAcc64* Acc) {

  // WsEnergyAcc struct needs 56 bytes in EEPROM

  uint32 F_ea_32 = (uint32) Acc->F_ea;
  uint32 F_er_32 = (uint32) Acc->F_er;

  Flash_Burst(addr, 2, Acc->Ea_ps.p);
  Flash_Burst(addr + 8, 2, Acc->Ea_ng.p);
  Flash_Burst(addr + 16, 2, Acc->Er_q1.p);
  Flash_Burst(addr + 24, 2, Acc->Er_q2.p);
  Flash_Burst(addr + 32, 2, Acc->Er_q3.p);
  Flash_Burst(addr + 40, 2, Acc->Er_q4.p);

  Flash_Burst(addr + 48, 2, &F_ea_32);
  Flash_Burst(addr + 52, 2, &F_er_32);

}

Where "Flash_Burst":

#define Flash_Burst(Address, Size, DataPtr) \
      Flash_Cmd((UINT32)Address, (UINT16)Size, (UINT32*)DataPtr, FLASH_BURST_CMD)

UINT8 /*far*/ 
Flash_Cmd(UINT32 FlashAddress, 
      UINT16 FlashDataCounter, 
      UINT32 *pFlashDataPtr, 
      UINT8 FlashCommand)
{
  /* Check to see if FACCERR or PVIOL is set */
  if (FSTAT &0x30)  
  {         
      /* Clear Flags if set*/
      FSTAT = 0x30;  
  }

  if (FlashDataCounter)
  {
    do
    {
        /* Wait for the Last Busrt Command to complete */
        while(!(FSTAT&FSTAT_FCBEF_MASK)){};/*wait until termination*/

        /* Write Data into Flash*/
        (*((volatile unsigned long *)(FlashAddress))) = *pFlashDataPtr;
        FlashAddress += 4;
        pFlashDataPtr++;

        /* Write Command */
        FCMD = FlashCommand;

        /* Put FCBEF at 1 */
        FSTAT = FSTAT_FCBEF_MASK;

        asm (NOP);
        asm (NOP);
        asm (NOP);

         /* Check if Flash Access Error or Protection Violation Error are Set */
        if (FSTAT&0x30)
        {     
          /* If so, finish the function returning 1 to indicate error */
          return (1);
        }

    }while (--FlashDataCounter);
  }
  /* wait for the last command to complete */
  while ((FSTAT&FSTAT_FCCF_MASK)==0){};/*wait until termination*/

  /* Return zero to indicate that the function executed OK */
  return (0);
}

and:

void Init_EEPROM_WsEnergyAcc(long addr, Ws_EnergyAcc64* Acc) {

  uint32 F_ea_32;
  uint32 F_er_32;

  Acc->Ea_ps.p[0] = *(uint32 *)addr;
  addr = addr + 4;
  Acc->Ea_ps.p[1] = *(uint32 *)addr;
  Acc->Ea_ps.v = (uint64) Acc->Ea_ps.p[0] << 32 | Acc->Ea_ps.p[1];

  addr = addr + 4;
  Acc->Ea_ng.p[0] = *(uint32 *)addr;
  addr = addr + 4;
  Acc->Ea_ng.p[1] = *(uint32 *)addr;
  Acc->Ea_ng.v = (uint64) Acc->Ea_ng.p[0] << 32 | Acc->Ea_ng.p[1];

  addr = addr + 4;
  Acc->Er_q1.p[0] = *(uint32*)addr;
  addr = addr + 4;
  Acc->Er_q1.p[1] = *(uint32*)addr;
  Acc->Er_q1.v = (uint64) Acc->Er_q1.p[0] << 32 | Acc->Er_q1.p[1];

  addr = addr + 4;
  Acc->Er_q2.p[0] = *(uint32*)addr;
  addr = addr + 4;
  Acc->Er_q2.p[1] = *(uint32*)addr;
  Acc->Er_q2.v = (uint64) Acc->Er_q2.p[0] << 32 | Acc->Er_q2.p[1];

  addr = addr + 4;
  Acc->Er_q3.p[0] = *(uint32*)addr;
  addr = addr + 4;
  Acc->Er_q3.p[1] = *(uint32*)addr;
  Acc->Er_q3.v = (uint64) Acc->Er_q3.p[0] << 32 | Acc->Er_q3.p[1];  

  addr = addr + 4;
  Acc->Er_q4.p[0] = *(uint32*)addr;
  addr = addr + 4;
  Acc->Er_q4.p[1] = *(uint32*)addr;
  Acc->Er_q4.v = (uint64) Acc->Er_q4.p[0] << 32 | Acc->Er_q4.p[1];  

  addr = addr + 4;
  F_ea_32 = *(uint32*) addr;
  Acc->F_ea = (uint16) F_ea_32;

  addr = addr + 4;
  F_er_32 = *(uint32*) addr;
  Acc->F_er = (uint16) F_er_32;

}

For testing my functions, I did a little test program:

void testEEPROM(Ws_EnergyAcc64* Acc){

      Ws_EnergyAcc64 checkStruct;

      Acc->Ea_ps.p[0] = 0x10000000;
      Acc->Ea_ps.p[1] = 0x10000000;
      Acc->Ea_ng.p[0] = 0x10000000;
      Acc->Ea_ng.p[1] = 0x10000000;
      Acc->Er_q1.p[0] = 0x10000000;
      Acc->Er_q1.p[1] = 0x10000000;
      Acc->Er_q2.p[0] = 0x10000000;
      Acc->Er_q2.p[1] = 0x10000000;
      Acc->Er_q3.p[0] = 0x10000000;
      Acc->Er_q3.p[1] = 0x10000000;
      Acc->Er_q4.p[0] = 0x10000000;
      Acc->Er_q4.p[1] = 0x10000000;
      Acc->F_ea = 0x0000;
      Acc->F_er = 0x0000;

     Save_EEPROM_WsEnergyAcc(PhR_ABS_Ws_addr, Acc);

     Acc->Ea_ps.p[0] = 0x10011001;
     Acc->Ea_ps.p[1] = 0x10011002;
     Acc->Ea_ng.p[0] = 0x10011003;
     Acc->Ea_ng.p[1] = 0x10011004;
     Acc->Er_q1.p[0] = 0x10011005;
     Acc->Er_q1.p[1] = 0x10011006;
     Acc->Er_q2.p[0] = 0x10011007;
     Acc->Er_q2.p[1] = 0x10011008;
     Acc->Er_q3.p[0] = 0x10011009;
     Acc->Er_q3.p[1] = 0x1001100A;
     Acc->Er_q4.p[0] = 0x1001100B;
     Acc->Er_q4.p[1] = 0x1001100C;
     Acc->F_ea = 0x0000;
     Acc->F_er = 0x0000;

     Save_EEPROM_WsEnergyAcc(PhR_ABS_Ws_addr, Acc);     
     Init_EEPROM_WsEnergyAcc(PhR_ABS_Ws_addr, &checkStruct);

     printf("%d\n", checkStruct.Ea_ps.p[0]);
     printf("%d\n", checkStruct.Ea_ps.p[1]);
     printf("%d\n", checkStruct.Ea_ng.p[0]);
     printf("%d\n", checkStruct.Ea_ng.p[1]);
     printf("%d\n", checkStruct.Er_q1.p[0]);
     printf("%d\n", checkStruct.Er_q1.p[1]);
     printf("%d\n", checkStruct.Er_q2.p[0]);
     printf("%d\n", checkStruct.Er_q2.p[1]);
     printf("%d\n", checkStruct.Er_q3.p[0]);
     printf("%d\n", checkStruct.Er_q3.p[1]);
     printf("%d\n", checkStruct.Er_q4.p[0]);
     printf("%d\n", checkStruct.Er_q4.p[1]);
}

If I write only one time in the EEPROM, it works, but if I write the EEPROM more times, like the example, it does not works, prints always 0x1000000.

Somebody can help me? Why does not works? If I can write one time, why I can't do it more times?

Thank you all!


Solution

  • Each time you want to write a EEPROM you mast erase it. First time it works, probably because of JTAG perform a mass erase.

    Take also note that the EEPROM in modern MCUs is emulated and use part of on chip flash memory. This explain better why you must erase it before writing.