2024-09-28 06:01 PM - edited 2024-09-28 06:02 PM
I am working with an STM32D103C8T6 and I want to store some data on the flash memory.
I have some idea on how to do It but not sure about some details.
My procedure is the following:
1- Add a new section in linker at a defined address near the end.
I understand this is done so main program never overrides my data. If not please correct me
ex:
.permament 0x800EA60 :
{
KEEP(*(.permament))
}>FLASH
2- Unlock flash and option bytes with
FLASH_CR and FLASH_KEYR registers.
3- Clear page inside the area I destined for my permanent data
4- Write my data in 16 bits packages
eg:
*(__IO uint16_t*)(addr) = data;
I have the following questions:
Regarding step 1:
Is this necessary? Does this guarantee I won't overwrite the main program or is it any other way to do it?
Regarding step 2:
Do I need to unlock option bytes or is this ?
Regarding step 3:
Where does a page start? Do I need to specify the addres in FLAS_AR register to the begining of a page?
Regarding step 4:
I know I cannot write 1s but can I write ceros anytime?
For example, can I do the following?:
Let's say I have 4 bytes with all 1s, I then write in the first byte a 3.
Some time later I write in the second byte a 5.
Later I change second first byte to 1.
Can I do this or do I need to clear the page after each write?
Solved! Go to Solution.
2024-10-21 08:08 PM
I will create a response which answers all the questions based on what I ended up doing:
1) I created a new memory area
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 63K
STORAGE_FLASH (rx) : ORIGIN = ORIGIN(FLASH) + LENGTH(FLASH), LENGTH = 1K
}
and assigned a new section inside it for memory initialization:
.permanent :
{
. = ALIGN(4);
KEEP(*(.permanent))
. = ALIGN(4);
} >STORAGE_FLASH
And I created a new symbol to track where to write:
__flashStorageBegin = ORIGIN(STORAGE_FLASH);
2) No need to unlock option bytes
3) Page start is aligned with "FLASH" area, since page is 1kB long for this MCU, all pages are a multiple of 1024 bytes from FLASH origin (0x8000000+1024*n)
In the FLASH_AR register you should only write a page start address.
4)You can write the same half-word multilple times without erasing the page mulitple time as long as you don't write 1s.
Extra information from other question I did:
Since you have to write to half-words, you should only write to even addresses.
2024-09-28 06:22 PM
1) It's not required. Best way would be to keep that section of flash out of the linker script. Putting it in there can only cause problems.
2) You do not need to unlock option bytes to write to flash.
3) STM32D103C8T6 isn't a chip, but on the STM32F103C8T6, each flash page is 1K. The last page is page 63 which starts at 0x0800FC00. Steps to erase a page are in the programming manual.
4) You can change bits from 1 to 0 without erasing. Your example works.
2024-09-28 06:39 PM
To make it easier, just create a data structure of your parameters that you use to read/write from flash. When you want to write/modify some specific parameter, read the data from flash to preserve what data you already have, modify the specific data parameter, erase the page, then write everything back to flash, and validate.
2024-09-28 07:30 PM
You don't need to create a section in the Linker Script, just shrink the FLASH size so it doesn't allocate into the space at the end. Define the address as a pointer in the app.
Unlock the flash.
The F1 doesn't allow for multiple bites of the apple, you get one write per word after erasure, but you can chose when you do it.
2024-09-28 07:42 PM
Thanks for your answers, I have some questions though.
What do you mean by "keep out from the linker script"? Should I declare the "FLASH" area to be 62kB instead of 64 for example?
Or you mean just not declaring the section I am gonna use?
If you ment the second one, what can I do so I don't overwrite the program?
Also which problems could it cause?
I've read the PM0075 manual already, but I am not certain about which address can I put there. Let's say I want to write at 0x0800FC02. What should I assign FLASH_AR with? Can I assing 0x...02 or shoud I always round up to 1kB and put 0x....00?
Also new question:
The manual says 16 bits at a time, but what happens if I do the following:
*(__IO uint8_t*)(addr) = data
2024-09-28 07:42 PM
Thanks for your answers, but I did not understood what you ment with 4.
2024-09-28 08:01 PM
Normally a word is considered as 32 bits, but since write operations are in 16 bits packs. Does this mean I write once for every 16 bits pack?
2024-09-29 06:30 AM
> What do you mean by "keep out from the linker script"? Should I declare the "FLASH" area to be 62kB instead of 64 for example?
Yes. By keeping it out of the script, it won't be used by the linker and it won't be overwritten when you flash the chip (unless you select full chip erase, which is not the default).
> I've read the PM0075 manual already, but I am not certain about which address can I put there. Let's say I want to write at 0x0800FC02. What should I assign FLASH_AR with? Can I assing 0x...02 or shoud I always round up to 1kB and put 0x....00?
You put the start of the page in FLASH_AR. The 0x0800FC02 location is within the page that starts at 0x0800FC00.
> The manual says 16 bits at a time, but what happens if I do the following:
Undefined behavior. Likely either a hard fault or an invalid write. You should stick to the supported operations listed in the manual.
2024-09-29 07:25 AM
>>Should I declare the "FLASH" area to be 62kB instead of 64 for example?
Yes, shrink the space.
Write structures with the size and alignment of the flash array, as I recollect this is 32-bit on the F1, but others have wider flash lines
2024-09-29 07:45 AM
The write size is a half-word on the STM32F1, so you should be writing half-words to even addresses. You can write a half-word more than once but you can only turn 1s to 0s.