cancel
Showing results for 
Search instead for 
Did you mean: 

stm32f2xx flash erase as painfull as it looks?

Javier1
Principal

I am porting some code from stm32f105 to stm32f205.

  1. stm32f105´s memory is erased in 64 pages of 2kbytes (i can handle this)
  2. stm32f205´s memory is erased in 12 sectors of 42kbytes!!? (flash size is 512kB)

(from stm32f2xx_hal_flash_ex.h)

/** @defgroup FLASHEx_Sectors FLASH Sectors
  * @{
  */
#define FLASH_SECTOR_0     0U  /*!< Sector Number 0   */
#define FLASH_SECTOR_1     1U  /*!< Sector Number 1   */
#define FLASH_SECTOR_2     2U  /*!< Sector Number 2   */
#define FLASH_SECTOR_3     3U  /*!< Sector Number 3   */
#define FLASH_SECTOR_4     4U  /*!< Sector Number 4   */
#define FLASH_SECTOR_5     5U  /*!< Sector Number 5   */
#define FLASH_SECTOR_6     6U  /*!< Sector Number 6   */
#define FLASH_SECTOR_7     7U  /*!< Sector Number 7   */
#define FLASH_SECTOR_8     8U  /*!< Sector Number 8   */
#define FLASH_SECTOR_9     9U  /*!< Sector Number 9   */
#define FLASH_SECTOR_10    10U /*!< Sector Number 10  */
#define FLASH_SECTOR_11    11U /*!< Sector Number 11  */

am i missing something here?

this is very incovenient because i dont have enough ram to copy in a table the part of the sector i dont want to be erased before erasing it.

stack overflow link with a similar question

we dont need to firmware by ourselves, lets talk
1 ACCEPTED SOLUTION

Accepted Solutions
DavidAlfa
Senior II

Yes, some page sizes are different. Your approach will vary depending on what are your needs.

I also don't understand why they make page sizes bigger than ram, it can cause a lot of trouble if you develop a fw and you see that issue later.

If is to for making a bootloader and updating the firmware, you don't need to care too much, write the bootloader in the first pages.

For updating just erase all the others and start writing.

It's a little trickier when you want to use the flash as eeprom to store settings, but can be done.

Choose a page with a size that can fit into your ram, you need to copy the page into it, because to store new data you must first erase it.

Make a temporal array with page size (or the data size), copy the flash data into it, modify whatever you want, erase and write back.

The easiest way is to make a typedef:

#define FLASH_ADDR	0x8000000	// Set the flash address (aligned to page)
#define FLASH_PAGES	1		// Number of pages
 
typedef struct{
	uint8_t hw_version;
	uint8_t sw_version;
	uint32_t serial;
	uint8_t option1;
	uint8_t option2;
	uint8_t option3;
	uint8_t option4;
}settings_t;

Make a struct pointer to the flash address:

settings_t *flashSettings = (settings_t*)FLASH_ADDR	// Whatever the address is

Make a struct buffer in ram:

settings_t ramSettings;

Copy the flash contents into the ram:

ramSettings = *flashSettings;	// This is basically a memcpy

Now you can just modify the option you need. 

Before writing, you must erase the flash:

uint32_t error=0;
HAL_FLASH_Unlock();		//unlock flash writing
FLASH_EraseInitTypeDef erase;	// Flash erase struct
erase.NbPages = FLASH_PAGES;
erase.PageAddress = FLASH_ADDR ;          
erase.TypeErase = FLASH_TYPEERASE_PAGES;	// Tell we are going to erase flash in pages
 
// Erase flash
if(HAL_FLASHEx_Erase(&erase, &error)!=HAL_OK){ 
	HAL_FLASH_Lock();
	Error();
}
 
// This should be the value if all pages were correctly erased
if(error != 0xFFFFFFFF){           
	HAL_FLASH_Lock();
	Error();
}
 
// Ensure that the flash contents are erased
// Divide by 2 because we use 16 bit pointer
for (uint16_t i = 0; i < (number of bytes per page)/2; i++) {	
	if( *(uint16_t*)(FLASH_ADDR+(i*2)) != 0xFFFF){	// Erased flash is always "1" 
		HAL_FLASH_Lock();
		Error();
	}
}
 

 Now, store your settings:

// Store settings. Again we divide by 2 because we use 16 bit pointers.
for (uint16_t i = 0; i < sizeof(settings_t) / 2; i++) {
	if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,\
	(((uint32_t)flashSettings+i*2)), *(((uint16_t*)&ramSettings)+i) ) != HAL_OK){
		HAL_FLASH_Lock();
		Error();
	}
}
HAL_FLASH_Lock();	// Lock the flash writing

Then, I also ensure that the written flash data matches the ram data.

Flash should not be used as "non volatile ram", you will wear the flash and damage it.

For values that change very often, use a NVRAM, which is like a SPI/I2C EEPROM but don't wear out.

Check this, it's a soldering iron firmware I developed few months ago, where I took the examples from.

https://github.com/deividAlfa/stm32_soldering_iron_controller/blob/master/Core/Src/settings.c

https://github.com/deividAlfa/stm32_soldering_iron_controller/blob/master/Core/Inc/settings.h

  

I store a flash array with the settings.

The ram settings are checked every 1 second with DMA+CRC hardware (this is very fast).

When a change is detected, it stores the checksum, current time and sets a "settings changed" flag.

Every time a change is detected it resets the time and updates the checksum.

There's a timeout (5 seconds), where if no more changes are detected, it stores the new settings into flash.

This way the flash is not overwritten for every little change, extending its lifespan.

Also, if you plan to use the flash as storage, you'll want to tell the linker to not use that space.

