How to write/read to FLASH on STM32F4, Cortex M4
Asked Answered
O

2

9

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

O answered 8/6, 2017 at 18:59 Comment(5)
It highly dependent to the hardware. Some types of flash memory do not allow non-block operations at all.Restivo
@4386427 That is incorrect. OPTKEY1 and OPTKEY2 are values, not addresses. Adding them to the address of FLASH_OPTKEYR will result in a crash or unexpected behavior.Karlise
@duskwuff - I see. I read it as if OPTKEY1 and OPTKEY2 was two registers within a group of registers called FLASH_OPTKEYR. Comment deleted. Thanks.Glove
Reading the manual in-depth is of course an option, but there is usually also an app note for how this is done. Check for "eeprom emulation" or "bootloader" app notes.Esse
I'd just like to point out, that flash memory has only a limited number of erase-write cycles before it degrades. I strongly recommend to either use battery backed up NVRAM or some high endurance external nonvolatile memory – for example MRAM – to store nonvolatile data that's changed often. Personally I always go with MRAM for those things.Chavira
L
12

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

Lothians answered 30/6, 2017 at 23:2 Comment(5)
thank you, and how would I read the values in the flash? Because first I need to read them, erase the flash and lastly write the old ones plus the new ones. Right?O
you can read first 8bit variable with calling userConfig[0] and following 8bit at userConfig[1].Acronym
Here is another example. I think it is a different MCU but the same Cortex family. I am pretty sure it should work though. os.mbed.com/users/olympux/code/eeprom_flashSidestroke
I've noticed that, although reading from on-board flash is extremely fast, writing to it (even after the sector has been erased) is very slow. Is this the expected behavior (i.e. is it a hardware limitation)? I'm measuring writing speeds around 7x slower than writing to a flash device (a micro SD card) over SPI at 1MHz.Hirz
@Hirz SDCards can have very different speed ratings than on-chip MCU flash since the former is usually speed critical (this is largely due to process optimizations, execution unit timing vs. flash memory timing characteristics). For example, in the datasheet for the STM32L412xx (section 6.3.10) you will see a timing table for "Flash Memory Characteristics". 64b programming time is 90ms and 32-dword time is ~2-3ms. But if you look at superfast SanDisk MD8832 used in SDCards (datasheet Table 11, section 10.3.2), a page write is 30ns. That's 100-1000x faster.Cleavable
M
3

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;
Merbromin answered 30/7, 2020 at 9:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.