Tom Nixon about

NRF52 Flash Layout

06 Feb 2021

I’ve recently been making another iteration of my low-power sensor project, this time using NRF52 devices. So far these seem really nice, but getting set up for development has taken a while. This is partly down to using a bunch of new tools (and stubbornly avoiding the standard Nordic development tools!), but the thing that took the longest to understand is the flash layout.

It seems quite easy to find this information now, but that’s hindsight talking! This is an attempt to document what I’ve learned before I forget and have to learn it all again.

Resources

These two pages cover most of the information:

Particularly, take a look at the “memory layout” figure on that Nordic page for an overview of how things are laid out.

All file paths in this document refer to files in the NRF5 SDK.

Q: What are all these components?

SoftDevice
Nordic’s proprietary BLE stack, delivered as a hex file and a bunch of headers.
BootLoader
Code that allows updating the firmware over USB, serial or BLE.
MBR
The first thing that runs (it’s executable unlike the PC MBR). This passes control to the bootloader, and handles interrupts. Also proprietary.
Application
The bit of code you’re actually trying to run.

Q: That looks complicated, do we really need all that stuff?

Nope! If you don’t want BLE or a bootloader, it’s fine to just write application code that starts at address 0. This is how the peripheral/bsp example works.

Q: So where’s the start address defined, then?

In the linker script. For example in examples/peripheral/bsp/pca10056/blank/armgcc/bsp_gcc_nrf52.ld, we have:

FLASH (rx) : ORIGIN = 0x0, LENGTH = 0x100000

which puts it at 0x0. Example applications which require a SoftDevice might have ORIGIN = 0x27000.

Q: Once I’ve compiled my application and have a hex file, how does the programmer know where it’s supposed to go in flash?

Intel hex files can contain multiple chunks, each with their own offset. Who knew? [1]

Q: How do I know where to put my application?

This is listed in the SoftDevice release notes… sort of.

It’s given in the “The combined MBR and SoftDevice memory requirements”:

Flash: 156 kB (0x27000 bytes)

This size should match the ORIGIN in your linker script.

Q: Where does the MBR come from?

Normally it’s included as part of the SoftDevice hex. It’s also available separately, in components/softdevice/mbr.

Q: Where does the bootloader come from?

Some development boards come with a bootloader already installed. If you need to install your own, or want to change the behaviour, the code is in examples/dfu.

Q: How does the MBR know where the bootloader is?

The linker script for the bootloader puts the start address in a “User information configuration register” (UICR), which is read by the MBR.

Q: Can I use a bootloader without a SoftDevice?

Yes, set ORIGIN = 0x1000. This is given as MBR_SIZE in components/softdevice/mbr/headers/nrf_mbr.h.

Conclusion

That’s it for now, hopefully this is helpful. I’m planning on writing more about other aspects of NRF5 development soon. Perhaps:

  • ESB radio with long-range BLE radio modes
  • using cmake for building
  • using openocd, including getting logs over SWD using RTT
  • setting up a development environment using Nix
[1]I did, but I was confused by looking at a non-SoftDevice example and not knowing where the start address is defined.