I'm working on creating a safe firmware upgrade for my adafruit feather m0. I understand from my CTO that wrote the previous upgrade that for either samd21 or all arm m0 (not sure which) the compiler compiles non relative addresses, meaning bx 0x3000 will jump to address 0x3000 and not 0x3000 bytes from my location. My goal is to split the flash into 4 banks:

  1. bootloader (2k)
  2. user data
  3. firmware #1
  4. firmware #2 which firmware will be booted is up to a flag in the flash do decide. i understand from my predecessor this is an issue since firmware#2 when loaded to ram might not run. I disagree and do believe simple changes in the .ld script should accomplish the task.

My only question to you guys is changing the .ld script .text address is enough ? i know the bootloader jumps to an address that was defined in the .ld script if it's not 0xFFFFFF (if the flash was written to). do i ned to change the .ld script to include two .text sections ? do i need to also define how they reside in the RAM as well ? any examples ? hint ?


  • Have you looked at the Samd21 datasheet?
    – PhillyNJ
    May 7 '18 at 10:39
  • The data sheet explained in detail how the samd21 memory is laid out including the boot loader section. I have no idea what you mean about .id script what ide are you using? Also search google for samd21 application note AT07175. A good tutorial on how to program the bootloader
    – PhillyNJ
    May 7 '18 at 10:48
  • the basic ld script shows me the basic memory layout and defines the variables that later on the bootloader uses, i don't need the datasheet for that. ld script and not id script is a GNU script for the ld (linker) that defines the layout in the binary and later on in the flash and memory layout. May 7 '18 at 10:55

A typical LD script consists of two sections - one that defines memory ("MEMORY") regions, and another that defines what to put in those memory regions ("SECTIONS").

To carve holes in an existing memory layout it is usually enough to just change the first section - the part that defines the layout of the memoy. Shrink and move existing blocks of memory and insert new ones.

For example you may have this at the moment:

  FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000-0x2000 /* First 8KB used by bootloader */
  RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000

There is a hole already defined of size 0x2000 at the start of flash, and the sketch is loaded from 0x2000 onwards.

You may want to shrink and move that, and add a "user data" chunk. It's enough to just go:

  USERDATA (rx) : ORIGIN = 0x2000, LENGTH = 0x1000
  FLASH (rx) : ORIGIN = 0x3000, LENGTH = 0x00040000-0x3000
  RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000

(I collapsed some of the maths cus it's pointless). Now the flash area (where the sketch goes) has been shrunk by 0x1000 and moved an extra 0x1000 up the memory map. A USERDATA chunk has been inserted which you can then use later on if you so wish.

To make things get put in there by the linker script (you don't need to change anything else to move the sketch data...) you can define a new section in the later part of the linker script:

.userdata : 

That should then place anything that you put in a .userdata section (or a subsection within that) within your sketch into the USERDATA chunk of flash - separate from your sketch.

const uint8_t __attribute__((section(".userdata"), used)) data[] = { 10, 100, 123, 177, 221, 49 };

However, if you plan to use it like EEPROM and only write to it using code in your sketch then you don't need to worry about anything like that - just carve out the hole. You can also provide some globals to help with your code, though:

(linker script)
PROVIDE(userdata_start = ORIGIN(USERDATA))
PROVIDE(userdata_length = LENGTH(USERDATA))

Then you can use those in your program to know where the USERDATA chunk is and how big it is (ideal if you ever choose to change it - no need to change your code, only the linker script).

  • tn the basic ld script at least the one i have the bootloader is not "holed" from the script it's part of it, it cannot be written to due to the use of fure 4 register i think that protects the first X bytes i think 16K in arduino's default. In any case the ld script also defines a .text region that is later on referred to from the bootloader and uses volatile __asm("bx ...") to jump to that address if the parallel flash address meant for the sketch has code and is not 0xffff (which means it was erased). how does the script "links" between the .text on the flash and the ram area ? May 7 '18 at 11:45
  • what i need is to compile my sketch once when it's base ram area is defined as X and flash X' and once when it's base is Y on the flash and Y' in the RAM. again as i understand all memory addresses are not relative. May 7 '18 at 11:47
  • Good point. The existing bootloader doesn't have a clue. The bootloader and the linker script both have to agree on what they are doing. If you change the linker script to start executing from a different area then you must also change the bootloader to jump to that area. There is no way for the bootloader to know anything unless you tell it.
    – Majenko
    May 7 '18 at 11:55
  • that goes without saying :) i need to mark the beginning, just like it's marked today and get the bootloader to have both addresses or update the address somehow during the firmware upgrade. i'll think of that later on, the real question i guess is lets say i move the .Text segment 0x4000 bytes up the flash memory do i need to relocate it in the script in RAM as well ? your answer says nothing much about the RAM just FLASH so i'm not sure. May 7 '18 at 12:00
  • What is there to "relocate" in RAM? RAM is separate to flash. Moving stuff in flash has no connection to RAM at all. If you want to slice up RAM you can. But that has no relevance to moving stuff in Flash.
    – Majenko
    May 7 '18 at 12:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.