cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with flash saving on STM32L4P5CGUX

kiwiosek2007
Associate II

I have a problem with saving settings to flash memory on STM32L4P5CGUX.

I made a settings menu for my project, and the settings should be stored in flash so they stay after power off. The problem is that only one setting gets saved — always the first one, no matter which setting I change.

After restarting the device, the other settings are lost or not loaded correctly.

What could cause this issue?

/**
 * @file  SettingsManager.c
 * @brief Persistent settings - stable version based on eeprom_emul.c
 */

#include "SettingsManager.h"
#include "stm32l4xx_hal.h"
#include <string.h>

/* Flash record (8 bytes) */
typedef struct __attribute__((packed)) {
    uint16_t magic;
    uint8_t  tempUnit;
    uint8_t  showEnv;
    uint8_t  colorScheme;
    uint8_t  language;
    uint8_t  saveCounter;
    uint8_t  reserved;
} Settings_FlashRecord_t;

_Static_assert(sizeof(Settings_FlashRecord_t) == 8, "Settings_FlashRecord_t must be 8 bytes!");

static Settings_t settings;

static const Settings_t defaults = {
    .tempUnit    = 0,
    .showEnv     = 0,
    .colorScheme = 0,
    .language    = 0
};

static void flash_load(void)
{
    const Settings_FlashRecord_t* rec = (const Settings_FlashRecord_t*)SETTINGS_FLASH_ADDRESS;

    if (rec->magic == SETTINGS_MAGIC)
    {
        settings.tempUnit    = rec->tempUnit;
        settings.showEnv     = rec->showEnv;
        settings.colorScheme = rec->colorScheme;
        settings.language    = rec->language;
    }
    else
    {
        settings = defaults;
    }
}

void Settings_Init(void)
{
    flash_load();
}

/* ================================================ */
/*  Save - modeled exactly after eeprom_emul.c     */
/* ================================================ */
static bool flash_save(void)
{
    Settings_FlashRecord_t rec;
    memset(&rec, 0xFF, sizeof(rec));

    rec.magic       = SETTINGS_MAGIC;
    rec.tempUnit    = settings.tempUnit;
    rec.showEnv     = settings.showEnv;
    rec.colorScheme = settings.colorScheme;
    rec.language    = settings.language;
    rec.saveCounter = 0x55;        // diagnostic marker

    if (HAL_FLASH_Unlock() != HAL_OK) {
        return false;
    }

    /* Erase page */
    FLASH_EraseInitTypeDef erase_init = {
        .TypeErase = FLASH_TYPEERASE_PAGES,
        .Banks     = SETTINGS_FLASH_BANK,
        .Page      = SETTINGS_FLASH_PAGE,
        .NbPages   = 1
    };

    uint32_t page_error = 0;
    HAL_StatusTypeDef status = HAL_FLASHEx_Erase(&erase_init, &page_error);

    if (status != HAL_OK || page_error != 0xFFFFFFFF) {
        HAL_FLASH_Lock();
        return false;
    }

    /* Write one doubleword */
    status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,
                               SETTINGS_FLASH_ADDRESS,
                               *(uint64_t*)&rec);

    HAL_FLASH_Lock();
    return (status == HAL_OK);
}

void Settings_Save(void)
{
    flash_save();
}

/* ==================== Getters / Setters ==================== */

uint8_t Settings_GetTempUnit(void)         { return settings.tempUnit;    }
void    Settings_SetTempUnit(uint8_t v)    { settings.tempUnit = v;    Settings_Save(); }

uint8_t Settings_GetShowEnv(void)          { return settings.showEnv;     }
void    Settings_SetShowEnv(uint8_t v)     { settings.showEnv = v;     Settings_Save(); }

uint8_t Settings_GetColorScheme(void)      { return settings.colorScheme; }
void    Settings_SetColorScheme(uint8_t v) { settings.colorScheme = v; Settings_Save(); }

uint8_t Settings_GetLanguage(void)         { return settings.language;    }
void    Settings_SetLanguage(uint8_t v)    { settings.language = v;    Settings_Save(); }

kiwiosek2007_0-1780051357982.png

 

1 REPLY 1
Saket_Om
ST Employee

Hello @kiwiosek2007 

On STM32L4, a 64‑bit flash doubleword can be programmed only once after an erase. HAL_FLASH_Program to a doubleword that is not in the erased (0xFF…) state fails with a programming error.

Your sequence is: erase page → program doubleword. That is correct only if the erase actually erases the same doubleword you then program. The symptom you describe — the very first save sticks, every later save is lost — is the classic signature of the erase targeting the wrong page/bank (or failing), so:

After you flash the firmware, the settings region is factory‑erased (0xFF). The first Settings_Save() programs successfully.
On every later save, the erase does not clear that doubleword (wrong Bank/Page, or erase error). HAL_FLASH_Program then fails on the already‑programmed doubleword.
You ignore the return value (flash_save()'s result is discarded in Settings_Save()), so you never see the failure. The old (first) value stays in flash.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om