Bluetooth Low Energy (a.k.a Bluetooth LE, BTLE, Bluetooth Smart)

Internals of the Nordic DFU Bootloader

05 Dec 2014

DFU Bootloader

Overview of Components

  • softdevice (i.e. bluetooth stack)
  • application
  • DFU-Bootloader
  • Bootloader settings page
  • UICR (register defined by nRF MCU which tells the softdevice where to forward control: bootloader or application).

The bootloader settings page tell the bootloader about forwarding control to the application.

When working with the mkit or any mbed Nordic platform, drag-n-drop of the firmware over USB results in a mass-erase followed by programming. In that case, the following options exist:

Softdevice + application [default builds using the online IDE; non FOTA] Softdevice + application + Bootloader + UICR pointing to the bootloader [initial app; available for download]

When updating over FOTA, the following is needed:

application only [meant for FOTA; build platforms available from links mentioned in the individual platforms page; requires the presence of a bootloader and also DFUService in the current application]

If you need FOTA, you must somehow get the softdevice and bootloader and initialized-UICR on the device. srec_cat can be used to combine things; and also initialize UICR and bootloader settings.

Sources and Build Instructions for the Bootloader

The sources are available publicly on GitHub. They are derived from Nordic's SDK V6.1.0 with very minor modifications.

A CMakeLists.txt file in included. The bootloader build depends on some headers and a few sources from mbed-src and the nRF51822 libraries; you'll need to point some variables within the CMakeLists.txt to the locations for these components. You can build the bootloader with the following steps:

Quote:

/BLE_BootLoader$ mkdir Build
/BLE_BootLoader$ cd Build/
/BLE_BootLoader/Build$ cmake ..
/BLE_BootLoader/Build$ make -j all

Please note that we expect to fit the bootloader within 16K of internal flash (at the upper end of the code space); and this includes nearly 1K of configuration space (for bootloader settings), so the actual available code size is a little less than 15K. Depending on your toolchain, it may be a challenge to fit the bootloader within these constraints. Doing this with ARM- CC required the user of the linker feedback files involving two rounds of compilation in which the first round generated the feedback file; please refer to the command line compiler option called 'feedback' under infocenter.arm.com or search for "Minimizing code size by eliminating unused functions during compilation" in the context of armcc.

If you are unable to fit the bootloader within 16K, then increase the value of the constant BOOTLOADER_REGION_START; you'll then also need to make a corresponding change in the bootloader's linker script to place the vector table at the new START address.

Receiving Control at Startup

At reset, the SoftDevice checks the UICR.BOOTADDR register. If this register is blank (0xFFFFFFFF), the SoftDevice assumes that no bootloader is present. It then forwards interrupts to the application and executes the application as usual. If the BOOTADDR register is set to an address different from 0xFFFFFFFF, the SoftDevice assumes that the bootloader vector table is located at this address. Interrupts are then forwarded to the bootloader at this address and execution will be started at the bootloader reset handler.

The UICR is a collection of memory-mapped configuration registers starting from the address 0x10000000; and can be programmed like any other part of the internal flash.

The following snippet within bootloader_settings_arm.c sets up the update for UICR. It sets up the UICR.BOOTADDR to point to the vector table of the bootloader.

uint32_t m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOT_START_ADDRESS))) = BOOTLOADER_REGION_START;

You should be able to verify that the .hex file generated for the bootloader contains the update to UICR.BOOTADDR. The following lines at the end of the generated .hex file do the trick:

Quote:

:020000041000EA
:0410140000C0030015

They specify the programming of the 4-byte value 0x0003C000 at address 0x10001014, which is the address of UICR.BOOTADDR. Please refer to the format for Intel HEX files. Please also refer to the datasheet for the nRF51822 for the layout of registers within the UICR region.

Setup to Forward Control to the Application

After being handed control, the bootloader looks for an application at the end of the SoftDevice; and if it fails to find one then it sets up the DFUService and waits for a new firmware.

In the normal case where there is an application, you'd want the bootloader to forward control to it. The bootloader must be instructed to look for a valid application by updating its settings; this can either be done statically or by writing into the 'settings' region manually. Settings reside within the page starting at the address 0x003FC00.

