Skip to main content
vtran1
Associate III
April 29, 2020
Solved

HAL_FLASH_Program not writing to flash permanently

  • April 29, 2020
  • 5 replies
  • 5143 views

Hi all,

I am using HAL_FLASH_Program() to program an uuid into a specific address. I can verify it write successfully by reading from the address. However, if I power cycle the MCU, the memory at that address returns to the original value. If I write it directly through ST-Link then it stays permanently. Does anyone know why is that? Do I need to erase the memory location before write to it using HAL_FLASH_Program()? I am using STM32F745.

Thank you

This topic has been closed for replies.
Best answer by Piranha

Fixed it:

FLASH->CR |= 0x1; //Set PG bit
__DMB();
*(volatile uint16_t*) 0x080BFFFA = uuid;
__DMB();
while(FLASH->SR & 0x0100)
  1. Don't limit comparison to >0, when you can do !=0 (the same as leaving it out completely) - it's safer relative to potential code changes in future.
  2. As berendi said, the address for half-word writes must be half-word aligned.
  3. Target type of casting must be volatile to prevent compiler from reordering the write operation relative to other volatile accesses - in this case register accesses.
  4. As flash memory region is not configured as device or strongly ordered memory, the store instruction must be encapsulated with DMB instructions to force CPU to complete previous stores and prevent from reordering instructions and doing speculative reads. This is recommended for all ARM CPU cores, but Cortex-M7 is the first from Cortex-M series, for which it is mandatory!

P.S. And of course the HAL code is broken in this regard...

5 replies

TDK
April 29, 2020

> Do I need to erase the memory location before write to it using HAL_FLASH_Program()?

Yes, you must erase flash before writing to it. You can't treat is as RAM.

"If you feel a post has answered your question, please click ""Accept as Solution""."
vtran1
vtran1Author
Associate III
April 29, 2020

Can I erase a byte in flash? What actually happen when I modify a flash byte using ST-Link?

TDK
April 29, 2020
Nope, you can only erase an entire page.
ST-Link probably reads the entire page, modifies it locally, then erases and writes it to flash.
You can write individual bytes that are already erased without having to erase the entire page.
"If you feel a post has answered your question, please click ""Accept as Solution""."
vtran1
vtran1Author
Associate III
April 29, 2020

I have tried to use the erase sector option in ST-Link but no success.

My procedure is below:

  • Program the firmware using ST-Link
  • Erase the last sector (which contains the address that I want to write) using ST-Link
  • Power cycle the MCU to run the firmware
  • The firmware then will run the HAL_FLASH_Program() function to write to the specific address
  • Verify ok by reading the address
  • Power cycle the MCU again, now the address come back to FFFF

What do you think I did wrong?

Piranha
Principal III
April 29, 2020

Reading can be "faked" by D-cache, if it's turned on. Try not turning it on and most likely you'll see that you are actually not writing anything. As for why... Here is a wild guess - you haven't read the reference manual and are trying to write double word values. ;)

vtran1
vtran1Author
Associate III
April 30, 2020

I have set the PSIZE bits in FLASH->CR register to 01 (x16) and write uint16_t data into the address but it gives me PGPERR. I'm really confused.

berendi
Principal
April 30, 2020

How exactly do you write it?

TDK
April 29, 2020

> What do you think I did wrong?

I don't think it's a useful exercise for me to guess what mistakes you're making. There's plenty of examples on how to write flash.

"If you feel a post has answered your question, please click ""Accept as Solution""."
berendi
Principal
April 30, 2020

> What do you think I did wrong?

You trusted a barely documented library function that it does what you think it should do.

Follow the instructions in these sections of the reference manual, set the registers exactly as advised.

  • Unlocking the Flash control register
  • Program/erase parallelism
  • Flash erase sequences / Sector erase
  • Flash programming sequences / Standard programming

Examine FLASH->SR after each step for possible problems.

vtran1
vtran1Author
Associate III
April 30, 2020

Thank you. I have ditched the HAL library and writing directly to registers as follow:

void FA_program_uuid( uint16_t uuid)
{
 HAL_FLASH_Unlock();
 __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
 FLASH->CR &= CR_PSIZE_MASK; //Clear all the PSIZE bits
 FLASH->CR |= FLASH_PSIZE_HALF_WORD; //Set PSIZE bits to 01: x16
 while((FLASH->SR & 0x0100) > 0)
 {
 //Wait for BSY bit is cleared
 }
 FLASH->CR |= 0x2; //Set SER bit
 FLASH->CR |= 0x30; //Select the sector by setting SNB bits
 FLASH->CR |= 0x100; //Set the STRT bit
 while((FLASH->SR & 0x0100) > 0)
 {
 //Wait for BSY bit is cleared
 }
 FLASH->CR |= 0x1; //Set PG bit
 *(uint16_t*) 0x080BFFFB = uuid;
 while((FLASH->SR & 0x0100) > 0)
 {
 //Wait for BSY bit is cleared
 }
 FLASH->CR &= 0xffffffe; //Clear PG bit
 HAL_FLASH_Lock();
}

And I got PGPERR flag in FLASH->SR even though I have set PSIZE to 01 for x16 programming.

berendi
Principal
April 30, 2020

The address must be aligned, 0x080BFFFB is not aligned for halfword writes, use an even number (and for full words, one divisible by 4).