This exercise is not yet supported in nRF Connect SDK v2.7.0 or v2.8.0. The support is ongoing.
Apologies for any inconvenience.
In this exercise, we will learn how to do DFU over UART . We will first enable Serial Recovery and then add DFU in the application. Both these can be active at the same time. After all, the bootloader does not know anything about the application.
UART0 on our development kits are routed to the debugger chip and exposed to the connected PC as a VCOM port. Therefore, we do not have to connect anything extra to the DK to test DFU over UART.
Exercise prerequisites
To send the firmware updates over UART, we will use the command line tool mcumgr-cli. You can install this using:
go install github.com/apache/mynewt-mcumgr-cli/mcumgr@latest
You might have to install Go to install mcumgr-cli. See https://go.dev/doc/install for how to install Go.
You will need to add mcumgr to path . For Linux , export PATH="$PATH:$HOME/go/bin"
For Windows, you can add it using the Edit System system environment variables
Now we can run mcumgr from the CLI:
Prepare the DK
The DK debugger (Interface MCU)has a virtual mass storage disk. This may interfere with UART DFU transfer since the Interface MCU is also used for UART<> USB conversion, so it is recommended to disable it using the J-link Commander(Windows), or JLinkExe(Linux) :
JLinkExe -device NRF52840_XXAA -if SWD -speed 4000 -autoconnect 1 -SelectEmuBySN SEGGER_ID
J-Link>MSDDisable
Probe configured successfully.
J-Link>exit
The Development Kit must then be power-cycled for the settings to take effect. Replace SEGGER_ID with the SEGGER ID of your DK. The SEGGER ID is for the on-board debugger on the DK. Each DK has its unique SEGGER ID. The SEGGER ID is displayed in the Connected Devices View in nRF Connect for VS Code, as shown in the screenshot below. It’s also printed on the kit label.
Note that this setting remains valid even if you program another firmware onto the device.
For this exercise, The base code is simply a copy of the Blinky sample. The goal here is to show you how to add MCUboot to an existing nRF Connect SDK application.
Open the code base of the exercise by navigating to Create a new application in the nRF Connect for VS Code extension, select Copy a sample, and search for Lesson 8 – Exercise 1.
Alternatively, in the GitHub repository for this course, go to the base code for this exercise, found in l8/l8_e1
.
1. Enable MCUboot in prj.conf
CONFIG_BOOTLOADER_MCUBOOT=y
Kconfig2. Enable logging for MCUboot
2.1 Create a child_image directory to configure child images.
2.2 Create a file to configure MCUboot in the child image folder and add the following comments inside mcuboot.conf
# STEP 2.3 - Enable logging for MCUboot
# STEP 3.1 - Enable Serial Recovery over UART
# STEP 3.2 - Disable UART, since Serial Recovery uses it
# STEP 3.3 - Configure boolader to use only one slot.
# STEP 5.1 - Go back to two slots, as we need two for DFU from the app
# STEP 3.4 - Turn on a LED so we can see when Serial Recovery mode is active
KconfigThe folder structure should now look like this:
2.3 Next, we will enable logging for MCUboot. For this, we both need to enable logs and set the log level:
CONFIG_LOG=y
CONFIG_MCUBOOT_LOG_LEVEL_INF=y
KconfigAfter this, we can build and run the sample to see it run with MCUboot. Observe logs from nRF Serial Terminal:
*** Booting nRF Connect SDK 2.6.1-3758bcbfa5cd ***
I: Starting bootloader
I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
I: Boot source: none
I: Image index: 0, Swap type: none
I: Bootloader chainload address offset: 0xc000
TerminalWe can also see the partitioning of the device, with the nRF Connect for VS Code Memory Report
Now, we have MCUboot running before the application. However, we can not yet update the application.
3. Add DFU over UART to MCUboot
Next, we will add DFU over UART to MCUboot, also known as Serial Recovery. MCUboot configuration options can be found here, and MCUboot Kconfig options specific for Serial Recovery are found here .
3.1 To enable Serial Recovery, we must set CONFIG_MCUBOOT_SERIAL
and to enable transport over UART, we must set BOOT_SERIAL_UART
. Since these are both for the MCUboot child image, we must set them in mcuboot.conf
.
CONFIG_MCUBOOT_SERIAL=y
CONFIG_BOOT_SERIAL_UART=y
Kconfig3.2 Since we now use UART for Serial Recovery, we must disable UART from the console from MCUboot, so this does not try to use the UART at the same time.
CONFIG_UART_CONSOLE=n
Kconfig3.3 By default, MCUboot splits the non-volatile memory into two slots. Since we use Serial Recovery, we can use only one slot instead to get more available non-volatile memory. We can do this by setting CONFIG_SINGLE_APPLICATION_SLOT
.
CONFIG_SINGLE_APPLICATION_SLOT=y
Kconfig3.4. To indicate that MCUboot is in Serial Recovery mode, it is nice to have an indicator LED. We can enable this by setting CONFIG_MCUBOOT_INDICATION_LED
.
CONFIG_MCUBOOT_INDICATION_LED=y
Kconfig3.5 we will set which button and LED will be used before testing. This is set using a Devicetree overlay. For this, we will create the file child_image/mcuboot.overlay
. Now, the folder structure will then look like this:
Add the following comment to mcuboot.overlay
:
/* Step 3.5 - Configure button and LED for Serial Recovery */
DevicetreeUnder it, add
/ {
aliases {
mcuboot-button0 = &button1;
mcuboot-led0 = &led1;
};
};
DevicetreeNote that the alias button1
represents the physical Button 2 on the DK. led1
alias represents the physical LED2 on the DK. Aliases and node identifiers in devicetree start from 0, while on the physical board, they start from 1.
4. Build and flash the application to your board.
Now we can test Serial Recovery. When you start the kit normally, you see LED1 blink as normal.
4.1 Now, hold button 2 while resetting the Development Kit. Instead of starting normally, the kit will now enter Serial Recovery mode. You can see this from LED2, which should be on.
4.2 While in serial recovery mode, we can use mcumgr-cli
to communicate with the DK. First, we will add a configuration to mcumgr-cli
:
Linux/OSX:
mcumgr conn add testDK type="serial" connstring="dev=/dev/ttyACM0,baud=115200,mtu=512"
Windows:
mcumgr conn add testDK type="serial" connstring="COM14,baud=115200,mtu=512"
Note that the port number will vary from machine to machine and DK to DK. Use the Connected Devices view in nRF Connect for VS Code to know the port of your DK.
testDK
in the command above can be named whatever we want. A list of supported mcumgr-cli commands can be found here.
4.3 With this configuration, we can test listing current images on the DK:
mcumgr -c testDK image list
This should return the following:
Images:
image=0 slot=0
version: 0.0.0
bootable: false
flags:
hash: 59947af60569a6512f303d69047cc875efd662c5834a4990f640b96e9923ef0e
Split status: N/A (0)
TerminalIf you see an error like Error: Access is denied
. it means there is an application on your machine that is using that same port. Close all applications that use that port to eliminate this error message.
4.4 Before we try to upload a new firmware image to the DK, we should change something in the application, so we can verify that the new firmware image has been flashed. This can, for example be to change the delay in the blinky code. For example, change SLEEP_TIME_MS
from 1000 to 100, then rebuild the code.
4.5 Now we can upload the new image firmware to the DK, using:
mcumgr -c testDK image upload build/zephyr/app_update.bin
Then this should be the result:
6.93 KiB / 42.01 KiB [====================>-------------------------------------------------------------------------------------------------------] 16.50% 3.14 KiB/s 00m11s
Terminal4.6 After the successful upload, reset the DK to see the new image in effect:
mcumgr -c testDK reset
DFU over UART from the application
5. Add DFU over UART to the application.
Next up, we will add DFU over UART to the application. This method uses the mcumgr library.
5.1 First, we must go back to dual slots, as DFU from the application must have two slots:
CONFIG_SINGLE_APPLICATION_SLOT=n
Kconfig5.2 Then we add mcumgr configurations and dependencies to prj.conf
. We can take inspiration from the SMP Server sample to find which configurations we need. For this exercise, we can use the following:
# Step 5.2 - Enable mcumgr DFU in application
# Enable MCUMGR
CONFIG_MCUMGR=y
# Enable MCUMGR management for both OS and Images
CONFIG_MCUMGR_GRP_OS=y
CONFIG_MCUMGR_GRP_IMG=y
# Configure MCUMGR transport to UART
CONFIG_MCUMGR_TRANSPORT_UART=y
# Dependencies
# Configure dependencies for CONFIG_MCUMGR
CONFIG_NET_BUF=y
CONFIG_ZCBOR=y
CONFIG_CRC=y
# Configure dependencies for CONFIG_MCUMGR_GRP_IMG
CONFIG_FLASH=y
CONFIG_IMG_MANAGER=y
# Configure dependencies for CONFIG_IMG_MANAGER
CONFIG_STREAM_FLASH=y
CONFIG_FLASH_MAP=y
# Configure dependencies for CONFIG_MCUMGR_TRANSPORT_UART
CONFIG_BASE64=y
Kconfig5.3 With this, we can do DFU over UART without entering bootloader mode.
Build, flash and start the DK normally (do not hold any buttons). During operations, we can use the mcumgr-cli
to list images, as before:
mcumgr -c testDK image list
Then we change the application code again, build the code and upload the new firmware image:
mcumgr -c testDK image upload build/zephyr/app_update.bin
5.4 Since we now use a dual slot configuration, the uploaded application does not automatically run. We can reset the DK now without any change. To make the application swap into primary slot, we must tag it with either “test” or “confirm”. Let’s do “test” first. First, we need to get the hash of the image:
mcumgr -c testDK image list
Will return:
Images:
image=0 slot=0
version: 0.0.0
bootable: true
flags: active confirmed
hash: <OLD_HASH>
image=0 slot=1
version: 0.0.0
bootable: true
flags:
hash: <NEW_HASH>
Split status: N/A (0)
TerminalThen we use the <HASH> to tag that slot as test
, and reset:
mcumgr -c testDK image test <NEW_HASH>
mcumgr -c testDK reset
The image will be swapped into secondary slot. We can check this with:
mcumgr -c testDK image list
Which should return:
Images:
image=0 slot=0
version: 0.0.0
bootable: true
flags: active
hash: <NEW_HASH>
image=0 slot=1
version: 0.0.0
bootable: true
flags: confirmed
hash: <OLD_HASH>
Split status: N/A (0)
TerminalAnd if we reset the board, again, we can in the same way see that the image swaps back to the old firmware. This is because we passed test
not confirm
to mcumgr
To restore the default DK debugger (Interface MCU) behavior with a virtual mass storage disk enabled, use the following J-Link command: MSDEnable
. This command can be executed via J-Link Commander (on Windows) or JLinkExe (on Linux).
The application core of the nRF5340 can be updated, as explained above.
When doing DFU from the application, no extra configurations are needed to update the network core. Another DFU package file must be used for the network core. Instead of app_update.bin
, use net_core_app_update.bin
.
However, for Serial Recovery, some extra configurations are needed to update the network core. The needed configurations are listed in our docs on Developing with nRF5340 DK: MCUboot’s serial recovery of the networking core image.