1
\$\begingroup\$

I use st eeprom library to save my variables. When I save a single variable, I do not have any problem. I can save it, refresh it and after disconnecting the power, I can read that variable. Now I want to save three different variables in three different pages, when I want to read them, I see the latest value in all of them. With this code I save the variables:

HAL_FLASH_Unlock();
EE_Init();
EE_WriteVariable(VirtAddVarTab[0], 10);
EE_WriteVariable(VirtAddVarTab[1], 20);
EE_WriteVariable(VirtAddVarTab[2], 30);
HAL_Delay(10);
EE_ReadVariable(VirtAddVarTab[0], &VarDataTab[0]);
EE_ReadVariable(VirtAddVarTab[1], &VarDataTab[1]);
EE_ReadVariable(VirtAddVarTab[2], &VarDataTab[2]);
HAL_FLASH_Lock();

After programing this code, I program this one:

HAL_FLASH_Unlock();
EE_Init();
EE_ReadVariable(VirtAddVarTab[0], &VarDataTab[0]);
EE_ReadVariable(VirtAddVarTab[1], &VarDataTab[1]);
EE_ReadVariable(VirtAddVarTab[2], &VarDataTab[2]);
HAL_FLASH_Lock();

And I see "30" in all of the memory them instead of 10,20,30 What is my problem?

page addresses :

#define ADDR_FLASH_PAGE_0     ((uint32_t)0x08000800) /* Base @ of Page 0, 1 Kbytes *///0x08000000
#define ADDR_FLASH_PAGE_1     ((uint32_t)0x08001000) /* Base @ of Page 1, 1 Kbytes *///0x08000400
#define ADDR_FLASH_PAGE_2     ((uint32_t)0x08001800) /* Base @ of Page 2, 1 Kbytes *///0x08000800
#define ADDR_FLASH_PAGE_3     ((uint32_t)0x08002000) /* Base @ of Page 3, 1 Kbytes *///0x08000C00
#define ADDR_FLASH_PAGE_4     ((uint32_t)0x08002800) /* Base @ of Page 4, 1 Kbytes *///0x08001000
#define ADDR_FLASH_PAGE_5     ((uint32_t)0x08003000) /* Base @ of Page 5, 1 Kbytes *///0x08001400
#define ADDR_FLASH_PAGE_6     ((uint32_t)0x08003800) /* Base @ of Page 6, 1 Kbytes *///0x08001800
#define ADDR_FLASH_PAGE_7     ((uint32_t)0x08004000) /* Base @ of Page 7, 1 Kbytes *///0x08001C00
#define ADDR_FLASH_PAGE_8     ((uint32_t)0x08004800) /* Base @ of Page 8, 1 Kbytes *///0x08002000
#define ADDR_FLASH_PAGE_9     ((uint32_t)0x08005000) /* Base @ of Page 9, 1 Kbytes *///0x08002400
#define ADDR_FLASH_PAGE_10    ((uint32_t)0x08005800) /* Base @ of Page 10, 1 Kbytes *///0x08002800

And I have two IROM IROM1 start address is 0x8000000 and its size is 0x400 IROM2 start address is 0x8000800 and its size is 0xF800

I define these in the beginning of the program :

uint16_t VirtAddVarTab[20];
uint16_t VarDataTab[20];

I did not initialize it. Do you mean I put for example 0 in the start and after that I use them?

\$\endgroup\$
12
  • \$\begingroup\$ Can you check the return values of the functions? It might indicate where things go wrong. Have you modified EEPROM_START_ADDRESS such that if fits your particular MCU? How do you initialize VirtAddVarTab? \$\endgroup\$
    – Codo
    Mar 15 '21 at 10:02
  • \$\begingroup\$ I defined these : uint16_t VirtAddVarTab[20]; uint16_t VarDataTab[20]; And this is the first page : #define ADDR_FLASH_PAGE_0 ((uint32_t)0x08000800) /* Base @ of Page 0, 1 Kbytes *///0x08000000 And I have two Iroms(IROM1 - IROM2) their addresses are (0x8000000(start address) - 0x400(size)) (0x8000800(start address) - 0xF800(size)) \$\endgroup\$
    – Hamed P
    Mar 15 '21 at 10:22
  • 1
    \$\begingroup\$ I assume you have a debugger. If not, get yourself one. Single step through your code and the problem should become clear. There is some merit in stepping through all of your code to check for correct operation. \$\endgroup\$
    – Kartman
    Mar 15 '21 at 11:36
  • 2
    \$\begingroup\$ So there's your problem: The EEPROM library basically has the concept of reading and writing key/value pairs. VirtAddVarTab is supposed to contain the keys. Since you don't initialize it, all keys are 0. So whatever you read and write, it will always be to and from key 0. That's why you get 30 as a result. \$\endgroup\$
    – Codo
    Mar 15 '21 at 11:37
  • 1
    \$\begingroup\$ @Codo yeah I suspected something like that. \$\endgroup\$
    – brhans
    Mar 15 '21 at 11:47
2
\$\begingroup\$

STM's pseudo EEPROM library offers an interface to read and write key/value pairs. Keys are uint16_t values. The array VirtAddVarTab is supposed to contain all possible keys.

Your code does not explicitly initialize VirtAddVarTab. So all keys are 0. Therefore, the code always writes to and reads from key 0.

To fix it, initialize VirtAddVarTab, e.g.:

uint16_t VirtAddVarTab[NB_OF_VAR] = { 0x100, 0x0102, 0x0200 };

While VirtAddVarTab is needed, you don't need to use it for EE_WriteVariable() and EE_ReadVariable(). (I assume you have copied it from STM's strange example code.)

An improved approach would be:

#define EE_KEY_COLOR       0x0100
#define EE_KEY_BRIGHTNESS  0x0102
#define EE_KEY_MODE        0x0200

uint16_t VirtAddVarTab[NB_OF_VAR] = { EE_KEY_COLOR, EE_KEY_BRIGHTNESS, EE_KEY_MODE };

uint16_t color;
uint16_t brightness;
uint16_t mode;

...

EE_ReadVariable(EE_KEY_COLOR, &color);
EE_ReadVariable(EE_KEY_BRIGHTNESS, &brightness);
EE_ReadVariable(EE_KEY_MODE , &mode);

VirtAddVarTab is required when a flash page has filled up and the active key/value pairs have to be transferred to another flash page. It's an unfortunate design decision by STM as it results in a mutual dependency between the project code and the library code.

STM's approach for the pseudo EEPROM is robust: it reduces flash wear and can recover even if power failed during write. However, the API is more complex than necessary, and the documentation – while covering the implementation in detail – insufficiently describes the usage.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for all your useful information \$\endgroup\$
    – Hamed P
    Mar 25 '21 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.