2021-02-21 07:37 PM
I always get errors when trying to erase a flash page on STM32G0. I traced through the HAL code, and the error is caused by the fact that the FLASH->SR register almost always has two error bits set, PGAERR and PGSERR.
So before spending more time on erasing the flash page, I first tried to simply clear the error bits from the FLASH->SR register.
In the attached file, you can see the execution log at the end.
When the function "erasePageAt" is called, we can clearly see that:
I built my test code to do retries when unlocking and locking the flash fail, and I wait on two flash busy conditions between steps. Please note that I wrote my own waiting function because the library function FLASH_WaitForLastOperation was *always* failing due to these two sticky error bits.
How can these two error bits suddenly appear when no operation is conducted on the flash in the meantime? It is as if they were spontanneously appearing.
Finally, what can cause the hard fault in the HAL_FLASH_Lock function? We can see that when the method was called, the flash was unlocked (bit 31 unset). Very strange.
Many thanks !
JL
2021-02-22 04:09 PM
I came up with the following code for the STM32G0 to load and save a structure named "EepromConfig" to the flash memory. I totally bypassed the HAL libraries. I post the code here in case it could help others. This code allows the emulation of eeprom with flash memory. Links to some other code that I used as a starting point are provided.
The code for watchdogPlatform_reset is (it prevents resetting the watchdog too early)):
void watchdogPlatform_reset() {
uint32_t counter = hwwdg.Instance->CR & WWDG_CR_T;
uint32_t window = hwwdg.Instance->CFR & WWDG_CFR_W;
if (counter <= window)
HAL_WWDG_Refresh(&hwwdg);
}
// SEE: https://os.mbed.com/questions/69101/Is-there-a-way-to-store-variables-in-a-n/
#include "General.h"
#include "Eeprom.h"
#include "Error.h"
// ***************************************************************************************************************************
// NOTE: It is expected in the following code that the struct EepromConfig has at least 8 bytes of useless padding at the end.
// ***************************************************************************************************************************
// Size of the Eeprom configuration structure, maybe with few padding bytes stripped at the end. This size is a multiple of 8.
#define EEPROM_CONFIG_NB_BYTES_USED (sizeof(struct EepromConfig) & ~7)
#define EEPROM_NB_PAGES ((EEPROM_CONFIG_NB_BYTES_USED + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE)
#define EEPROM_NB_BYTES (EEPROM_NB_PAGES * FLASH_PAGE_SIZE)
#define ALIGNED(x) ((x % FLASH_PAGE_SIZE) == 0)
// Reserve some space in flash memory for the "eeprom".
// We use the # at the end of the text section name to prevent a linker warning.
uint8_t eepromStorage[EEPROM_NB_BYTES]
__attribute__ ((section (".text#"), used))
__attribute__ ((aligned (FLASH_PAGE_SIZE)));
static void unlock_flash() {
__disable_irq();
#if MODEL_HAS_WATCHDOG()
watchdogPlatform_reset();
#endif
while (FLASH->SR & (FLASH_SR_BSY1))
continue;
FLASH->KEYR = FLASH_KEY1;
FLASH->KEYR = FLASH_KEY2;
}
static void lock_flash() {
FLASH->CR |= FLASH_CR_LOCK;
__enable_irq();
}
static void wait_and_check_error(void) {
// Wait until done.
while (FLASH->SR & FLASH_SR_BSY1)
continue;
//Check for errors.
uint32_t cc = ERROR_CODE_NO_ERROR;
if (FLASH->SR & FLASH_SR_WRPERR)
cc = ERROR_CODE_FLASH_WRPERR;
else if (FLASH->SR & FLASH_SR_PGAERR)
cc = ERROR_CODE_FLASH_PGAERR;
else if (FLASH->SR & FLASH_SR_PGSERR)
cc = ERROR_CODE_FLASH_PGSERR;
if (cc != ERROR_CODE_NO_ERROR)
error_fatal(cc);
}
static void erasePage(void *dest) {
uint32_t pageNumber = ((uint32_t) dest - FLASH_BASE) / FLASH_PAGE_SIZE;
unlock_flash();
// Clear current errors.
FLASH->SR = FLASH_SR_WRPERR | FLASH_SR_PGAERR | FLASH_SR_PGSERR;
// Run command.
FLASH->CR = FLASH_CR_PER | (pageNumber << FLASH_CR_PNB_Pos);
FLASH->CR |= FLASH_CR_STRT;
wait_and_check_error();
// Clear command.
FLASH->CR = 0;
lock_flash();
}
static void copyToFlash(void *dest, void *src, size_t sizeInBytes) {
unlock_flash();
// Set programming mode.
SET_BIT(FLASH->CR, FLASH_CR_PG);
uint32_t *pDest = (uint32_t*) dest;
uint32_t *pSrc = (uint32_t*) src;
// Two uint32_t will be written to flash for each loop iteration. i.e. 8 bytes written per iteration.
for (uint32_t i = 0, n = sizeInBytes / 8; i < n; i++) {
/* Barrier to ensure programming is performed in 2 steps, in right order (independently of compiler optimization behavior) */
__ISB();
/* Program first word. */
*pDest++ = *pSrc++;
/* Barrier to ensure programming is performed in 2 steps, in right order (independently of compiler optimization behavior) */
__ISB();
/* Program second word. */
*pDest++ = *pSrc++;
wait_and_check_error();
#if MODEL_HAS_WATCHDOG()
watchdogPlatform_reset();
#endif
}
// Clear programming mode.
FLASH->CR = 0;
lock_flash();
}
static void programPage(void *dest, void *src, size_t sizeInBytes) {
erasePage(dest);
copyToFlash(dest, src, sizeInBytes);
}
static void checkAlignment() {
if (!ALIGNED((uint32_t) eepromStorage) || !ALIGNED(sizeof eepromStorage))
error_fatal(ERROR_CODE_FLASH_NOT_ALIGNED);
}
// eeprom_cfg must be aligned on a 4 byte boundary.
void eeprom_platform_save(EepromConfig &eeprom_cfg) {
checkAlignment();
char *pSrc = (char *) &eeprom_cfg;
char *pDest = (char *) eepromStorage;
uint32_t toGo = EEPROM_CONFIG_NB_BYTES_USED;
for (uint32_t i = 0; i < EEPROM_NB_PAGES; i++, pSrc += FLASH_PAGE_SIZE, pDest += FLASH_PAGE_SIZE) {
uint16_t thisTime = (toGo > FLASH_PAGE_SIZE) ? FLASH_PAGE_SIZE : toGo;
toGo -= thisTime;
uint8_t same = memcmp(pSrc, pDest, thisTime) == 0;
if (!same)
programPage(pDest, pSrc, thisTime);
}
}
// eeprom_cfg must be aligned on a 4 byte boundary.
void eeprom_platform_load(EepromConfig &eeprom_cfg) {
checkAlignment();
uint32_t *pSrc = (uint32_t *) eepromStorage;
uint32_t *pDest = (uint32_t *) &eeprom_cfg;
// Load the structure by chunks of 32 bits.
for (uint32_t i = 0, n = EEPROM_CONFIG_NB_BYTES_USED / sizeof (uint32_t); i < n; i++)
*pDest++ = *pSrc++;
}
2023-07-31 03:47 PM
Hi Jim, i'm having the same problem on my STM32G03 personal dedicated board,did you manage to fix it? i simply can't use the ST dedicated MIDDLEWARE for eeprom emulation because of this error.