Splitting Code Among Multiple Memory Areas

Asked by Cat C

Hello,
STM34F4xx don’t have EEPROM but it can be emulated according to Application Note “AN3969”.

However, we need to use some of the Flash; recommended are sectors 2 and 3.
However, after this we need to tell the linker to use all flash for code (text) except sectors 2 and 3.

How do I tell the linker to “bridge” the two areas together?
I think it would be in "arm-gcc-link.ld" around here:

MEMORY
{
 rom (rx) : ORIGIN = 0x08000000, LENGTH = 0x00008000
 rom1 (rx) : ORIGIN = 0x08010000, LENGTH = 0x000F0000
 ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
 ram1 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000
}
SECTIONS
{
    .text :
    {
        KEEP(*(.isr_vector .isr_vector.*))
        *(.text .text.* .gnu.linkonce.t.*)
        *(.glue_7t) *(.glue_7)
        *(.rodata .rodata* .gnu.linkonce.r.*)
    } >> rom | rom1
...
}

In some TI compiler/linker I saw this:
SECTIONS
   {
.text: { *(.text) } >> P_MEM1 | P_MEM2 | P_MEM3 | P_MEM4
   }
but it doesn't seem to work with GNU tools for ARM.

Thanks,

Cat

Question information

Language:
English Edit question
Status:
Answered
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
Freddie Chopin (freddie-chopin) said :
#1

