Skip to content

Zephyr RTOS Bootloader

Introduction

Zephyr RTOS Bootloader

In this Codelab, you will first learn the basic principles of integrating a bootloader application in Zephyr RTOS. You will then learn how to download and install new applications securely.

What you’ll build

  • You will integrate the MCUboot bootloader application into your Zephyr RTOS application.
  • You will then implement a download mechanism for storing a new application and installing it.

What you’ll learn

  • You will learn the basic principles of bootloaders and their implications for Zephyr RTOS program images.
  • You will also understand how the boot sequence is modified to start an application with a bootloader.

What you’ll need

The Bootloader Principle

A bootloader is a type of application that allows system or application software to be updated without the use of specialised hardware, such as a JTAG programmer (or other programmers for different MCUs). The bootloader manages and installs system or application images. In specific cases, it may also download them. Throughout the rest of this document, we will often refer to the system or application image as ‘firmware’. We will also refer to the process of downloading and installing new firmware as ‘DFU’.

DFUs/bootloaders can communicate using a variety of protocols to download firmware and save it to the non-volatile memory of the embedded system. These protocols can be UART, Ethernet, USB or a wireless protocol for systems with wireless connectivity. As well as downloading new firmware, DFUs/Bootloaders are responsible for verifying its integrity and authenticity.

Usually, systems with bootloaders have at least two firmware images coexisting on the non volatile memory of the MCU. They must also include code for branching installation of a new firmware image.

It is very common that the need for a bootloader mechanism is overlooked when conceiving embedded system software, because the bootloader is not the end product. However, the bootloader is an essential component of an embedded system. It allows to launch a system with software that only fulfills a subset of the final requirements and to add features to the product once it has already been launched to the market. And, even more importantly, it also allows the developers to fix bugs that are discovered over the lifetime of the product and to deploy corrections.

Writing a bootloader application requires an understanding of how a program image is built and how the MCU uses this memory. In this codelab, we will develop a simple bootloader and explain all components required for its development.

The Zephyr RTOS Memory Model

From the lecture notes, recall that the Zephyr RTOS/MCUboot memory model is as depicted in the figure below:

_Zephyr RTOS_/MCUboot Memory Model

Zephyr RTOS/MCUboot Memory Model

It is important to note that this is not the only applicable model, and that other memory models are also possible (for instance, where the bootloader is not located before the application in ROM). However, on Cortex-M MCUs, the MCU expects the application to start by reading the SP and PC at the start of the ROM. Therefore, locating the immutable bootloader at the start of the ROM is not really an option.

Boot sequences

In general, a boot sequence can comprise several stages before reaching the application. These stages include several bootloader stages and the application itself. Except for the immutable bootloader, all stages can evolve over time and be upgraded to add new features and correct bugs. Upgrades are possible for boot sequences with two or more stages: any active stage can replace the next stage in the sequence, meaning that when the system restarts, the updated components (including the updated application) will be executed. The very first stage is usually immutable because it takes control on startup, so a faulty upgrade could be very difficult to recover from.

Usually, for protecting against faults in a newly updated component, multiple versions of each stage are stored in the non volatile memory. Each stage is responsible for detecting faults in the next stage and for rolling back if a fault is discovered.

Our simple implementation

In this codelab, we will implement different options for a simple two-stage boot sequence: a bootloader that won’t be upgraded and an application that will be upgraded. Most boot sequences usually comprise at least three stages: a root bootloader or boot selector that is not upgraded, and two upgradable stages (bootloader and application) with multiple versions stored on the device. In our implementation, the bootloader acts as both a boot selector and a bootloader, capable of installing new images.

Compile and Install the MCUboot Bootloader Application

Integrating multiple applications using sysbuild

The integration of the MCUboot bootloader with a Zephyr RTOS application is often achieved using the Zephyr RTOS sysbuild higher-level build system. This system enables multiple builds to be combined and multiple applications to be flashed or debugged simultaneously. For the sake of simplicity, we will build and flash the MCUboot bootloader and the BikeComputer program as two separate applications.

Import MCUboot into Your Workspace

