cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_FLASH_Program not writing to flash permanently

vtran1
Associate II

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

1 ACCEPTED SOLUTION

Accepted Solutions

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

View solution in original post

18 REPLIES 18
TDK
Guru

> 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
Associate II

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

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
Associate II

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
Chief II

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

TDK
Guru

> 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

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

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.

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.