2023-10-30 10:12 AM - edited 2023-10-30 10:12 AM
Hi all,
We deployed a lot of devices that have a STM32G431KBU6 controller.
It basically has a foot switch to turn on/off a 12v DC motor and a rotary switch to control the speed.
We use EEPROM emulator to save the speed setting.
If speed setting is different from the stored value and there is no new speed change detected within a minute we store the new value. (to safe unnecessary writes)
Clients mostly only set the speed setting once when they first use the product.
So EEPROM emulated write is almost never done only EEPROM emulated read on start up of the device
Somehow support receives a lot of complains about non responding devices. Only reprogram the device helps. But this is a temporarily fix.
Sometimes clients tell us they had a power outage before these issues appear.
We can not reproduce the issue, maybe because our mains power is very clean?
Can power glitches (12v power jack) cause flash program corruption?
2023-10-30 10:49 AM
The eeprom emulator writes into pages of FLASH memory. And your program is also stored in FLASH memory.
What have you done to ensure that the pages of FLASH used for EEPROM-emulation are not pages where the compiler/linker places your program?
You probably need to alter the memory-map from the default one for your processor to set aside at least two pages of FLASH for EEPROM emulation, and alter the source-code of the EEPROM emulation to use those pages.
2023-10-30 11:29 AM
Reads from flash are unlikely to cause issues even if power is unstable. If power drops below the BOR threshold, chip will reset and all is well.
Have you recovered a "nonfunctioning" device and examined the flash on it?
Writes could certainly cause issues, but it doesn't sound like that is occurring.
2023-10-31 06:02 AM
I instructed the assembly team to program our code to address 0x08000000
At startup I read in our values:
//Small delay for potential discharge before unlocking flash
HAL_Delay(600);
/* Unlock the Flash Program Erase controller */
HAL_FLASH_Unlock();
ee_status = EE_Init(EE_CONDITIONAL_ERASE);
if(ee_status != EE_OK) {Error_Handler();}
ee_status = EE_ReadVariable32bits(1, &EEPROM_MotorSpeedManual);
ee_status = EE_ReadVariable32bits(2, &EEPROM_MotorSpeed);
ee_status = EE_ReadVariable32bits(3, &EEPROM_MotorDirection);
Later on, when a setting change is detected, I write the new inputs after one minute
if(g_SettingsChanged == true && HAL_GetTick()-lastSettingsChangedTime > 60000)
{
HAL_FLASH_Unlock();
EE_WriteVariable32bits(1, S_MotorSpeedManual);
EE_WriteVariable32bits(2, S_MotorSpeed);
EE_WriteVariable32bits(3, S_MotorDirection);
HAL_FLASH_Lock();
g_SettingsChanged = false;
lastSettingsChangedTime = HAL_GetTick();
}
Where can I verify where EEPROM values are written to?
2023-10-31 06:10 AM
As you can see in my code I unlock flash already at startup, I read the EEPROM values if there are. Otherwise I write the default values and lock flash.
Maybe I can improve this by already store the default in EEPROM when programming the device? Not sure how.
To avoid recalling a lot of devices my client wants a self repairing mechanism.
Some form of factory reset/repair options.
For example have a backup of working firmware that the chip can reprogram it self with.
Is that possible? The program can fit the microcontroller multiple times. Hopefully ST has a bootloader/mechanism for this.
2023-10-31 06:24 AM
How does dropping into Error_Handler() fix anything? Won't that just die silently in a while(1) loop by default?
Perhaps you need a better strategy? Like addressing the issue, erasing the section of FLASH being used, and write usable defaults? Or whatever is needed for it to initialize the memory so EE_Init() succeeds.
If the device had a battery presumably NVRAM/BKP would be a better place to store things temporarily?
Perhaps you could learn to use FLASH directly, and journal your write, and check them, etc?
2023-10-31 06:31 AM
I seem to recall previous posts on this forum that mention that the ST EEPROM emulation code ALWAYS writes to the EEPROM flash area on startup. It writes to the first "unused" page (or 64-bit row). This was to handle the case where a previous write operation may have been interrupted by a power failure or reset. If I remember correctly, if the flash was partially programmed yet reads back as 0xffff, a 2nd attempt to program it may fail. This "always write the next block on startup" was a way to ensure that writes from user code would always write to "good" flash. You can check the code to see if that really is the case.
You do not need (and SHOULD NOT) unlock the flash on startup. Only unlock it right before you write to flash - and the EEPROM emulation code should handle that internally. You shouldn't need to.
There are #defines for which FLASH pages are used. See AN4894, section 5.1.3, "User Defines" (at least in the version I have). But as @TDK mentioned, as long as the FLASH used by the EEPROM emulation does not overlap the FLASH used for code, none of that should corrupt your code.
I don't recall is the G431 has dual flash banks. If it does, you should enable dual bank mode and make sure the EEPROM emulation is in the 2nd bank and your code in the first bank (which it is if you load code at 0x08000000).
2023-10-31 06:54 AM
You are right Error_Handler() toggles a led but doesn't solve anything.
The code snippet was cut-off a bit early. I needed to unlock Flash to write my defaults, but I unlock way to early here right?
//Small delay for potential discharge before unlocking flash
HAL_Delay(600);
/* Unlock the Flash Program Erase controller */
HAL_FLASH_Unlock();
ee_status = EE_Init(EE_CONDITIONAL_ERASE);
if(ee_status != EE_OK) {Error_Handler();}
ee_status = EE_ReadVariable32bits(1, &EEPROM_MotorSpeedManual);
ee_status = EE_ReadVariable32bits(2, &EEPROM_MotorSpeed);
ee_status = EE_ReadVariable32bits(3, &EEPROM_MotorDirection);
if(EEPROM_MotorSpeedManual == 0)
{
ee_status = EE_WriteVariable32bits(1, S_MotorSpeedManualDef);
}
if(EEPROM_MotorSpeed == 0)
{
ee_status = EE_WriteVariable32bits(2, S_MotorSpeedDef);
}
if(EEPROM_MotorDirection == 0)
{
ee_status = EE_WriteVariable32bits(3, S_MotorDirection);
}
ee_status = EE_ReadVariable32bits(1, &EEPROM_MotorSpeedManual);
S_MotorSpeedManual = EEPROM_MotorSpeedManual;
ee_status = EE_ReadVariable32bits(2, &EEPROM_MotorSpeed);
S_MotorSpeed = EEPROM_MotorSpeed;
ee_status = EE_ReadVariable32bits(3, &EEPROM_MotorDirection);
S_MotorDirection = EEPROM_MotorDirection;
/* Lock the Flash Program Erase controller */
HAL_FLASH_Lock();
I guess I can eliminate these writes at startup when I already have defaults when I program the device.
The EEPROM emulator is not power resilient right?
Should I go with something more robust like LittleFS or SPIFFS?
Or should I invest more time to make the emulator code robust and safe?
As soon as I unlock flash the risk of damaging program code seems too high for me
2023-10-31 06:55 AM
Products that die silently in Error_Handler() will look like bricks to a consumer, and be very hard to recover via any kind of user interface.
For things I need to allow for user configuration in a semi-permanent fashion, I have workable defaults, I recover settings from FLASH, and manage the write, erase, journalling of the configuration structure directly. The structure has integrity checking so you know if it wrote completely/correctly.
The EEPROM emulation is a black-box of halfassery ..
2023-10-31 06:57 AM
The G431 doesn't have dual flash mechanism.
So it it wise to try to program this mechanism in a single bank config?
I guess I loose all protection mechanisms, corruption can occur in the entire bank