Add DFU support to your application

Add DFU support to your application

This guide will show you, step by step, how to add Device Firmware Update (DFU) support to your application using the nRF Connect SDK. First it will demonstrate how to add BLE DFU support to the Peripheral LBS sample and how to perform a DFU using the nRF Connect Device Manager app. The next section will show you how to add Serial DFU support to the Hello World sample and how to perform a DFU from a computer using mcumgr. The code snippets used in this guide are inspired by the SMP Server sample.

Check out the source code for the mcumgr management library for more information about the library and the underlying protocols. It contains a README explaining mcumgr and a README explaining the Simple Management Protocol (SMP).

Before starting, make sure you have installed the nRF Connect SDK and are familiar with nRF Connect for VS code. Check out the nRF Connect for VS Code series on YouTube for help with this. The west command is used to build and flash the samples, but if you're not familiar with the command line, you can build and flash the sample using nRF Connect for VS Code instead.

The samples in this guide are tested with nRF Connect SDK v1.8.0-rc1 and the nRF52840 DK

Table of contents:

DFU over Bluetooth

Modify the Peripheral LBS sample

In the above image, Linux is used. If you're using Windows, make sure the nRF Connect Toolchain points to the folder <ncs location>/<ncs version>/toolchain

  • First, add the following lines to ble_dfu_peripheral_lbs/prj.conf

# Enable mcumgr.
CONFIG_MCUMGR=y

# Enable most core commands.
CONFIG_MCUMGR_CMD_IMG_MGMT=y
CONFIG_MCUMGR_CMD_OS_MGMT=y

# Ensure an MCUboot-compatible binary is generated.
CONFIG_BOOTLOADER_MCUBOOT=y

The first config (MCUMGR) will enable the mcumgr management library and the next two (MCUMGR_CMD_IMG_MGMT and MCU_MGR_CMD_OS_MGMT) enables the command handlers for image management and OS management. The image management command handlers makes it possible to uploadlisttest and confirm the image(s), while the OS management command handlers makes it possible to reset the chip (and run the echo command). Since the DFU support is added to the application, the chip needs to be reset, to give control to MCUboot, which will validate the new uploaded image and swap it with the old image. Finally, BOOTLOADER_MCUBOOT includes MCUboot as a child image.

  • Add the following lines to ble_dfu_peripheral_lbs/prj.conf as well

# Allow for large Bluetooth data packets.
CONFIG_BT_L2CAP_TX_MTU=252
CONFIG_BT_BUF_ACL_RX_SIZE=256

# Enable the Bluetooth (unauthenticated) and shell mcumgr transports.
CONFIG_MCUMGR_SMP_BT=y
CONFIG_MCUMGR_SMP_BT_AUTHEN=n

# Some command handlers require a large stack.
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096

First we increase the L2CAP MTU (BT_L2CAP_TX_MTU) and the ACL size (BT_BUF_ACL_RX_SIZE) in order to be able to upload the binary. Next, the Bluetooth mcumgr SMP transport (MCUMGR_SMP_BT) is enabled and the need for an encrypted and authenticated connection to send messages over the BLE SMP transport layer (MCUMGR_SMP_BT_AUTHEN) is disabled (remember to change this value if your application has higher security requirements). The work queue stack size is increased to avoid stack overflow.

  • Add the lines below to the top of ble_dfu_peripheral_lbs/src/main.c

#include <mgmt/mcumgr/smp_bt.h>
#include "os_mgmt/os_mgmt.h"
#include "img_mgmt/img_mgmt.h"

  • Remove the LBS Service UUID from the scan response packet, and replace it with the SMP service UUID:

BT_DATA_BYTES(BT_DATA_UUID128_ALL,
		      0x84, 0xaa, 0x60, 0x74, 0x52, 0x8a, 0x8b, 0x86,
		      0xd3, 0x4c, 0xb7, 0x1d, 0x1d, 0xdc, 0x53, 0x8d),

The reason this was done, is to make the advertising visible for the nRF Connect Device Manager app. The app will filter out all the devices that doesn't advertise with the SMP service UUID.

printk("build time: " __DATE__ " " __TIME__ "\n");
os_mgmt_register_group();
img_mgmt_register_group();
smp_bt_register();

Here we register the OS and Image group as well as the SMP Bluetooth service. A printk with the build date and time is added to make it easier to confirm that an update was successful.

