cancel
Showing results for 
Search instead for 
Did you mean: 

Questions about saving data to flash

kukoldiega
Associate II

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?
 

1 ACCEPTED SOLUTION

Accepted Solutions
kukoldiega
Associate II

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.
 

 

View solution in original post

10 REPLIES 10
TDK
Guru

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.

TDK_0-1727572966794.png

PM0075.pdf

 

4) You can change bits from 1 to 0 without erasing. Your example works.

If you feel a post has answered your question, please click "Accept as Solution".
Karl Yamashita
Lead III
  1. Yes, you need to modify the linker script to reserve a page for your data you want to save. Else your program could use that page. And if you erase the page, you've lost part of your firmware.
  2. You need unlock to erase and write. You don't need it for reading flash.
  3. With your example with 3 and 5, it won't work, just as you indicated that you can't write a 1 where there is a zero. 
  4. If you use ST's driver, you specify the address you want to write data to, after the page has been erased.

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. 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.

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.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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

 

Thanks for your answers, but I did not understood what you ment with 4.

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?

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

If you feel a post has answered your question, please click "Accept as Solution".

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

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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.

If you feel a post has answered your question, please click "Accept as Solution".