You do that by modifying the linker script (STM32FXXXXXXX_FLASH.ld).

For example::

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH =64K
}

Change to this:

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH =62K
  SETTINGS    (rx)    : ORIGIN = 0x800F800,   LENGTH = 2K
}

Now you can safely use the address 0x800F800 to write/read 2KB of data.

https://github.com/deividAlfa/stm32_soldering_iron_controller/blob/master/STM32F103C8TX_FLASH.ld

View solution in original post

3 REPLIES 3

The 'F2 (and 'F4) FLASH is partitioned into non-uniform sectors. See RM.

0693W000008yrvMQAQ.png> this is very incovenient

Yes, it is, but that's the price you pay for large FLASH on smaller piece of silicon.

JW

DavidAlfa
Senior II

Yes, some page sizes are different. Your approach will vary depending on what are your needs.

I also don't understand why they make page sizes bigger than ram, it can cause a lot of trouble if you develop a fw and you see that issue later.

If is to for making a bootloader and updating the firmware, you don't need to care too much, write the bootloader in the first pages.

For updating just erase all the others and start writing.

It's a little trickier when you want to use the flash as eeprom to store settings, but can be done.

Choose a page with a size that can fit into your ram, you need to copy the page into it, because to store new data you must first erase it.

Make a temporal array with page size (or the data size), copy the flash data into it, modify whatever you want, erase and write back.

The easiest way is to make a typedef:

#define FLASH_ADDR	0x8000000	// Set the flash address (aligned to page)
#define FLASH_PAGES	1		// Number of pages
 
typedef struct{
	uint8_t hw_version;
	uint8_t sw_version;
	uint32_t serial;
	uint8_t option1;
	uint8_t option2;
	uint8_t option3;
	uint8_t option4;
}settings_t;

Make a struct pointer to the flash address:

settings_t *flashSettings = (settings_t*)FLASH_ADDR	// Whatever the address is

Make a struct buffer in ram:

settings_t ramSettings;

Copy the flash contents into the ram:

ramSettings = *flashSettings;	// This is basically a memcpy

Now you can just modify the option you need. 

Before writing, you must erase the flash:

uint32_t error=0;
HAL_FLASH_Unlock();		//unlock flash writing
FLASH_EraseInitTypeDef erase;	// Flash erase struct
erase.NbPages = FLASH_PAGES;
erase.PageAddress = FLASH_ADDR ;          
erase.TypeErase = FLASH_TYPEERASE_PAGES;	// Tell we are going to erase flash in pages
 
// Erase flash
if(HAL_FLASHEx_Erase(&erase, &error)!=HAL_OK){ 
	HAL_FLASH_Lock();
	Error();
}
 
// This should be the value if all pages were correctly erased
if(error != 0xFFFFFFFF){           
	HAL_FLASH_Lock();
	Error();
}
 
// Ensure that the flash contents are erased
// Divide by 2 because we use 16 bit pointer
for (uint16_t i = 0; i < (number of bytes per page)/2; i++) {	
	if( *(uint16_t*)(FLASH_ADDR+(i*2)) != 0xFFFF){	// Erased flash is always "1" 
		HAL_FLASH_Lock();
		Error();
	}
}
 

 Now, store your settings:

// Store settings. Again we divide by 2 because we use 16 bit pointers.
for (uint16_t i = 0; i < sizeof(settings_t) / 2; i++) {
	if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD,\
	(((uint32_t)flashSettings+i*2)), *(((uint16_t*)&ramSettings)+i) ) != HAL_OK){
		HAL_FLASH_Lock();
		Error();
	}
}
HAL_FLASH_Lock();	// Lock the flash writing

Then, I also ensure that the written flash data matches the ram data.

Flash should not be used as "non volatile ram", you will wear the flash and damage it.

For values that change very often, use a NVRAM, which is like a SPI/I2C EEPROM but don't wear out.

Check this, it's a soldering iron firmware I developed few months ago, where I took the examples from.

https://github.com/deividAlfa/stm32_soldering_iron_controller/blob/master/Core/Src/settings.c

https://github.com/deividAlfa/stm32_soldering_iron_controller/blob/master/Core/Inc/settings.h

  

I store a flash array with the settings.

The ram settings are checked every 1 second with DMA+CRC hardware (this is very fast).

When a change is detected, it stores the checksum, current time and sets a "settings changed" flag.

Every time a change is detected it resets the time and updates the checksum.

There's a timeout (5 seconds), where if no more changes are detected, it stores the new settings into flash.

This way the flash is not overwritten for every little change, extending its lifespan.

Also, if you plan to use the flash as storage, you'll want to tell the linker to not use that space.

You do that by modifying the linker script (STM32FXXXXXXX_FLASH.ld).

For example::

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH =64K
}

Change to this:

MEMORY
{
  RAM    (xrw)    : ORIGIN = 0x20000000,   LENGTH = 20K
  FLASH    (rx)    : ORIGIN = 0x8000000,   LENGTH =62K
  SETTINGS    (rx)    : ORIGIN = 0x800F800,   LENGTH = 2K
}

Now you can safely use the address 0x800F800 to write/read 2KB of data.

https://github.com/deividAlfa/stm32_soldering_iron_controller/blob/master/STM32F103C8TX_FLASH.ld

> It's a little trickier when you want to use the flash as eeprom to store settings, but can be done.

> Choose a page with a size that can fit into your ram, you need to copy the page into it, because to store new data you must first erase it.

I personally prefer using two sectors for this purpose - one holds data while the other is being erased.

This, of course, is application dependent. You may also consider using the BKPSRAM with battery, external serial EEPROM/FRAM/FLASH...

JW