From what I know you cannot do that - you can just MANUALLY place specific object files (or matched by regex) in specific regions of memory. For that reason just use LAST two sectors for EEPROM emulation and the rest of flash is for you - you "waste" some memory, but you keep it simple (; Other approach might me to place just vectors (maybe startup) in the first sector, your EEPROM in two next sectors.

Revision history for this message
Cat C (catalin-cluj) said :
#2

I'm still hoping it's possible as it's possible with other tools.
Using the last sectors might be OK but I'd hate it out of "principle" (not sure how to say that).
How would I do the last thing you suggested: some startup in the first sector?
Actual code if possible, please.
Because I tried to not put anything in the first 4 sectors and that didn't work; it looks like something HAS to be in the first one.
This is what I have. The commented-out lines are what I need or things I tried.

MEMORY
{
 rom (rx) : ORIGIN = 0x08000000, LENGTH = 0x00100000
/* rom (rx) : ORIGIN = 0x08000000, LENGTH = 0x00008000 */
/* rom1 (rx) : ORIGIN = 0x08010000, LENGTH = 0x000F0000 */
 ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00020000
/* ram1 (rwx) : ORIGIN = 0x10000000, LENGTH = 0x00010000 */
}

_eram = 0x20000000 + 0x00020000;

/* Section Definitions */
SECTIONS
{
    .text :
    {
        KEEP(*(.isr_vector .isr_vector.*))
        *(.text .text.* .gnu.linkonce.t.*)
        *(.glue_7t) *(.glue_7)
        *(.rodata .rodata* .gnu.linkonce.r.*)
    } > rom

/* .text :
    {
        KEEP(*(.isr_vector .isr_vector.*))
        *(.text .text.* .gnu.linkonce.t.*)
        *(.glue_7t) *(.glue_7)
        *(.rodata .rodata* .gnu.linkonce.r.*)
    } > rom1 */

    .ARM.extab :
    {
        *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > rom

    __exidx_start = .;
    .ARM.exidx :
    {
        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    } > rom
    __exidx_end = .;

    . = ALIGN(4);
    _etext = .;
    _sidata = .;

    .data : AT (_etext)
    {
        _sdata = .;
        *(.data .data.*)
        . = ALIGN(4);
        _edata = . ;
    } > ram

    /* .bss section which is used for uninitialized data */
    .bss (NOLOAD) :
    {
        _sbss = . ;
        *(.bss .bss.*)
        *(COMMON)
        . = ALIGN(4);
        _ebss = . ;
    } > ram

    /* stack section */
    .co_stack (NOLOAD):
    {
        . = ALIGN(8);
        *(.co_stack .co_stack.*)
    } > ram

    . = ALIGN(4);

    _end = . ;
}

Revision history for this message
Joey Ye (jinyun-ye) said :
#3

GNU linker doesn't have the feature to split input sections into more than one output sections. There was a brief discussion about similar request but got no follow-up http://sourceware.org/ml/binutils/2012-04/msg00359.html

I took a look a overlay and feel that enabling this feature is non-trivial. I'd still recommend manually splitting as Freddie suggested, at least in near future.

- Joey

Revision history for this message
Cat C (catalin-cluj) said :
#4

Thank you Joey,

If I use the last 2 sectors that is a quarter of all FLASH!

I would love to follow Freddie's other suggestion to place vectors/startup in the first sector and use next 2 for EEPROM, but I don't know how to do that.
That's why I posted my .ld file and asked for help with that.

Thanks,

Cat

Revision history for this message
Freddie Chopin (freddie-chopin) said :
#5

The simpliest approach, but not the "clean" one, would be to just move the current address (; You have just one memory region, you place your vector table, and just after it do:
. = 0x8008000
This will make the space from end of vectors (or whatever you have before) till 0x8008000 "unallocated" (free).

The better one is to do sth like that (I've not checked the code):

MEMORY
{
 rom (rx) : ORIGIN = 0x08000000, LENGTH = 0x00008000
 rom1 (rx) : ORIGIN = 0x08010000, LENGTH = 0x000F0000
...
}
...

EXTERN(vectors)

SECTIONS
{
    .vectors:
    {
        KEEP(vectors.o(.isr_vector .isr_vector.*))
    } > rom

    .text :
    {
        *(.text .text.* .gnu.linkonce.t.*)
        *(.glue_7t) *(.glue_7)
        *(.rodata .rodata* .gnu.linkonce.r.*)
    } > rom1
...

Few things to keep in mind:
1. If you have vector table NOT in .text section it may get discarded, that's why I put "EXTERN(vectors)" above - the symbol in parentheses must match the VARIABLE in the section (the vector table itself), not the section name (it does not matter) - I put vectors in ".vectors" section, as I'm not sure you can have multiple ".text" sections, probably not (;
2. This line
KEEP(vectors.o(.isr_vector .isr_vector.*))
will put sections .isr_vector and .isr_vector.* in here, but ONLY from vectors.o object file (this MUST match the file in which you have the vector table, maybe startup.o or sth like that). Make sure the table is NOT in .text section.

This is the simpliest approach. If you'd like to split .text sections from multiple files it gets harder, as you need to EXPLICITLY list the files (or provide a regex to match them), sth like:

.section1: { file[0-5]*(.text) }
.section2: { file[6-9]*(.text) }
...

The other option is to do sth like this:

.section1: { file[0-5]*(.text) }
.section2: { *(EXCLUDE_FILE (file[0-5]*) .text) }

Revision history for this message
Cat C (catalin-cluj) said :
#6

I have to work on other things for a while so I can't test the "hole" at this point.
I got the emulation to work on the last 2 sectors; loosing 256K of FLASH.

When/IF I can get the "hole" to work, I may have some further problems: I plan to use "dfu-util" for field upgrades.
Does anybody know if I can tell "dfu-util" to leave the hole un-programmed?
I realize this may not be the place to ask but it's related; I will ask the "dfu-util" people if nobody here knows.

Thanks,

Cat

Revision history for this message
Freddie Chopin (freddie-chopin) said :
#7

To have such "hole" unprogrammed you'd need to have a linker script with "nothing" there. Just moving the current address won't make it happen - the region will be filled with 0xFFFF. And the program you're going to use needs to read files with address info like hex or elf - bin is out of the question.

So - first solution (the naive one) won't work in such scenario. The other two should work if the software you use reads hex or elf files.

Can you help with this problem?

Provide an answer of your own, or ask Cat C for more information if necessary.

To post a message you must log in.