cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F401 Using flash memory sector 0 as storage

Chuckero
Associate II

Hello,

I'm searching for a way to use sector 0 as storage memory but no luck so far.

I'm using STM32F401CCU6 and I'm working on a firmware which have to save about 300 bytes in a no volatile memory. For this microcontroller family we have this memory map:

Sector   -  Address ini    ~ Address end   - Size
Sector 0 - 0x0800 0000 ~ 0x0800 3FFF - 16 Kbytes
Sector 1 - 0x0800 4000 ~ 0x0800 7FFF - 16 Kbytes
Sector 2 - 0x0800 8000 ~ 0x0800 BFFF - 16 Kbytes
Sector 3 - 0x0800 C000 ~ 0x0800 FFFF - 16 Kbytes
Sector 4 - 0x0801 0000 ~ 0x0801 FFFF - 64 Kbytes
Sector 5 - 0x0802 0000 ~ 0x0803 FFFF - 128 Kbytes
Sector 6 - 0x0804 0000 ~ 0x0805 FFFF - 128 Kbytes
Sector 7 - 0x0806 0000 ~ 0x0807 FFFF - 128 Kbytes

So far I already used a little bit more then 66kB, which means, my firmware is using sectors 0 to 4 and increasing.

Now, I'm already saving the data in flash memory, all good for the sector 5 using HAL. But it's only 500 bytes in a block of 128Kbytes, it's a waste of memory, and when the firmware reaches the block 5 I'll have to move the data to next sector.

So, the question is: is it possible to use sector 0 as storage and make the boot start from block 1?

The best information I found about it, was this post, but it's about STM32F7 and that solution is not available for F4:
https://stackoverflow.com/questions/56896375/how-can-i-change-the-start-address-on-flash/56902284#56902284

Thank you all.

14 REPLIES 14
Chuckero
Associate II

Thanks @Tesla DeLorean everything is working as planned now.

One last question, about the memory optimization. Now I have this memory usage:

Chuckero_0-1694475758790.png

I notice the initial block (sectors 0 to 2) is using only 412 bytes.So, my first shot is to move my storage from sector 3 to sector 1. Other than that, can I freely play with the sectors in linker script? Is there something to avoid or "dangerous"? My intention is to fill as much of sector 0 as possible.
This is what I have in linker script following the suggestions:

 

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */

_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */

/* Memories definition */
MEMORY
{
  RAM    (xrw)      : ORIGIN = 0x20000000, LENGTH = 64K
  FLASH_ISR (rx)    : ORIGIN = 0x08000000, LENGTH = 48K
  FLASH_HOLE (rx)   : ORIGIN = 0x0800C000, LENGTH = 16K
  FLASH (rx)        : ORIGIN = 0x08010000, LENGTH = 256K-64K
}

/* Sections */
SECTIONS
{
  /* The startup code into "FLASH" Rom type memory */
  .isr_vector :
  {...} >FLASH_ISR

  /* The program code and other data into "FLASH" Rom type memory */
  .text :
  {...} >FLASH

  /* Constant data into "FLASH" Rom type memory */
  .rodata :
  {...} >FLASH

  .ARM.extab   :
  {...} >FLASH_ISR

  .ARM :
  {...} >FLASH

  .preinit_array     :
  {
  } >FLASH_ISR

  .init_array :
  {
  } >FLASH_ISR

  .fini_array :
  {
  } >FLASH_ISR

  /* Reserve section 3 from flash memory. */
  .myDataStorage 0x800C000 :
  {...} > FLASH_HOLE

  /* Initialized data sections into "RAM" Ram type memory */
  .data :
  {...} >RAM AT> FLASH

  /* Uninitialized data section into "RAM" Ram type memory */
  . = ALIGN(4);
  .bss :
  {...} >RAM

  /* User_heap_stack section, used to check that there is enough "RAM" Ram  type memory left */
  ._user_heap_stack :
  {...} >RAM
}

 

Thanks again

The Linker Script  an be used to funnel the content of particular objects into the desired section. Perhaps cherry pick C library content to start filling that section 

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

@Pavel A. wrote:

In addition to what @Tesla DeLorean wrote: you cannot rewrite a portion of flash sector , even if the data written there is all FFs (I don't quite understand why, but this is from experience). You can write each "write unit" only once after erase. This means that you should write the sector 0 so that the unused space after the vectors and other stuff remains virgin. Make a separate small "image" (hex/bin) for the sector 0 and write it using CubeProgrammer or other tool, usually these tools won't fill end of sector after the data.

Then locate the start of unwritten area in sector 0 and program your data there as usual.


Hello @Pavel A.,
What you mean with "you cannot rewrite a portion of flash sector"? I didn't understand, because, at this moment my firmware is writing about 300 bytes at the first address of sector 1, then, when the user change some parameters the new data is saved at first address + 300, next time it goes at first address + 600, etc. All working perfectly and this way I can increase the flash lifespan hundreds of times.

>next time it goes at first address + 600

So you are not RE-writing at (first address + 0x300), you're writing at a new fresh location. What I meant was writing twice at the same address without erase.

@Pavel A. wrote you cannot rewrite a portion of flash sector , even if the data written there is all FFs (I don't quite understand why, but this is from experience).

The reason is that ST uses error-correction-coding (ECC). As well as all the 64 (or whatever) number of bits in each line of FLASH, there are a further few bits (perhaps 8 for a 64-bit line). The ECC can correct any single bit that reads back wrongly, and detect when two bits are wrong.

The actual bit pattern needed to be written in ECC depends, of course, on what bit pattern is written in the FLASH line. It is based on something like a Hamming code, and needs to be simple such that it does not delay the read of the memory location. Consequently, the ECC pattern where the FLASH line is 0xFFFFFFFFFFFFFFFF is NOT 0xFF.

ST must have put special logic into the error-correction read algorithm to detect and ignore ECC errors where all bits (including the ECC ones) are erased. But they have not bothered to put a similar "special-case exception" in the FLASH write code, where the ECC pattern is generated. If that's important to you, you can add code to your flash-write function that skips the write if the value-to-write is 0xFFFFFFFFFFFFFFFF.

Suppose the ECC pattern for 0xFFFFFFFFFFFFFFFF is 0xDB

Where the stm32 reads 0xFFFFFFFFFFFFFFFF 0xDB it knows the data is good, and passes that to the arm core.

Where the stm32 reads 0xFFF7FFFFFFFFFFFF 0xDB, it knows it has 1 bit error, corrects that and passes 0xFFFFFFFFFFFFFFFF to the arm core.

Where the stm32 reads 0xFFFFFFFFFFFFFFFF 0xFF, it sees the special case of blank memory, and passes that to the arm core.

Where the stm32 reads 0xFFFFFFFFFFFFFFFF 0xDA, it knows it has 1 bit error in the ECC bits, corrects that and passes 0xFFFFFFFFFFFFFFFF to the arm core.

If you wish to write a line of FLASH, it has to start 0xFFFFFFFFFFFFFFFF 0xFF in order that programming can succeed. But if you write 0xFFFFFFFFFFFFFFFF then it will put 0xDB into the ECC bits. So the line cannot be written again.

I do not know who first started adding ECC to FLASH memory. The first arm microcontrollers I was aware of that had it were the (then) Philips LPC2xxx series. I think manufacturers regard the benefits (they can use smaller=cheaper memory cells, run them faster or at lower power and get fewer dead chips) often outweigh the complications users see in reprogrammability.