Skip to main content
jo512
Associate II
October 15, 2025
Solved

Unable to erase flash in NUCLEO-G0B1RE board

  • October 15, 2025
  • 5 replies
  • 773 views

Hi

I am using the function below to erase the flash, but am not able to do the same.

I have to erase from address 0x0803E000UL i.e. page 124

The function does basically 

1. HAL_FLASH_Unlock

2. HAL_FLASHEx_Erase(&erase_init, &page_error) - where page is 124 

3. reads the erased flash area 

4. HAL_FLASH_Lock

Am I missing something? I would not prefer to run the function in ram

I have MCUboot running and my application running on slot 0 is based on FreeRTOS.  I am trying to erase slot1.

 

#define SLOT1_BASE_ADDR 0x0803E000UL

void erase_slot1_flash(void)
{
 HAL_StatusTypeDef status;
 uint32_t page_error = 0;
 FLASH_EraseInitTypeDef erase_init;
 uint32_t page_index;

 /* Determine actual flash size (in KB) from system memory register */
 uint32_t flash_size_kb = *(uint16_t *)FLASHSIZE_BASE;
 uint32_t flash_start = FLASH_BASE;
 uint32_t flash_end_addr = FLASH_BASE + (flash_size_kb * 1024UL) - 1UL;

 printf("SLOT1_BASE_ADDR = 0x%08lX\r\n", (unsigned long)SLOT1_BASE_ADDR);
 printf("FLASH_BASE = 0x%08lX\r\n", (unsigned long)FLASH_BASE);
 printf("FLASH_SIZE_KB = %lu\r\n", (unsigned long)flash_size_kb);
 printf("FLASH_START_ADDR = 0x%08lX\r\n", (unsigned long)flash_start);
 printf("FLASH_END_ADDR = 0x%08lX\r\n", (unsigned long)flash_end_addr);

 /* Sanity check: make sure SLOT1 lies within flash */
 if ((SLOT1_BASE_ADDR < flash_start) || (SLOT1_BASE_ADDR > flash_end_addr)) {
 printf("Error: SLOT1_BASE_ADDR is outside internal flash range!\r\n");
 return;
 }

 /* Compute which flash page the slot address belongs to */
 page_index = (SLOT1_BASE_ADDR - FLASH_BASE) / FLASH_PAGE_SIZE;
 HAL_FLASH_Unlock();
 printf("Before erase: ");
 for (uint8_t i = 0; i < 16; i++) {
 uint8_t val = *(uint8_t *)(SLOT1_BASE_ADDR + i);
 printf(" %02x", val);
 }
 printf("\n\r");

 /* Prepare erase configuration */
 erase_init.TypeErase = FLASH_TYPEERASE_PAGES;
 erase_init.Page = page_index;
 erase_init.NbPages = 1;

 printf("Erasing page (index=%lu, address=0x%08lX)\r\n",
 (unsigned long)page_index, (unsigned long)SLOT1_BASE_ADDR);

 /* Optional: clear prior flash flags */
 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR |
 FLASH_FLAG_RDERR |
 FLASH_FLAG_FASTERR |
 FLASH_FLAG_MISERR |
 FLASH_FLAG_PGSERR |
 FLASH_FLAG_WRPERR |
 FLASH_FLAG_PROGERR |
 FLASH_FLAG_OPERR);

 status = HAL_FLASHEx_Erase(&erase_init, &page_error);
 if (status != HAL_OK) {
 printf("Erase failed! HAL status=%d Flash error=%lu\r\n",
 status, HAL_FLASH_GetError());
 } else {
 printf("Erase successful.\r\n");
 }
 printf("-After erase: ");
 for (uint8_t i = 0; i < 16; i++) {
 uint8_t val = *(uint8_t *)(SLOT1_BASE_ADDR + i);
 printf(" %02x", val);
 }
 printf("\n\r");
 HAL_FLASH_Lock();
}

 

Best answer by gbm

This works and is more immune to errors and less ambiguous than a series of assignments:

FLASH_EraseInitTypeDef erase_init = {
 .TypeErase = FLASH_TYPEERASE_PAGES,
 .Banks = FLASH_BANK_1,
 .Page = page_index,
 .NbPages = 1
};

 

5 replies

TDK
Super User
October 15, 2025

So what happens? What do your log functions output when it fails?

You should set the erase_init.Bank parameter to bank 1.

"If you feel a post has answered your question, please click ""Accept as Solution""."
jo512
jo512Author
Associate II
October 15, 2025

Missed it 

I have some more observations 

when #define SLOT1_BASE_ADDR 0x0803E000UL is

FLASH_START_ADDR = 0x08000000
FLASH_SIZE_KB = 512
FLASH_END_ADDR = 0x0807FFFF
SLOT1_BASE_ADDR = 0x0803E000
Before erase: 48 65 6c 6c 6f 20 66 72 6f 6d 20 46 72 65 65 52
Erasing page (index=124, address=0x0803E000)
Erase successful.
-After erase: 48 65 6c 6c 6f 20 66 72 6f 6d 20 46 72 65 65 52
Before write: 48 65 6c 6c 6f 20 66 72 6f 6d 20 46 72 65 65 52
Write failed @0x0803e000, err=8

 As shown above, Line 8 and 9 should be FFs but not

When #define SLOT1_BASE_ADDR 0x08040000UL is

