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.
DFU Bootloader
Overview of Components
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.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 address0x10001014
, 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:
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.