The following settings need to be installed (listed alongside the corresponding addresses):

Quote:

0x3FC00: 0x00000001
0x3FC04: 0x00000000
0x3FC08: 0x000000FE
0x3FC0C-0x3FC20: 0x00000000

The above can be accomplished by amending the command line options to srec_cat with the following sequence placed *after* ${PROJECT_NAME}.hex -intel:

Quote:

-exclude 0x3FC00 0x3FC20 -generate 0x3FC00 0x3FC04 -l-e-constant 0x01 4 -generate 0x3FC04 0x3FC08 -l-e-constant 0x00 4 -generate 0x3FC08 0x3FC0C -l-e-constant 0xFE 4 -generate 0x3FC0C 0x3FC20 -constant 0x00

Combining With the SoftDevice and an Initial Application

The initial image to be programmed onto a device needs to contain the soft- device combined the dfu-bootloader and possibly an initial application.

One such potential initial application is:

[Repository '/teams/Bluetooth-Low-Energy/code/BLE_Default_APP/' not found]

The following is a complete command to combine all the above components:

Quote:

srec_cat ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib/s110_nrf51822_7_0_0/s110_nrf51822_7.0.0_softdevice.hex -intel BLE_Default_APP.hex -intel ../../BLE_BootLoader/Build/BLE_BOOTLOADER.hex -intel -exclude 0x3FC00 0x3FC20 -generate 0x3FC00 0x3FC04 -l-e-constant 0x01 4 -generate 0x3FC04 0x3FC08 -l-e-constant 0x00 4 -generate 0x3FC08 0x3FC0C -l-e-constant 0xFE 4 -generate 0x3FC0C 0x3FC20 -constant 0x00 -o combined.hex -intel

Et voila, the above produces a combined.hex which is ready to be flashed onto the target following a mass-erase; and you've got your DFU bootloader setup.

Receiving Control from an Application when FOTA is Triggered

The Bootloader receives control in one of two possible cases: either from the SoftDevice during system startup, or from an application for which FOTA has been triggered. In the second case, the bootloader should always enter DFU mode and wait for a new firmware. It is important for the bootloader to be able to distinguish between the two possibilities. This is done through one of the registers in the power-domain: the GPREGRET, which is the general purpose retention register (has nothing to do with retaining regrets).

A DFU enabled application executes the following code when DFU is triggered by writing into the control characteristic of the DFU service:

sd_power_gpregret_set(BOOTLOADER_DFU_START);

The above sets GPREGRET, which can then be read back by the bootloader.

BOOTLOADER_DFU_START happens to be some constant which is understood by the bootloader as a special indication that control flowed into it from an application (instead of the SoftDevice).

Finally

You're free to modify and enhance the bootloader; and you're encouraged to do so. You might want to have your particular flavour depend on certain buttons or other settings to do special boot-yoga.

We're intending to rewrite the bootloader using mbed's BLE_API; and we also want to abstract out the platform agnostic parts of the bootloader to be able to produce a portable variety.

Happy Hacking. And may FOTA be fun for you.

21 Jan 2015

Hi,

I am trying to do this on Windows host. I am not familiar with cmake and I have problem to make this work. Problem is to build bootloader.

  • cmake .. does not work for me... I added toolchain.cmake file
  • I called next command (command pass) cmake .. -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake -G "MSYS Makefiles"
  • command make -j all does not work. Error is /bin/sh: /C/Program Files (x86)/CMake/bin/cmake.exe: No such file or directory

Can you give me some advice how to do this on Windows host?

Thanks a lot Best regards Milan

21 Jan 2015

I work with Linux as my development platform; but I'm quite sure CMake works on Windows. You should be able to build on Windows, but I won't be able to guide you about that. Surely someone from the community can jump in and help.

22 Jan 2015

Hi Milan,

If you are familiar with Makefile and GCC, you can have a try of https://github.com/Seeed-Studio/nrf51_dfu_bootloader

Best, Yihui

22 Jan 2015

Hi Yihui,

Thanks for link. It is OK.... I can compile your code .... I do not have problem with Makefile, GCC and cmake under Linux as my dev platform. But, for this project Windows host is requested by customer...

