How to write/read to FLASH on STM32F4, Cortex M4
I want to write a variable, for example an integer with the number 5 to the FLASH and then after the power goes away and the device is turned on again read it.
I already know that in order to write something I first need to erase the page and then write.
In the manual it says:
- Write OPTKEY1 = 0x0819 2A3B in the Flash option key register (FLASH_OPTKEYR)
- Write OPTKEY2 = 0x4C5D 6E7F in the Flash option key register (FLASH_OPTKEYR)
How do I perform this tasks?
Sector 0 has a Block adress from 0x0800 0000 to 0x0800 3FFF, this is where I want to write.
Here the link to the manual, page 71: STM32 Manual
You can use following code for write data to flash with HAL library.
void Write_Flash(uint8_t data)
{
HAL_FLASH_Unlock();
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR );
FLASH_Erase_Sector(FLASH_SECTOR_6, VOLTAGE_RANGE_3);
HAL_FLASH_Program(TYPEPROGRAM_WORD, FlashAddress, data);
HAL_FLASH_Lock();
}
You should update linker script as follows. Add DATA
in MEMORY
and add .user_data
in SECTIONS
.
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 320K
CCMRAM (rw) : ORIGIN = 0x10000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 2048K
DATA (rwx) : ORIGIN = 0x08040000, LENGTH = 128k
}
/* Define output sections */
SECTIONS
{
.user_data :
{
. = ALIGN(4);
KEEP(*(.user_data))
. = ALIGN(4);
} > DATA
You should add following attribute on main code for reading data after power on
__attribute__((__section__(".user_data"))) const char userConfig[64];
After all these, you can read your flash data with calling userConfig[0]
.
I'm using STM32F407 and Atollic TrueSTUDIO® for STM32 Version 9.3.0.
When using above suggested code
attribute((section(".user_data"))) const char userConfig[64];
my compiler assumed userConfig
to be constant zero. I had to remove the const
from the declaration to make it work.
My complete solution consists of two parts (as already said above but with some further modifications):
Step 1 edit linker file:
In 'MEMORY'
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 896K /* origin size was 1024k, subtracted size of DATA */
DATA (rx) : ORIGIN = 0x080E0000, LENGTH = 128K
In 'SECTIONS'
/* User data section at the end of the flash to store calibration data etc. */
.user_data (NOLOAD):
{
. = ALIGN(4);
_user_data_start = .; /* create a global symbol at user_data start */
KEEP(*(.user_data))
. = ALIGN(4);
_user_data_end = .; /* create a global symbol at user_data end */
} >DATA
Step 2 write code:
uint8_t userConfig[64] __attribute__ ((section(".user_data")));
extern uint32_t _user_data_start;
extern uint32_t _user_data_end;
uint8_t ConfArray[16];
uint32_t TestArray[2];
// Copy a part from the userConfig to variable in RAM
for (i = 0; i < 16; i++)
{
ConfArray[i] = userConfig[i];
}
// get the address of start and end of user_data in flash
// the & is importand, else you would get the value at the address _user_data_start and _user_data_end points to
TestArray[0] = (uint32_t)&_user_data_start;
TestArray[1] = (uint32_t)&_user_data_end;