Skip to main content
Bertrand1
Senior
August 17, 2020
Question

Weird behaviour with data in flash ( STM32F412RE)

  • August 17, 2020
  • 6 replies
  • 2115 views

Hello,

I have some application parameters stored in flash area, declared like this :

__attribute__((__section__(".storageFlash"))) const parametersTable_t flashParameters;

The linker script has been modified as follow:

/* Specify the memory areas */

MEMORY

{

RAM (xrw)     : ORIGIN = 0x20000000, LENGTH = 256K

FLASH (rx)     : ORIGIN = 0x8000000, LENGTH = 384K

PARAMETERS_STORAGE (rx)   : ORIGIN = 0x08060000, LENGTH = 64K

CALIBRATION_STORAGE (rx) : ORIGIN = 0x08068000, LENGTH = 64K

}

....

 .storageFlash (NOLOAD) :

 {

   . = ALIGN(4);

   *(storageFlash)

   . = ALIGN(4);

 } >PARAMETERS_STORAGE

In my program I do a simple copy on a local data or make a comparaison with Ram data like this : temp = flashParameters.version;

With Atollic , I can read that flashParameters.version = 12 but temp = 0!!

If I read the raw memory I can also find 12.

I don't understand why the programm read always 0 instead of 12.

Thanks for your help

Bertrand

This topic has been closed for replies.

6 replies

Tesla DeLorean
Guru
August 17, 2020

Some of your memory regions overlap.

Check the addresses in .MAP

Check the code generated in the listing file (.LST, .LSS, whatever)

The optimizer might assume a const region with nothing defined in it might be zero

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Bertrand1
Bertrand1Author
Senior
August 17, 2020

Thanks Clive for your prompt reply.

I checked .map : flashParameter is located at 0x08060000.

It is correct according to the linker script.

I am try to understand the .list file but too low level for me. Here an extract :

 temp = flashParameters.version;
 temp2 = flashParam.version;
 sprintf(sBuf, " Stored parameters version is %d ...", temp);
 8019988:	4c25 	ldr	r4, [pc, #148]	; (8019a20 <isConfigInFlashValid+0xac>)
 801998a:	2200 	movs	r2, #0
 801998c:	4925 	ldr	r1, [pc, #148]	; (8019a24 <isConfigInFlashValid+0xb0>)
 801998e:	4620 	mov	r0, r4
 8019990:	f004 f98c 	bl	801dcac <siprintf>

   

TDK
August 17, 2020

Maybe it's just optimized out or the line has been shuffled somewhere else.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Bertrand1
Bertrand1Author
Senior
August 18, 2020

I don't think so. I removed almost all optimization and I do a comparaison after that and it fails.

12 == 12 -> Wrong!

I am crazy ;)

Bertrand1
Bertrand1Author
Senior
August 18, 2020

Additionnal information : If I place the code in the main.c ( uint16_t test = flashParameters.version). it works!

For today, I do a memcpy on a RAM structure in a step before ( I don't know how to explain, but I do this memcpy one step before in the call stack)

waclawek.jan
Super User
August 18, 2020

Read out that FLASH area - does it contain what you think it should?

Step through disasm and observe registers.

JW

Bertrand1
Bertrand1Author
Senior
August 18, 2020

Thanks for your help.

I read out the flash and I can find the right value on it.

For disassembly analysis with register, I have a lack ok knowledge to do it yet. :(

Bertrand

waclawek.jan
Super User
August 18, 2020

I don't know what development environment are you using, but in IDEs it's usually just about clicking into the disasm window and single-stepping as usually. Shouldn't be that hard to try.

JW

Bertrand1
Bertrand1Author
Senior
August 18, 2020

I am on Atollic Studio 9.3.

Not difficult to find the disassembly but to understand what the programm do exactly.

waclawek.jan
Super User
August 18, 2020

Observe how do the Rx registers change. It's not that hard to guess.

From your snippet:

> ldr r4, [pc, #148] ; (8019a20 <isConfigInFlashValid+0xac>)

This load content of 0x08019a20 into register r4.

> movs r2, #0

This moves constant 2 into register 2.

> ldr r1, [pc, #148] ; (8019a24 <isConfigInFlashValid+0xb0>)

This loads content of 0x8019a24 into r1

> mov r0, r4

This moves content of r4 into r0.

> bl 801dcac <siprintf>

This calls sprintf (okay, siprintf, which is an optimization on sprintf performed by the library).

First 4 parameters to functions are usually passed in r0, r1, r2, r3; return value is passed back in r0 (this is given by ARM ABI).

The first parameter, address of sbuf, was loaded in the first step into r4 then moved to r0.

The second parameter, address of the format string, was loaded in the third step.

The third parameter, in r2, is 0, and that's what's printed out.

So, the optimizer judged that flashParameters.version == 0. It did so because you probably don't initialize flashParameters.version (you probably load some direct value into it through a different mechanism which the C compiler does not see), so for C, it's an global variable which is not explicitly initialized - as such it's implicitly initialized to 0 so the optimizer may assume it is 0.

Qualify flashParameters as volatile.

JW

Bertrand1
Bertrand1Author
Senior
August 18, 2020

Ok, thanks.

I will check that.

Bertrand