The following steps explain how to import MCUboot into your Zephyr RTOS workspace:

  • Add the following to your west.yml file:
    manifest-repo/west.yml
        ...
          import:
            path-prefix: deps
            file: west.yml # not strictly needed since it is the value by default
            name-allowlist:
              ...
              - mcuboot
              - mbedtls
              ...
    
  • Run west update.
  • Check that the MCUboot bootloader is available in the “deps/bootloader” folder.

Build the MCUboot Application

MCUboot not fully compatible with Zephyr RTOS v4.2.1

Unfortunately, at this time, MCUboot is not fully compatible with Zephyr RTOS v4.2.1. Changes in the “mbedtls” module require to patch the MCUboot distribution as documented below.

The following steps are required to build and flash the Zephyr RTOS MCUboot bootloader application:

  • Add the file “Kconfig.mbedtls_fragment” with the following content in the “deps/bootloader/mcuboot/boot/zephyr/” folder:
Kconfig.mbedtls_fragment
deps/bootloader/mcuboot/boot/zephyr/Kconfig.mbedtls_fragment
# Kconfig fragment: Kconfig.mbedtls_fragment
#
# This fragment tries to enable Zephyr's mbedTLS module and the minimal
# symbols MCUboot needs. If your environment overrides some symbols,
# adjust as needed.

config MBEDTLS_FORCE_ENABLE
    bool "Force-enable mbedTLS minimal config for MCUboot"
    default y

if MBEDTLS_FORCE_ENABLE

config MBEDTLS
    bool "Mbed TLS library"
    default y
help
  Enable mbed TLS module support.

config MBEDTLS_CFG_FILE
    string "mbed TLS config header"
    default "config-mbedtls.h"

# Minimal components needed by MCUboot for ECDSA/RSA
config MBEDTLS_SHA256_C
    bool "mbed TLS SHA-256"
    default y

config MBEDTLS_ECP_C
    bool "mbed TLS ECC primitives"
    default y

config MBEDTLS_ECDSA_C
    bool "mbed TLS ECDSA"
    default y

config MBEDTLS_BIGNUM_C
    bool "mbed TLS bignum"
    default y

config MBEDTLS_PK_C
    bool "mbed TLS pk abstraction"
    default y

config MBEDTLS_PK_PARSE_C
    bool "mbed TLS pk parse"
    default y

config MBEDTLS_PK_WRITE_C
    bool "mbed TLS pk write"
    default y

endif # MBEDTLS_FORCE_ENABLE
  • Source this file in the “deps/bootloader/mcuboot/boot/zephyr/Kconfig” file by adding rsource "Kconfig.mbedtls_fragment" right before mainmenu "MCUboot configuration"

  • Create a “prj_bootloader.conf” file at the root of your workspace. This configuration file will be used to build the MCUboot bootloader application. Some changes are required for a proper MbedTLS configuration and the following content must be added:

    {workspace}/prj_bootloader.conf
    # Base mbedtls
    CONFIG_MBEDTLS=y
    CONFIG_MBEDTLS_CFG_FILE="config-mbedtls.h"
    
    # Required curve for MCUboot ECDSA-P256
    CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
    

  • Modify the “deps/bootloader/mcuboot/boot/zephyr/CMakeLists.txt” file by replacing
    if(DEFINED CONFIG_MBEDTLS)
    zephyr_library_include_directories(
      ${ZEPHYR_MBEDTLS_MODULE_DIR}/include
    )
    endif()
    
    with
    if(DEFINED CONFIG_MBEDTLS)
    zephyr_library_include_directories(
      ${ZEPHYR_BASE}/../modules/crypto/mbedtls/include
    )
    endif()
    
    For this change, make sure that you defined the environment variable ZEPHYR_BASE correctly.
  • Build the MCUboot bootloader application as a standard Zephyr RTOS application, running west build deps/bootloader/mcuboot/boot/zephyr --pristine --extra-conf "full path to prj_bootloader.conf". You will see a warning saying “Using default MCUboot signing key file, this file is for debug use only and is not secure!”. This is not an issue at this point.

  • Flash the application. The following output should appear on a serial monitor:

    *** Booting MCUboot v2.2.0-54-g4eba8087fa60 ***
    *** Using Zephyr OS build v4.2.1 ***
    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
    W: Failed reading image headers; Image=0
    E: Image in the primary slot is not valid!
    E: Unable to find bootable image
    