FLASH_START_ADDR = 0x08000000
FLASH_SIZE_KB = 512
FLASH_END_ADDR = 0x0807FFFF
SLOT1_BASE_ADDR = 0x08040000
Before erase: 70 72 61 6a 6f 73 68 20 64 69 64 20 74 68 69 73
Erasing page (index=128, address=0x08040000)
Erase successful.
-After erase: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
Before write: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
String written at 0x08040000
-After write: 70 72 61 6a 6f 73 68 20 64 69 64 20 74 68 69 73

The behavior is as expected.

 

jo512
jo512Author
Associate II
October 15, 2025

Maybe my linker file also helps

/* Memories definition */
MEMORY
{
 RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 144K
 FLASH (rx) : ORIGIN = 0x800C200, LENGTH = (512K - 0xC200)
}
TDK
Super User
October 15, 2025

If HAL reports success, it probably erased something.

Did you fix the uninitialized Banks parameter in the code? Note that your pages are in different banks.

TDK_0-1760537768777.png

 

"If you feel a post has answered your question, please click ""Accept as Solution""."
jo512
jo512Author
Associate II
October 15, 2025

Hi TDK

Thanks for pointing out, I did not do this, What is this?

Sorry, I am pretty new to ST subsystem as I am migrating from Atmel and NXP to ST 

jo512
jo512Author
Associate II
October 15, 2025

But then also why are the other banks working? Can you point me to a quick document please

TDK
Super User
October 15, 2025

The reference manual explains how the flash banks work and how they're organized.

The HAL source code is the best reference for what needs to be passed to HAL functions. In this case, look at the definition for FLASH_EraseInitTypeDef.

"If you feel a post has answered your question, please click ""Accept as Solution""."
jo512
jo512Author
Associate II
October 16, 2025

Hi TDK 

Honestly, I am lost in a pile of datasheets, which gives me a feeling I am chasing my own tail.

But thanks, for pointing me to the code, this helps.

As time, a factor which I cannot control, I am now planning to use a quick fix, I find that I can erase and write multiple times from flash location 0x08040000UL and store my new firmware at this location. 

I configure MCUboot to use this location as slot1. 

Do you see any problem for that?

Thanks for the support

gbm
Principal
October 15, 2025

Try this in place of the three assignments (lines 38+):

FLASH_EraseInitTypeDef erase_init = {
 .TypeErase = FLASH_TYPEERASE_PAGES,
 .Page = page_index,
 .NbPages = 1
};

 

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
jo512
jo512Author
Associate II
October 16, 2025

Hi gbm 

How does this help? 

FLASH_EraseInitTypeDef erase_init = {
 .TypeErase = FLASH_TYPEERASE_PAGES,
 .Page = page_index,
 .NbPages = 1
};

Is there some compiler or linker issue. I just checked my assembler code, both generated the same code

Can you please explain me? Am I missing something in STM ecosystem? 

P.S.: I have been advised multiple times by others not to use ST products, as the whole ecosystem and datasheet is a mess. I fear all these are leading me to the same path.

gbm
Principal
October 16, 2025

When you initialize a structure in its declaration, the fields which are not initialized explicitly are initialized to zeros. It's a common mistake in STM32 ecosystem to declare the structure without an initializer inside of a function, then to assign some fields - the remaining fields then have some random values, causing the call to fail or behave strangely. Unfortunately, many ST offcial examples suggest this to the programmers by setting the fields with a series of assignments instead of initializing them in the declaration.

If you consider ST documents and libraries to be of low quality, then you probably haven't seen their competitors' stuff.

ST reference manual are much better than others. Also, a big advantage of STM32 is that the errata is much smaller than the reference manual. ;)

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice
TDK
Super User
October 16, 2025

Did you try:

erase_init.Banks = FLASH_BANK_1;

or

erase_init.Banks = FLASH_BANK_2;

depending on where the page to be erased is.

Flash is 128 pages per bank. See "3.3.1 FLASH organization" in the reference manual.

STM32G0x1 advanced Arm<Sup>®</Sup>-based 32-bit MCUs - Reference manual

 

> P.S.: I have been advised multiple times by others not to use ST products, as the whole ecosystem and datasheet is a mess. I fear all these are leading me to the same path.

What alternative products have awesome documentation and ecosystems? Genuinely asking. I have used many different manufacturer's microcontrollers. They are all a mess in their own way. Maybe you could say Arduino is good here, but that's only because the software is very limiting.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Andrew Neil
Super User
October 16, 2025

@TDK wrote:

What alternative products have awesome documentation and ecosystems? 


Certainly not Atmel !

A complex system that works is invariably found to have evolved from a simple system that worked.A complex system designed from scratch never works and cannot be patched up to make it work.
jo512
jo512Author
Associate II
October 16, 2025

Hi All

I will not make this question a discussion of which company has the best product. This is my first project using ST after a couple of years. I did my research, should I chose NXP or ST, I decided to use STM32 just for the price perspective. I was advised against it by many. 

Multiple manufactures provide Datasheets and ecosystems and I have been using them since 1996, for example

  1. Coldfire from freescale (but imx from NXP is a disaster) 
  2. Xmegas, Mega and SAMs from Atmel (but Microchip destroyed it)
  3. NXP K series
  4. Renesas Rx series

Currently, I am using ST just because it's the microcontroller with good price to feature ratio. 

In the future, I would like to add ST also among my favorites.