Arm GCC linker: how to put data at absolute address in (rw)-non-volatile memory
Asked Answered
B

1

3

I am facing the following problem. I am programming an ARM cortex M4 micro controller and I would like it to have a default value for IP address, netmask, gateway and so on. This default values should be changeable via serial communication AND the changes should be persistent. For example: default value for IP address and netmask are: 192.168.1.20 255.255.255.0 The user changes the address and netmask to 192.168.2.10 255.255.255.0 Now after disconnecting and reconnecting the unit to power supply the "default" values should be the user entered (192.168.2.10/255.255.255.0)

To solve this, I thought about using the so called work flash memory of my uC. This is a non-volatile memory which can be written using special commands. What I am trying to achieve is to define default values in the program code (as variables at the moment, or as defines later if possible) which are picked up by the linker and whose VALUE is put to the non-volatile memory (work flash) at address 0x200C000.

Right now my linker file looks like this:

MEMORY
{
    rom  (rx)  : ORIGIN = 0x00000000, LENGTH = 0x100000 /* 1MB */
    ram  (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 0x10000 /* 64K  */
    ram1 (rwx) : ORIGIN = 0x20038000, LENGTH = 0x10000  /* 64K  */
    wofl (rwx) : ORIGIN = 0x200C0000, LENGTH = 0x8000   /* 32K  */
}

...

.wifi_defaults :
{
    KEEP(*(.wifi_defaults*));
} > wofl

...

and the variable declaration in the source code (just for testing):

uint16_t __attribute__((section(".wifi_defaults"))) test= 0x00D0;

The .map file shows me:

.wifi_defaults  0x200c0000        0x2
 *(.wifi_defaults*)
 .wifi_defaults
                0x200c0000        0x2 ..\obj\HSFirmware.o
                0x200c0000                test

But when accessing the variable I am not getting the correct value, just the initial 0xFFFF which was returned even before starting to mess with the linker stuff.

I also tried to use a CONST in front of the variable declaration, which made no difference.

As far as I understand my code puts an uninitialized variable at the specified code segment. How can I put an initialized variable at the given address?

Binoculars answered 12/10, 2016 at 15:24 Comment(5)
Un-programmed flash memory reads as 0xffff. How does the code/data get to the device? Also, you need routines to do the special sequence to program the code for the update. I would suggest that you do not try to initialize the data in 'flash'. Instead keep a default ROM copy (which seems to work/program). If you read 0xffff, then call you flash program routine to make it the default. Also you can provide an option to restore defaults. There are issues with the loading tools and binary format that need to be resolved otherwise. Please read about VMA and LMA in the LD documents.Sayers
You should probably do a checksum/crc, etc of the flash configuration data. If it is bad, then you can use the defaults which will reside in ROM (and could be set via a define). The flash may go bad during normal use (lasts ~10 yrs?) and the user will at least still have a semi-functioning device if it goes bad and you use sensible defaults (as opposed to random garbage).Sayers
Related:stackoverflow.com/questions/39892860/… The answer there might be answering this as wellConclusive
artless noise, that is exatly what I implemented in the meantime. And while implementing I came to the same solution, that it would be beneficial to have the default data in ROM and write it to the flash in order to be able to restore factory defaults. Thanks for you comment.Binoculars
If you are flashing your device with a tools that knows how to write flash at 0x200C0000, it'll do it for you. Otherwise, I'd recomment the 1st comment of @artless noise.Person
A
0

You have missed the 'used' attribute to force the compiler to keep this variable.

By the way, in some posts I saw that it is not enough to avoid the link to throw away the section if there is no code that uses it (in your case, some code using the test variable).

Personally, I have tested it with GCC for ARM version 10.3.1, and it wasn't necessary.

Thus, in your example, it would be defined as following:

uint16_t __attribute__((section(".wifi_defaults")), used) test= 0x00D0;
Alceste answered 16/2, 2023 at 6:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.