The bootloader is running correctly at this point, but, as expected, it cannot find a bootable image.

Modify Your BikeComputer Application To Integrate a Bootloader

To enable the BikeComputer to run from the bootloader application, you must add some configuration parameters to the BikeComputer program as follows:

  • Create a file named “prj_dfu.conf” in the “bike_computer” folder and add the configuration parameters as described below.

  • Modify the build so that the image is chain-loaded by MCUboot:

    bike_computer/prj_dfu.conf
    CONFIG_BOOTLOADER_MCUBOOT=y
    

  • Instruct west build to sign the image with the appropriate default key file:

    bike_computer/prj_dfu.conf
    CONFIG_MCUBOOT_SIGNATURE_KEY_FILE="{workspace_folder}/deps/bootloader/mcuboot/root-rsa-2048.pem"
    
    At this stage, the default MCUboot signing key file is used.

  • Add versioning for signing the image:

    bike_computer/prj_dfu.conf
    CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="1.0.0+0"
    

Once you have modified the prj.conf file, you can build the BikeComputer program by adding --extra-conf "full path to prj_dfu.conf" to the build command. After flashing the BikeComputer program, the bootloader should now jump to the first image slot at startup and the BikeComputer program should start up as normal.

Signing the BikeComputer Program and Provide the Key to the Bootloader application

An important aspect of the image update process is that images uploaded to the device must be signed. If this is not the case, and if the MCUboot is configured to verify the image, the MCUboot application will reject the candidate images, as it needs to verify their authenticity. To this end, the bootloader must embed the key used to sign the application.

In the previous steps, the MCUboot application was instructed to use the default key and the BikeComputer program was signed with this key. However, each program should use its own generated key.

The MCUboot project comes with the “bootloader/mcuboot/scripts/imgutil.py” script, which allows you to, among other things, generate a pair of keys, extract the public key, and generate the “.c” file containing the public key that will be integrated into the bootloader program. It is therefore necessary to:

  • First install the dependencies listed in “deps/bootloader/mcuboot/scripts/ requirements.txt” using the command pip install -r requirements.txt.

  • Then generate a key pair using python deps/bootloader/mcuboot/scripts/imgtool.py keygen -k mykey.pem -t rsa-2048. The file “mykey.pem” contains the key pair that will be used for signing the application.

Once the key has been generated, you must instruct the MCUboot application to embed it and sign the BikeComputer program with it. This can be done as follows:

  • Modify the “prj_bootloader.conf” configuration file by adding:
    {workspace}/prj_bootloader.conf
    CONFIG_BOOT_SIGNATURE_KEY_FILE="full path to private_key_rsa-2048.pem"
    
  • Build the MCUboot application and flash it. The BikeComputer program installed in the primary slot should now be detected as invalid!

  • Modify the BikeComputer prj.conf configuration file by changing the path to the key file. Build and flash the application. It should then be recognized as valid again and it should start up normally.

The MCUboot and BikeComputer program are now ready to receive updates. The next sections will cover two different methods of updating a Zephyr RTOS program.

Update the BikeComputer Program using Serial Recovery

One way to update a Zephyr RTOS program is to download the software update from the bootloader itself, as shown in the diagram below:

DFU from the Bootloader

DFU from the Bootloader

(source: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-9-bootloaders-and-dfu-fota/topic/device-firmware-update-dfu-essentials/)

To implement this solution, the download will be executed from the bootloader application via UART. The setup is shown below:

DFU from the Bootloader Setup

DFU from the Bootloader Setup

(source: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-9-bootloaders-and-dfu-fota/topic/exercise-1-dfu-over-uart/)

The application itself does not require any changes, but the bootloader application does. These changes are implemented by using another prj.conf file for the MCUboot application:

  • First copy the existing “prj_bootloader.conf” file created in the previous step and rename it “prj_serial_recovery.conf”. Then, apply the following changes.

  • Enable Serial Recovery over UART:

    {workspace}/prj_serial_recovery.conf
    CONFIG_MCUBOOT_SERIAL=y
    CONFIG_BOOT_SERIAL_UART=y 
    

  • Disable console UART, since Serial Recovery uses UART:

    {workspace}/prj_serial_recovery.conf
    CONFIG_UART_CONSOLE=n
    

  • Since with this configuration, the application is updated in place, only one slot is required to store the application. Configure the bootloader to use a single slot:

    {workspace}/prj_serial_recovery.conf
    CONFIG_SINGLE_APPLICATION_SLOT=y
    

  • Configure LED indication when Serial Recovery mode is active:

    {workspace}/prj_serial_recovery.conf
    CONFIG_MCUBOOT_INDICATION_LED=y
    

