2021-04-07 03:04 AM
I am porting some code from stm32f105 to stm32f205.
(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
Solved! Go to Solution.
2021-04-07 04:28 AM
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
2021-04-07 03:36 AM
The 'F2 (and 'F4) FLASH is partitioned into non-uniform sectors. See RM.
> this is very incovenient
Yes, it is, but that's the price you pay for large FLASH on smaller piece of silicon.
JW
2021-04-07 04:28 AM
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
2021-04-07 05:45 AM
> 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