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:

  1. Write OPTKEY1 = 0x0819 2A3B in the Flash option key register (FLASH_OPTKEYR)
  2. 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;