HAL_FLASH_Program not writing to flash permanently
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-29 12:13 PM
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
Solved! Go to Solution.
- Labels:
-
Flash
-
STM32F7 Series
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-30 11:40 AM
Fixed it:
FLASH->CR |= 0x1; //Set PG bit
__DMB();
*(volatile uint16_t*) 0x080BFFFA = uuid;
__DMB();
while(FLASH->SR & 0x0100)
- 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.
- As berendi said, the address for half-word writes must be half-word aligned.
- 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.
- 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...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-29 12:56 PM
> 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-29 1:20 PM
Can I erase a byte in flash? What actually happen when I modify a flash byte using ST-Link?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-29 1:25 PM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-29 2:01 PM
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-29 2:27 PM
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. ;)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-29 2:43 PM
> 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-30 2:11 AM
> 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-30 10:39 AM
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
‎2020-04-30 10:44 AM
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.