I am little confused with this bootloader. I am waiting for NRF51-DK board and this need to be done on this board. On mbed site, I see hex file for NRF51-DK. With this, I can compile sample project for FOTA Platform and program from androide phone as example...This is clear...

Your bootloader is for Seeed platform. Is there a source code for NRF51-DK or I will need to port for this board?

Thanks...

Best regards

Milan

22 Jan 2015

The nRF-DK is not much different from the nRF-mkit; it has the same amount of internal flash but double the SRAM. The booloader hex built for the mkit should work just the same for the DK.

22 Jan 2015

Hi Guys,

Is there any software that allows us to upload new version of firmware over the air from a computer (linux or mac os x) using this boot loader or is it right now only available as phone app uploader?

/Marek

23 Jan 2015

Hi Marek,

I successfully uploaded a new version of firmware with the script - https://github.com/xiongyihui/nrf51_dfu_tool on Ubuntu/Linux.

- Yihui

24 Jan 2015

Hi guys !

I am trying to use DFU on nRF51822 without external crystal. The "initial image" to install the bootloader doesn't work (I can't see my device). So I guess I am supposed to modify the bootloader the use it with internal clock only right ? Has somebody done that already ?

In the source files, I have found this line that could be the origin of the problem in the main.cpp : SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, true);

What else ?

Jules

25 Jan 2015

You're using a non-standard hardware platform. You need to update SystemInit in system_nrf51822.c found in mbed-src/libraries/mbed/targets/cmsis/TARGET_NORDIC/TARGET_MCU_NRF51822/ to use the correct clock source.

28 Jan 2015

I assume the clock setup in the boot loader also has to be changed?

29 Jan 2015

I'm trying to get the cmake working on windows,but I've run into an error that I could do with som help please:

cmake

C:\nrf51822\MyDFUTest\dfu-bootloader\Build>cmake .. -G "Unix Makefiles"
-- MBED_SRC_PATH : C:/nrf51822/MyDFUTest/dfu-bootloader/../mbed-src
-- BLE_API_SRC_PATH : C:/nrf51822/MyDFUTest/dfu-bootloader/../BLE_API
-- NRF51822_SRC_PATH : C:/nrf51822/MyDFUTest/dfu-bootloader/../nRF51822
-- The ASM compiler identification is unknown
-- Found assembler: c:/Keil_v5/ARM/ARMCC/bin/armcc.exe
-- Warning: Did not find file Compiler/-ASM
-- C compiler  : c:/Keil_v5/ARM/ARMCC/bin/armcc.exe
-- C++ compiler: c:/Keil_v5/ARM/ARMCC/bin/armcc.exe
-- Size command: size
-- Main target : BLE_BOOTLOADER.elf
-- Configuring done
-- Generating done
-- Build files have been written to: C:/nrf51822/MyDFUTest/dfu-bootloader/Build

Then...

make

C:\nrf51822\MyDFUTest\dfu-bootloader\Build>make all
Linking CXX executable BLE_BOOTLOADER.elf.exe
"C:/nrf51822/MyDFUTest/dfu-bootloader/bootloader.sct", line 7 (column 9): Error: L6236E: No section matches selector -
no section to be FIRST/LAST.
Not enough information to produce a FEEDBACK file.
Not enough information to list the image map.
Finished: 2 information, 0 warning and 1 error messages.
make[2]: *** [BLE_BOOTLOADER.elf.exe] Error 1
make[1]: *** [CMakeFiles/BLE_BOOTLOADER.elf.dir/all] Error 2
make: *** [all] Error 2

The contents of the bootloader.sct are the same as currently on git hub

Is there a compiler flag I need to set?

Thanks Wayne

29 Jan 2015

Wayne Keenan wrote:

I assume the clock setup in the boot loader also has to be changed?

