Skip to main content
Explorer
September 17, 2025
Question

Internal flash storage issue on STM32G0B1

  • September 17, 2025
  • 1 reply
  • 279 views

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.

Shaunus_0-1758113387876.png

Shaunus_1-1758114807711.png

If anyone has any ideas on why my flags are acting up I would greatly appreciate it.

Regards,

Shaun

 

    This topic has been closed for replies.

    1 reply

    Super User
    September 17, 2025

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