2025-06-23 8:46 AM
I am working on a H755zi-Q Nucleo board , I am using the flash memory to store some parameters and i have implemented flash wearing as well, All this works fine , my data persists across resets and is correctly loaded upon reset, and i have even verified this in the memory , in debug mode i see each page being written perfectly on every write command, when i upload a new code or sometimes when i terminate and relaunch the debug session and open memory , i see that data is erased. How do i prevent this?i want to retain that sector's data over flashes and debug sessions, the memory sector i am using is far away from my code's sector, (i am using bank 2 last sector).
This is my initial data in the memory, i have entered debug mode, and after performing a new write operation,
here we are again,
but from now if i keep performing write operations they are preserved correctly.
/*
* @brief Find the page of the memory sector to write the
* data of the params struct
*/
uint32_t FindLatestPage(void)
{
FlashPage *pages = (FlashPage *)FLASH_STORAGE_ADDR;
uint32_t latestSeq = 0;
uint32_t latestIdx = 0;
for (uint32_t i = 0; i < NUM_PAGES; i++)
{
if (pages[i].magic == 0xFFFFFFFF)
{
return (i == 0) ? 0 : i - 1; // Return last valid page
}
if (pages[i].magic == MAGIC_NUMBER && pages[i].sequence > latestSeq)
{
latestSeq = pages[i].sequence;
latestIdx = i;
}
}
return latestIdx; // Sector full, return last page
}
/*
* @brief Load data from the flash memory
* to populate the can param struct.
*/
void LoadFromFlash(void)
{
uint32_t idx = FindLatestPage();
FlashPage *page = (FlashPage *)(FLASH_STORAGE_ADDR + idx * PAGE_SIZE);
if (page->magic == MAGIC_NUMBER)
{
memcpy(&canparam, &page->data, sizeof(BMS_COMMAND_RECEPTION));
}
else
{
// Initialize with defaults if no valid data
memset(&canparam, 0, sizeof(BMS_COMMAND_RECEPTION));
SaveToFlash(0); // Start with page 0
}
}
/*
* @brief Save data to next page on the flash.
*/
HAL_StatusTypeDef SaveToFlash(uint32_t currentIdx)
{
HAL_StatusTypeDef status;
FLASH_EraseInitTypeDef eraseInit = {0};
uint32_t sectorError = 0;
static uint32_t sequence = 0;
uint32_t nextIdx = (currentIdx + 1) % NUM_PAGES;
// Check if sector is full (next page is used or wrapping to 0)
FlashPage *nextPage = (FlashPage *)(FLASH_STORAGE_ADDR + nextIdx * PAGE_SIZE);
if (nextIdx == 0 || nextPage->magic != 0xFFFFFFFF)
{
// Erase Sector 7 of Bank 2 when full
status = HAL_FLASH_Unlock();
if (status != HAL_OK) return status;
eraseInit.TypeErase = FLASH_TYPEERASE_SECTORS;
eraseInit.Banks = FLASH_BANK_2;
eraseInit.Sector = FLASH_SECTOR_7; // Sector 7 in Bank 2
eraseInit.NbSectors = 1;
status = HAL_FLASHEx_Erase(&eraseInit, §orError); // Fixed: Use sectorError
if (status != HAL_OK)
{
HAL_FLASH_Lock();
return status;
}
sequence = 0; // Reset sequence after erase
nextIdx = 0; // Start from page 0
HAL_FLASH_Lock();
}
// Write to the next page
status = HAL_FLASH_Unlock();
if (status != HAL_OK) return status;
FlashPage newPage;
newPage.magic = MAGIC_NUMBER;
newPage.sequence = ++sequence; // Increment sequence for each write
newPage.data = canparam;
uint8_t *data = (uint8_t *)&newPage;
uint32_t addr = FLASH_STORAGE_ADDR + nextIdx * PAGE_SIZE;
for (uint32_t i = 0; i < sizeof(FlashPage); i += 32)
{
status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, addr + i, (uint32_t)(data + i));
if (status != HAL_OK)
{
HAL_FLASH_Lock();
return status;
}
}
HAL_FLASH_Lock();
return HAL_OK;
}
/*
* @brief Update the parameter if changed and then save it
* to the next page on the flash memory.
*/
void UpdateParameter(uint16_t index, uint16_t value)
{
// Adjust index: Convert 1-based index to 0-based
if (index >= 1 && index <= 28)
{
uint8_t internalIndex = index - 1;
BMS_COMMAND_RECEPTION old = canparam;
canparam.audCommandDataArray[internalIndex] = value;
if (memcmp(&old, &canparam, sizeof(BMS_COMMAND_RECEPTION)) != 0)
{
uint32_t currentIdx = FindLatestPage();
if (SaveToFlash(currentIdx) != HAL_OK)
{
TRACE("ERROR UPDATING THE FLASH MEMORY (UPDATE PARAM FAILED)\r\n");
}
}
}
else
{
TRACE("Invalid index in UpdateParameter(): %d\r\n", index);
}
Here are my functions , if you think there is something wrong with this , do let me know.
Also any suggestions to make the code make more cleaner , i try to keep it clean add comments and briefs for functions as well , what else could be more helpful i am open to constructive criticism.
Thankyou.
2025-06-23 10:11 AM - edited 2025-06-23 10:13 AM
Ensure the pages are not marked to be written in the linker file. Generally, you don't want any references to them at all in there. The debugger only erases what it needs to by default.
Don't do any erases/writes to flash within the first 1 second if you want debugging to work.
2025-06-23 10:32 AM
in my linker file i don't have any references to that page, it is the last sector of my flash memory.
MEMORY
{
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 2048K
DTCMRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
RAM_D1 (xrw) : ORIGIN = 0x24000000, LENGTH = 512K
RAM_D2 (xrw) : ORIGIN = 0x30000000, LENGTH = 288K
RAM_D3 (xrw) : ORIGIN = 0x38000000, LENGTH = 64K
ITCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 64K
}
should i change the length of flash to exclude the last 128K sector ?
because here we only have the starting addresses and lengths?
and i am not performing any write/erase in the first second and debugging works fine, we just see some auto erases of flash memory due to the flashing of the code during debug session , this is what i think.
2025-06-23 11:28 AM
Yes, remove that section from the linker file.
When the debugger loads the program, it will list the sectors it erases before the code is loaded. Look in the Console output.
However, I don't think that's the problem here. It looks like your program is doing the erasing, as it is physically impossible to erase less than a flash page. Also, the "erased" screenshot you have above shows some portions of the page have been written.
I suggest looking for bugs in the code logic. Log messages to UART or some other readable output when erases and writes are done.