I changed it in system_nrf51822.c , added some lines in the main of the bootloader, but I cannot get to compile the the new bootlader. I have been trying to change the CMakeList to use arm-gcc instead of armcc (I don't have the license), the cmake works but not the make. I am having some weirds errors about some parameters called in some functions, both from arm-gcc and the Nordic SDK 6.1.0. If somebody manages to compile the bootloader to use it without the external clock, please post it !

30 Jan 2015

The armcc compiler has compiled the sources and for me it's failing at the linking stage; the Keil license limit is 32k and the boot loader shouldn't be more that 16k, so you should be ok, unless I've not gotten far enough to hit a license limit I'm not aware of.

I installed make-3.81 and core utils-5.3.0 (from http://sourceforge.net/projects/gnuwin32/files/) and cmake 3.1.1

For reference my edits to work with armcc where :

CMakelist.txt changes

# decide about the actual compilers to be used ...
set(TOOLCHAIN_SYSROOT c:/Keil_v5/ARM/ARMCC)
set(CMAKE_C_COMPILER   ${TOOLCHAIN_SYSROOT}/bin/armcc.exe)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_SYSROOT}/bin/armcc.exe)

... and ...

SET(CMAKE_CXX_LINK_EXECUTABLE
    "${TOOLCHAIN_SYSROOT}/bin/armlink.exe ...


I also tweaked the 'include_directories' to point to where I happened to put my SDK6.1.0

To run (delete any existing cmake cache file and folder form the Build folder):

Running cmake

set CC=c:\Keil_v5\ARM\ARMCC\bin\armcc
set CXX=c:\Keil_v5\ARM\ARMCC\bin\armcc
cd Build
cmake .. -G "Unix Makefiles"
make

This is the first time I've used Keil from the command line and CMake in anger, and I've followed some other recipes using 'merge hex' elsewhere to assemble a firmware hex file; so being a relative newbie, a cook rather than a chef, in this particular niche I'm a little stuck (or was rather drained at the time) on how to figure out what the linker is complaining about shown in the error in my previous reply; what does it really need? is it is possible in this setup?

I'd be grateful if anymore more experienced could help me understand what srec really wants as input, e.g. are there some additional compiler or linker flags that will give it the symbols it's after ?

All the best Wayne

29 Jan 2015

Wayne Keenan wrote:

unless I've not gotten far enough to hit a license limit I'm not aware of.

just read this: The eval edition linker does not accept scatter-loading description files for sophisticated memory layouts.

oh well.

30 Jan 2015

Wayne Keenan wrote:

I assume the clock setup in the boot loader also has to be changed?

Yes, that would also need changing.

I've setup an issue on Github to track the request for instructions on building the bootloader using armgcc. https://github.com/mbedmicro/BLE_API/issues/27

I'll be away next week; but will look into this shortly upon return.

30 Jan 2015

That would be great, thank you.

19 Feb 2015

If you have a board without a 32k oscillator then you can try my image (with RC_250_PPM_4000MS_CALIBRATION):

https://www.dropbox.com/s/plqqq7uoyiaa9ik/sd_boot.hex?dl=0

It's just a bootloader with 7.1.0 soft device

20 Feb 2015

I managed to build the bootloader using GCC on Windows, I'll get round to publishing my project, but the basic outline of the recipe was roughly:

1. install WIn32 version of GNU 'make' and the 'srec' utilities and the ARM GCC toolchain from https://launchpad.net/gcc-arm-embedded, not to mention the nordic 6.1.0 SDK

2. git clone https://github.com/Rallare/nrf51_bootloader_gcc.git

3. replace the source in that repo with the source from Rohit's bootloader for mbed https://github.com/mbedmicro/dfu-bootloader

4. fix up the makefile to add/remove source files as necessary

5. tweak the linker script: edit: gcc_nrf51_s110_bootloader_xxaa.ld FLASH (rx) : ORIGIN = 0x0003C000, LENGTH = 0x4000

6. Don't forget to tweak any nRF clock settings as required for your platform. (couple of lines)

then in a 'normal' cmd.exe window you should be able to build the bootloader.

'thats' it" As I mentioned, when I get a chance I'll put the actual project online.

All the best Wayne

20 Feb 2015

Lovely. Thanks! Looking forward to your project.

03 Mar 2015

Thanks for a great thread to begin with. I'm very fascinated about the FOTA discussions!

Uploading from iOS & Android is great but what I really want is to be able to upload from my MacOS terminal environment. BlueZ seems to be a Linux (only) framework and I simply wonder if anyone have a approach for MacOS in hidden away on their computer? :)

