cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Flashing or entering the debug mode performs a mass chip ERASE?

Obaid_tanveer
Associate II

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). 

Obaid_tanveer_0-1750693108289.png

This is my initial data in the memory, i have entered debug mode, and after performing a new write operation,  

Obaid_tanveer_1-1750693249684.png

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, &sectorError);  // 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.

3 REPLIES 3
TDK
Super User

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.

If you feel a post has answered your question, please click "Accept as Solution".

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.

  

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.

If you feel a post has answered your question, please click "Accept as Solution".