If you've followed the above steps correctly, the sample should look like this: https://github.com/simon-iversen/sdk-nrf/tree/ble_dfu_peripheral_lbs/samples/bluetooth/peripheral_lbs 

Testing

  • Connect your board to the computer, then build the modified peripheral_lbs sample and flash it to the board
west build -b nrf52840dk_nrf52840 -p && west flash --erase

  • Open a serial terminal, reset the chip and check the date and time that is output. 

For example:

...
*** Booting Zephyr OS build v2.7.0-ncs1-rc1 ***
Starting Bluetooth Peripheral LBS example
build time: Nov 30 2021 17:14:25
...

  • Build the sample again, to create the file used for the DFU update
west build -b nrf52840dk_nrf52840 -p

Due to the printk statement with the build date and time, a new and different binary will be created

  • Transfer the generated file peripheral_lbs/build/zephyr/app_update.bin to your phone
  • Install the nRF Connect Device Manager app on your phone
  • If you open the app, the advertisement from the peripheral LBS sample should be found. Click on it

  • Next, click on the download button, then "SELECT FILE" and find the app_update.bin file you just transferred to the phone

  • Click on "START", then select "Test and Confirm" and start the firmware update

       

The app will then transfer the image binary, and "UPLOAD COMPLETE" should be displayed when the whole binary is uploaded

       

The nRF Connect Device Manager app will reset the chip after the transfer is completed. If the date and time output on the terminal is different from the one seen earlier, it means a different image is running and the update was successful

For example:

...
*** Booting Zephyr OS build v2.7.0-ncs1-rc1 ***
Starting Bluetooth Peripheral LBS example
build time: Nov 30 2021 17:18:53
...

The new image will get confirmed from the app, so it should not revert back on the next reset.

Serial DFU

Modify the Hello World sample

In the above image, Linux is used. If you're using Windows, make sure the nRF Connect Toolchain points to the folder <ncs location>/<ncs version>/toolchain

  • Start by adding these lines to serial_dfu_hello_world/prj.conf

# Enable mcumgr.
CONFIG_MCUMGR=y

# Enable most core commands.
CONFIG_MCUMGR_CMD_IMG_MGMT=y
CONFIG_MCUMGR_CMD_OS_MGMT=y

# Ensure an MCUboot-compatible binary is generated.
CONFIG_BOOTLOADER_MCUBOOT=y

Check out Modify the Peripheral LBS sample for an explanations of these configs

  • Add these lines to serial_dfu_hello_world/prj.conf as well:

# Enable the serial mcumgr transport.
CONFIG_MCUMGR_SMP_UART=y

# Disable UART Console and enable the RTT console
CONFIG_UART_CONSOLE=n
CONFIG_RTT_CONSOLE=y
CONFIG_USE_SEGGER_RTT=y

# Some command handlers require a large stack.
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096

We start by enabling the serial mcumgr SMP transport (MCUMGR_SMP_UART). Next, we use RTT for logging instead of UART, so that it doesn't interfere with the transfer (see Nordic nRF5x Segger J-Link -> RTT Console). Another option is to use the configs from smp_svr/overlay-serial-console.config to enable the UART console with mcumgr pass through. The work queue stack size is increased to avoid a stack overflow (SYSTEM_WORKQUEUE_STACK_SIZDE).

  • At the top of hello_world/src/main.c. add these include statements

#include "os_mgmt/os_mgmt.h"
#include "img_mgmt/img_mgmt.h"

  • Like we did for the Bluetooth DFU add the lines shown below. Put them in the start of the main function, 

printk("build time: " __DATE__ " " __TIME__ "\n");
os_mgmt_register_group();
img_mgmt_register_group();

We don't need to run any functions related to the SMP serial transport. This is because smp_uart_init() will run before main and set up an UART mcumgr ISR that handles the incoming mcumgr messages.

If you've followed the above steps correctly, the sample should look like this: https://github.com/simon-iversen/sdk-zephyr/tree/serial_dfu_hello_world/samples/hello_world 

Testing

Before testing the sample, make sure mass storage is disabled. If not the upload command might stall at 0%

west build -b nrf52840dk_nrf52840 -p && west flash --erase
  • Disconnect and connect the micro USB

Use the USB connector connected to the Interface MCU, not the USB connector connected to the USB peripheral. This is because UART 0 is used for mcumgr UART, which is by default connected to the Interface MCU for the nRF52840 DK in nRF Connect SDK.