Best regards, Fredrik

29 Apr 2015

Is there any chance of initial images with single bank DFU boot loader builds being made available?

I'm working on building it myself, but merging the single bank code from Nordic with the mbed modified DFU boot loader code and making it all build using gcc is proving to be non-trivial!

Regards, Stu

29 Apr 2015

Hi,

I would have guessed it would be a matter of replacing the dual-bank module. This is not a priority for us at the moment, but creating alternate bootloaders it is a part of our mid-term roadmap. If you point out specific issues with your effort we may be able to help out partially. Sorry for not offering immediate help.

30 Apr 2015

Hello,

Has anyone successfully built, or is anyone planning on building the DFU-Bootloader for the RedBearLab BLE Nano?

(With FOTA working.)

Thanks, Anton

30 Apr 2015

Rohit Grover wrote:

I would have guessed it would be a matter of replacing the dual-bank module. This is not a priority for us at the moment, but creating alternate bootloaders it is a part of our mid-term roadmap. If you point out specific issues with your effort we may be able to help out partially. Sorry for not offering immediate help.

No problem. It is indeed just that - and I nearly have it working now.

It may actually be more useful to build something based on the dual bank boot loader, but using the whole application space as the 'swap' space, thus still allowing OTA upgrade of soft device and boot loader, but at the expense of having to flash the application again afterwards. This will have to wait until I have the single bank version working...

03 Jun 2015

Hi Rohit,

I am trying to get FOTA working with some of my newer applications using the s130 soft device. The initial images for the likes of the nRF51DK linked to from here seem to be built with the S110 Soft Device.

When I try and build code using a shadow platform that uses the S130 soft device my application will not start up correctly.

Similarly if I try and use the iOS DFU loader to update the Softdevice to S130 directly after installing the default image then the update fails.

Can you provide default initial images using the s130 soft device for the nRF5122 mKit and nRF51DK please?

Thanks,

Allen.

05 Jun 2015

Hi Allen,

Programs compiled for the FOTA shadow platform won't currently work because the older bootloader isn't binary compatible with the latest softdevice. We'll be posting an update for the bootloader and default-app to work with the S130 softdevice. The updated bootloader from Nordic requires an 'init-packet' holding some metadata to describe the target MCU and softdevice; this is done for safety. The init packet also contains a CRC of the image; this means that would need to be generated by the toolchain for every application. We're not sure what the best user experience should be in this case.

We'll resovle this and post an updated bootloader very shortly.

05 Jun 2015

Thanks for your quick replies as always Rohit,

One thing I noticed when looking through the med nRF51822 library is that in nRF51822/nordic-sdk/components/libraries there is a boatloader-dfu directory containing the boot loader code.

I presume the plan for the future is that mbed can build a .hex image that not only contains the soft device and app, but also the boot loader higher in memory? This would be much easier than having to create the initial image manually with srec_cat.

Again, thanks for your reply.

Allen

05 Jun 2015

Allen,

Yes, one of the ideas we're considering is to always combine the bootloader with the FOTA application. We expect to make some decisions about this early next week. I won't be able to provide a useful update before that.

regards,

09 Jun 2015

Hi,

Here's a temporary default-initial-app for FOTA to work with S130/S110 (sdk-v8): default_bootloader_app_s130_tmp.hex

This version of the bootloader works with and without an init packet (metadata). Here's one possible init packet if you wish to use init packet for basic safety. initpacket.dat

This bootloader should work for all nRF platforms: mkit, nRF-DK, Dongle, etc.

This is a stopgap solution. It will permit users to build application using the shadow platform and drive FOTA. We'll integrate the updated bootloader component into our FOTA toolchain very shortly.

Please note that this bootloader currently shifts the device MAC address by 1 (during FOTA mode) in order to get around the problem of FOTA clients with sticky service/characteristic caches. We're not sure if this is the best approach; and we might disable this in future.

The bootloader was built from https://github.com/ARMmbed/dfu-bootloader. It uses https://github.com/mbedmicro/nRF51822/tree/develop.