Before building the MCUboot application, you need to add the zcbor dependency to the west.yml file (right below the mbedtls dependency) and run west update. You can then build the MCUboot application using west build deps/bootloader/mcuboot/boot/zephyr --pristine --extra-conf "full path to prj_serial_recovery.conf" It should start and execute as before. As the board is configured for the use of the MCUboot application in Serial Recovery mode, it is ready for testing.

Upload a Firmware Update

We use a desktop tool called AuTerm to send firmware updates via UART. Other tools can also be used, and alternative tools are presented here.

Read the instructions for downloading and installing the AuTerm tool. Once ready, launch AuTerm and follow the instructions below to update your BikeComputer program using Serial Recovery:

  • Reset the board while pressing Button1. It should restart but instead of jumping to the BikeComputer program, it should wait for an update to be receive. LED1 should turn on.
  • Close any open UART connections to the board.
  • In AuTerm, configure the COM port to use under the “Config” tab and press “Open”. The connection should be established.
  • In AuTerm, select the “MCUmgr” tab. Under “Images”, select “Get” and press “Go”. You should see that the board is configured with one slot (“Slot 0”).
  • Modify your “BikeComputer” program so that a difference in logging appears at application start. Build the program without flashing it.
  • In AuTerm, select the “MCUmgr” tab. Under “Upload”, select the “build/zephyr/zephyr.signed.bin” file, check the “Reset after upload” box and press “Go” to start the upload. Upload should start and after it is finished, the board should reset and start again.
  • In AuTerm, select the “Terminal” tab. You should see that your updated program has been successfully installed and started on the board.

Intermediate Wrap-up

Before moving to the next section, make sure that you have accomplished the following:

  • You have modified the MCUboot application configuration, built and flashed it. Upon reset, the board launches the MCUboot application and successfully jumps to the BikeComputer program
  • You have understood how the memory model of your board has been modified to use a MCUboot bootloader application.
  • You have performed a firmware update download using Serial Recovery successfully and observed that the updated BikeComputer program launches successfully.

Update the BikeComputer Program over UART from the Application

In the previous section, we implemented a software update using Serial Recovery by utilising DFU over UART with the onboard UART-to-USB converter available on the development kit. However, incorporating a UART-to-USB converter into an embedded system is not usually practical, as this increases the bill of materials, power consumption, and complexity.

In this section, we implement a different mechanism that does not require an onboard UART-to-USB converter but rather makes uses of the USB MCU interface. This setup is illustrated in the diagram below:

DFU from the Application Setup

DFU from the Application Setup

