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

glts
  • 21,808
  • 12
  • 73
  • 94
Alex M.
  • 351
  • 2
  • 5
  • 12
  • It highly dependent to the hardware. Some types of flash memory do not allow non-block operations at all. – 0andriy Jun 08 '17 at 20:10
  • @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. –  Jun 30 '17 at 23:18
  • @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. – Support Ukraine Jul 01 '17 at 06:07
  • 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. – Lundin Sep 05 '17 at 09:57
  • 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. – datenwolf Jul 30 '20 at 10:08

2 Answers2

13

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

Gürtaç Kadem
  • 315
  • 4
  • 13
  • 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? – Alex M. Aug 05 '17 at 16:00
  • you can read first 8bit variable with calling `userConfig[0]` and following 8bit at `userConfig[1]`. – Gürtaç Kadem Aug 08 '17 at 06:22
  • 1
    Here is another example. I think it is a different MCU but the same Cortex family. I am pretty sure it should work though. https://os.mbed.com/users/olympux/code/eeprom_flash/ – Barmaley Apr 16 '18 at 19:33
  • 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. – karl71 Apr 05 '19 at 15:43
  • @karl71 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. – PeterT Mar 21 '20 at 17:40
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;
Stephan
  • 41
  • 3