For example:

*** Booting Zephyr OS build v2.7.0-ncs1-rc1 ***
Hello World! nrf52840dk_nrf52840
build time: Nov 30 2021 17:39:13
  • Build the sample again, to create the file used for the DFU update 
west build -b nrf52840dk_nrf52840 -p
  • Install mcumgr by following the instructions in the section MCUmgr -> Command-line Tool, and add it to the path
  • Get the development kit’s serial port name (for example, "/dev/ttyACM0"), by running nrfjprog --com
../home$ nrfjprog --com
683416774 /dev/ttyACM0 VCOM0
  • Open the command line and run the following command
mcumgr --conntype serial --connstring "/dev/ttyACM0,baud=115200" echo hello

The string "hello" should be returned, if not the communication is not working properly

  • Open a terminal in ../zephyr/samples/hello_world/build/zephyr (where the signed binary app_update.bin is located) and type in the following command to start the upload
mcumgr --conntype serial --connstring "/dev/ttyACM0,baud=115200" image upload -e app_update.bin
  • When the transfer has completed run the following command:
mcumgr --conntype serial --connstring "/dev/ttyACM0,baud=115200" image list

This will list all the images located on the chip, and if the upload has been successful, you should see an image at slot 1, similar to below:

Images: 
image=0 slot=0
version: 0.0.0
bootable: true
flags: active confirmed
hash: f8ebf4778aa17de10c24ea1a8fd7b3877672a934448d5193b89a0a60c37699cd
image=0 slot=1
version: 0.0.0
bootable: true flags:
hash: 31cc459b1ec1ac8e19f092caa860db8e377a7ab66234012bdb6a1dd522807269
Split status: N/A (0)

In order for mcuboot to swap the images on reset, the flag of the image in slot-1 has to be "pending". This can be done by running the mcumgr test command, with the hash of slot-1 image. For example:

mcumgr --conntype serial --connstring "/dev/ttyACM0,baud=115200" image test 31cc459b1ec1ac8e19f092caa860db8e377a7ab66234012bdb6a1dd522807269

The image in slot-1 should now be in a "pending" state

  • For the swap to start, the chip needs to reset. This can be done remotely through mcumgr:
mcumgr --conntype serial --connstring "/dev/ttyACM0,baud=115200" reset
  • Check the log output, and if the date and time output is different from the one seen earlier, the update was successful

For example:

*** Booting Zephyr OS build v2.7.0-ncs1-rc1 ***
Hello World! nrf52840dk_nrf52840
build time: Nov 30 2021 17:42:56
  • To make the swap permanent, run the confirm command
mcumgr --conntype serial --connstring "/dev/ttyACM0,baud=115200" image confirm

Other DFU samples

Serial DFU using external flash

This sample is similar to the one in Serial DFU, just that the secondary slot is located at the nRF52840 DK's onboard flash instead of the internal flash

https://github.com/simon-iversen/sdk-zephyr/tree/serial_dfu_ext_flash_hello_world/samples/hello_world

Anonymous
Parents
  • Hi,
    I tried the Serial DFU sample with NRF9160-DK board in Windows enviroment.

    The project build and run.

    When I use mcumgr the command work but was non possible to me upload a new image.

    The mcumgr echo work:

    C:\FW\DFU_hello_world\build_nrf9160dk_nrf9160_ns\zephyr>mcumgr --conntype serial --connstring "com13,baud=115200" echo hello
    hello

    The mcumgr image list work:

    C:\FW\DFU_hello_world\build_nrf9160dk_nrf9160_ns\zephyr>mcumgr --conntype serial --connstring "com13,baud=115200" image list
    Images:
    image=0 slot=0
    version: 0.0.0
    bootable: true
    flags: active confirmed
    hash: ed709b43573bd8ab480672e00fb40dfa4d93da3e4aa849bc194a6e2c3a35f2a9
    Split status: N/A (0)

    The mcumgr image upload stall at 0%:

    C:\FW\DFU_hello_world\build_nrf9160dk_nrf9160_ns\zephyr>mcumgr --conntype serial --connstring "com13,baud=115200" image upload -e app_update.bin
    0 B / 109.28 KiB [------------------------------------------------------------------------------------------] 0.00%

    Any suggestion?

  • Could you create a DevZone ticket and ask the question there?

  • Ok, I opened a new ticket.

    Maurizio

Comment Children
No Data