(source: https://academy.nordicsemi.com/courses/nrf-connect-sdk-intermediate/lessons/lesson-9-bootloaders-and-dfu-fota/topic/exercise-4-dfu-over-usb/)

Using this mechanism with a SoC that comes with a built-in USB peripheral eliminates the need for additional hardware, thus reducing the cost and complexity of a system that uses wired DFU.

In order to implement this mechanism, you will first need to build and flash the MCUboot bootloader application using west build deps/bootloader/mcuboot/boot/zephyr –pristine –extra-conf “full path to prj_bootloader.conf”`. This enables logging in the bootloader again and allows updates with two slots. Once you have flashed the updated bootloader and reset the board, you should see the following log in the console:

Serial terminal
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: 0x10000
I: Image version: v1.0.1
I: Jumping to the first image slot
The next section explains how to interpret this log.

Understand MCUboot Logging

It is important to understand the logging information provided by the MCUboot application in order to understand the update mechanism. The log contains the following information:

  • Information about images:

       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
    

    • The possible values for magic are BOOT_MAGIC_GOOD (1), BOOT_MAGIC_BAD (2) or BOOT_MAGIC_UNSET (3).

    • The possible values for swap_type are

Value Symbol Description
1 BOOT_SWAP_TYPE_NONE Attempt to boot the contents of the primary slot.
2 BOOT_SWAP_TYPE_TEST Swap to the secondary slot.
Absent a confirm command, revert back on next boot
3 BOOT_SWAP_TYPE_PERM Swap to the secondary slot,
and permanently switch to booting its contents.
4 BOOT_SWAP_TYPE_REVERT Swap back to alternate slot.
A confirm changes this state to NONE.
5 BOOT_SWAP_TYPE_FAIL Swap failed because image to be run
is not valid.
0xFF BOOT_SWAP_TYPE_PANIC Swapping encountered an unrecoverable error
* The possible values for `copy_done` and `image_ok` are `BOOT_FLAG_SET` (`1`), `BOOT_FLAG_BAD` (`2`) or `BOOT_FLAG_UNSET` (`3`).
  • Information about the Boot source. It is set to none, unless the magic of the primary slot is BOOT_MAGIC_GOOD, the copy_done of the primary slot is BOOT_FLAG_UNSET and the magic of the secondary slot is not BOOT_MAGIC_GOOD, in which case the Boot source is the primary slot.

  • The other information can be deduced from the preceding ones.

After flashing the BikeComputer program, the bootloader will simply attempt to jump to the application in the primary slot.

The swap Algorithms used by MCUboot

MCUboot supports different ways of swapping firmware candidates:

  • Swap using scratch: The algorithm uses an additional scratch area to perform the swap. The main drawback of this method is that it makes extensive use of the scratch area, which can be problematic on non-volatile flash memory. This video explains the algorithm in detail.

  • Swap using move: The algorithm uses an additional sector in the primary slot to perform the swap. The use of segment is evenly distributed and this is particularly beneficial when there are a large number of segments. This video explains the algorithm in detail.

  • Swap using offset: This is essentially the same algorithm as Swap using move, but where the additional sector is allocated in the secondary slot.

Modify the BikeComputer Program for Supporting DFU over UART

To implement Serial Recovery, it was not necessary to modify the BikeComputer program, because DFU was implemented in the MCUboot bootloader application. In the new scenario, the DFU over UART is implemented in the BikeComputer program. The following changes are required:

  • Modifiy the “prj_dfu.conf” configuration file at the root of your BikeComputer program with the following content:

    bike_computer/prj_dfu.conf
    # Changes required for MCUmgr
    # Enable mcumgr DFU in application
    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
    
    # Enable USB subsystem
    CONFIG_USB_DEVICE_STACK=y
    CONFIG_UART_LINE_CTRL=y
    CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
    
    Read the comments in the configuration file to understand the requirements for supporting DFU over UART in the application.

  • Modify the “nrf5340dk_nrf5340_cpuapp.overlay” file to configure the COM port to be used for mcuMgr DFU:

    bike_computer/boards/nrf5340dk_nrf5340_cpuapp.overlay
    ...
    &zephyr_udc0 {
      cdc_acm_uart0: cdc_acm_uart0 {
        compatible = "zephyr,cdc-acm-uart";
      };
    };
    
    / {
        chosen {
            zephyr,uart-mcumgr = &cdc_acm_uart0;
        };
    };
    

  • Enable USB for the BikeComputer program by modifying the main() function as follows:

    bike_computer/main.cpp
    ...
    // Include header for USB
    #include <zephyr/usb/usb_device.h>
    ...
    
    int main() 
      ...
      // Enable USB (before starting the BikeComputer instance)
      if (IS_ENABLED(CONFIG_USB_DEVICE_STACK)) {
        auto ret = usb_enable(NULL);
        if (ret) {
          LOG_ERR("Cannot enable USB: %d", ret);
          return 0;
        }
      }
      ...
    

  • Build your BikeComputer program by adding --extra-conf "full path to prj_dfu.conf" to the west build command. You may ignore warnings related to CONFIG_USB_DEVICE_VID and CONFIG_USB_DEVICE_PID.

  • Flash the updated program. You should see the same bootloader log on the console.

Upload a Firmware Update over UART

To upload a firmware update, you must first connect the “nRF USB” (to differentiate from the USB connected to the J-Link debugger) to your computer. If your BikeComputer program has been updated as described in the previous section, another COM port should be available for connecting on your computer.

The steps for uploading a firmware update are as follows:

  • In AuTerm, configure the COM port to use under the “Config” tab. Choose the new COM port and establish the connection by pressing “Open”.
  • In AuTerm, select the “MCUmgr” tab. Under “Images”, select “Get” and press “Go”. You should see that the board is configured with two slots (“Slot 0” and “Slot 1”) - note that if you only flashed the BikeComputer program using west flash, you may see only one slot. The first slot should be the one of the current application (say version “1.0.0”). It should be active, confirmed and bootable.
  • Modify your “BikeComputer” program so that a difference in logging appears at application start. Modify the CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION by incrementing the patch number. Build the program without flashing it.
  • In AuTerm, select the “MCUmgr” tab. Under “Upload”, select the “build/zephyr/zephyr.signed.bin” file, check the “Reset after upload” box and press “Go” to start the upload. Upload should start and after it is finished, the board should reset and start again.
  • In a serial terminal, you should see the following:
    Serial terminal
    ** Booting MCUboot v2.2.0-54-g4eba8087fa60 ***
    *** Using Zephyr OS build v4.2.1 ***
    I: Starting bootloader
    I: Primary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    I: Secondary image: magic=good, swap_type=0x2, copy_done=0x3, image_ok=0x3
    I: Boot source: none
    I: Image index: 0, Swap type: test
    I: Starting swap using move algorithm.
    I: Bootloader chainload address offset: 0x10000
    I: Image version: v1.0.1
    I: Jumping to the first image slot
    
  • As you can see in the log, the second slot is recognized as valid and the bootloader will start a swap to the secondary slot. After the move algorithm has been applied, the bootloader jumps to the first slot and you should see that your updated BikeComputer (with the updated image version) starts correctly. At this point, the update has not been confirmed.

  • If you update the images in AuTerm, you should see two slots with the latest image (e.g. version “1.0.1”) in slot 0 and the oldest image (e.g. version “1.0.0”) in slot 1. The two images have been swapped.

  • If you reset your board (without confirming the update), your should see the following log:

    Serial terminal
    *** Booting MCUboot v2.2.0-54-g4eba8087fa60 ***
    *** Using Zephyr OS build v4.2.1 ***
    I: Starting bootloader
    I: Primary image: magic=good, swap_type=0x2, copy_done=0x1, 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: revert
    I: Starting swap using move algorithm.
    I: Secondary image: magic=unset, swap_type=0x1, copy_done=0x3, image_ok=0x3
    
    The update has not been confirmed and the oldest image is restored by swapping. Your oldest BikeComputer program should start and you can confirm with AuTerm that the slots have been reverted with the oldest image in slot 0.

  • If you boot again, no swap takes place and the oldest image runs.

  • It is time to confirm the newest image that is stored in slot 1. You can do this by selecting slot 1 in the MCUmgr tab, by choosing set, checking the Confirm box and pressing Go. Slot 1 should now appear as permanent, bootable and pending.
  • If you reset the board again, you should see the following log:
    Serial terminal
    *** Using Zephyr OS build v4.2.1 ***
    *** Booting MCUboot v2.2.0-54-g4eba8087fa60 ***
    I: Starting bootloader
    I: Primary image: magic=good, swap_type=0x4, copy_done=0x1, image_ok=0x1
    I: Secondary image: magic=good, swap_type=0x3, copy_done=0x3, image_ok=0x1
    I: Boot source: none
    I: Image index: 0, Swap type: perm
    I: Starting swap using move algorithm.
    
    The secondary image is swapped again and your newest BikeComputer program starts.
  • If you update the images using AuTerm, slot 0 should contain the newest image as active, confirmed and bootable.
  • You can give it one more try with a newest version of the BikeComputer program. It should upload to slot 1 and you could confirm it after the initial swap so that it is not reverted.

Final Wrap-up

To achieve a fully functional bootloading process and understand its key principles, ensure you have accomplished the following:

  • You understand how the device’s flash is partitioned.
  • You have successfully tested the Serial Recovery process.
  • You have successfully tested DFU over UART from the BikeComputer program.
  • You understand how the mcuBoot bootloader application analyses image slots at startup and performs an image swap if applicable.
  • You have confirmed a firmware update after a test swap.