2025-09-17 6:20 AM
Good day,
I am writing firmware for a custom board using the STM32G0B1KET6 and am experiencing issues related to writing a serial number to the internal flash.
As far as I can tell, this MCU has 512 KB of flash split into 2 banks of 128 pages (each page is 2 KB). I am attempting to write to the last page of the first bank (Page 127 @ 0x803F800).
I have modified the linker file to reduce the flash area used by my application code like so:
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 144K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
Here is my flash writing function.
uint8_t Flash_Write(uint32_t startAddress, uint64_t data)
{
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_BSY1);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_BSY2);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGSERR);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_PGAERR);
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_CFGBSY);
if(__HAL_FLASH_GET_FLAG(FLASH_FLAG_CFGBSY) == 1)
{
return 0;
}
HAL_StatusTypeDef status;
uint32_t err;
status = HAL_FLASH_Unlock();
if (status != HAL_OK)
{
// Handle error
printf("Failed to unlock flash.\r\n");
return 0;
}
// Erase page first
FLASH_EraseInitTypeDef EraseInitStruct;
uint32_t PageError = 0;
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.Page = (startAddress - FLASH_BASE) / FLASH_PAGE_SIZE;
EraseInitStruct.NbPages = 1;
EraseInitStruct.Banks = FLASH_BANK_1;
status = HAL_FLASHEx_Erase(&EraseInitStruct, &PageError);
if (status != HAL_OK)
{
err = HAL_FLASH_GetError();
printf("Failed to erase flash. Err: %lu\r\n",err);
HAL_FLASH_Lock();
return 0;
}
// Write data
if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, startAddress, data) != HAL_OK)
{
// Handle error
err = HAL_FLASH_GetError();
printf("Flash programming error. Err: %lu\r\n",err);
HAL_FLASH_Lock();
return 0;
}
HAL_FLASH_Lock();
return 1;
}
void cmSetUID(void)
{
uint64_t UID;
uint8_t retry = 0;
UID = atoi((char*)&DebugRxBuf[DebugRxPtr]);
while(Flash_Write(0x0803F800,UID) == 0)
{
if(retry > 10)
{
printf("UID Set: FAILED\r\n");
return;
}
else
{
//HAL_Delay(10);
retry++;
}
}
printf("UID Set: %lu\r\n",(uint32_t)UID);
}
void cmReadUID(void)
{
uint64_t UID;
UID = Flash_Read(0x0803F800);
printf("UID Read: %lu\r\n",(uint32_t)UID);
}
For some reason the PGSERR and PGAERR flags are always set when the board is programmed or this function is entered, which is why I am manually clearing them to prevent failure at the HAL_FLASHEx_Erase function.
The issue that I am having relates to the CFGBSY flag, which is sometimes set on boot or after a successful write (but not always), and I cannot clear the flag as it is set/cleared by hardware. For some reason the CFGBSY flag will eventually go low after successive calls to the Flash_Write function even though the function returns if the flag is set.
If anyone has any ideas on why my flags are acting up I would greatly appreciate it.
Regards,
Shaun
2025-09-17 6:33 AM - edited 2025-09-17 6:33 AM
> For some reason the PGSERR and PGAERR flags are always set
Issue #1. This can be caused if something writes only half of a flash page.
> CFGBSY flag, which is sometimes set on boot or after a successful write
If CFGBSY is high, there's a pending erase or write operation. Is PG high? Probably a pending write operation. Solution is to wait for CFGBSY to drop.
Could be an issue with how your board is getting programmed prior to debugging. Maybe debugger is only writing half of a page. Ensure the HEX/ELF/BIN file (whichever is used to flash) is a multiple of 8 bytes.