A field update that fails halfway shouldn't turn your device into a brick. In this article, you'll see how we set up MCUboot for signed images, A/B slots and automatic rollback, and what we learned shipping it on Nordic nRF52 and nRF53 products.

By the end of this article, you'll understand:

  • How MCUboot partitions flash and what a signed image contains
  • When to pick overwrite, swap or direct-XIP upgrades
  • How to sign images and keep your keys out of the repository
  • How to confirm or roll back an update from your application

Why a Bootloader at All?

Once a product leaves the lab, firmware updates are your only way to fix bugs, close security holes and ship new features. Doing that safely needs three guarantees:

  • Authenticity: the device only runs firmware that you signed.
  • Integrity: a corrupted or half-written image is never executed.
  • Recoverability: if the new firmware misbehaves, the device goes back to the last known-good version on its own.

MCUboot is an open-source secure bootloader for 32-bit microcontrollers that provides all three. It is the default bootloader in Zephyr and the nRF Connect SDK, and it also runs on Mynewt, Mbed and bare-metal ports.

Flash Layout and Image Format

MCUboot splits flash into a bootloader partition and two image slots. The primary slot holds the firmware that runs; the secondary slot receives a new image over BLE, UART, USB or cellular. On the next reset, MCUboot checks the new image and, if it is valid, installs it into the primary slot.

Anatomy of a Signed Image

Every image carries three parts:

  • A header (usually 0x200 bytes) with a magic number, load address and semantic version.
  • The payload: your application binary.
  • A TLV area with the SHA-256 hash, the public key hash and the signature.

The Slot Trailer

At the end of each slot sits a small trailer where MCUboot records swap progress and the image's confirmed flag. Because of that trailer, an update interrupted by a power loss resumes where it stopped on the next boot.

Choosing an Upgrade Mode

The upgrade strategy is a build-time choice, and it decides how much flash you need and whether rollback is possible.

Upgrade Modes Compared

Mode Rollback Flash cost When we use it
Overwrite-only No Lowest Tiny parts, or when the secondary slot lives in external flash and every byte counts.
Swap using scratch Yes Extra scratch sector Mixed sector sizes or a secondary slot on external QSPI flash.
Swap using move Yes One extra sector in the primary slot Uniform internal flash sectors.
Direct-XIP Yes Two full executable slots Large external flash with execute-in-place, when fast updates matter more than space.

Our Default on Nordic Parts

On nRF52 and nRF53 parts with uniform 4 KB internal flash sectors, we start with swap using move. It needs no scratch partition and still gives full rollback.

Rule of thumb: if you can afford the flash, use a swap mode. The ability to revert an update that boots but then fails your self-test is what makes fleet updates safe.

Signing Images

MCUboot checks a signature before it boots or installs any image.

Generating and Storing Keys

Generate a key pair once, keep the private key out of the repository (an HSM or your CI secret store), and build the public key into the bootloader. Never ship the default development keys that come with the MCUboot repository. They are public, so anyone could sign firmware your devices would accept.

Shell
# One-time: create an ECDSA P-256 signing key
imgtool keygen -k keys/root-ec-p256.pem -t ecdsa-p256

Signing With imgtool

West signs builds automatically once the key is configured, but it helps to know what happens underneath:

Shell
imgtool sign \
  --key keys/root-ec-p256.pem \
  --header-size 0x200 --pad-header \
  --align 4 \
  --version 1.3.0+42 \
  --slot-size 0x67000 \
  build/app/zephyr/zephyr.bin app-v1.3.0-signed.bin

Enabling MCUboot in Zephyr

With sysbuild, adding MCUboot to a Zephyr application takes a couple of configuration lines. The bootloader and the application are built and signed together in one west build.

Sysbuild Configuration

sysbuild.conf
SB_CONFIG_BOOTLOADER_MCUBOOT=y
SB_CONFIG_MCUBOOT_MODE_SWAP_USING_MOVE=y
SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y
SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="${APP_DIR}/keys/root-ec-p256.pem"

Receiving Updates Over BLE

MCUmgr gives you an image-management protocol that phone apps and command-line tools already speak:

prj.conf
CONFIG_BOOTLOADER_MCUBOOT=y
CONFIG_MCUMGR=y
CONFIG_MCUMGR_GRP_IMG=y
CONFIG_MCUMGR_GRP_OS=y
CONFIG_MCUMGR_TRANSPORT_BT=y

Building and Flashing

Shell
west build -b nrf52840dk/nrf52840 --sysbuild app
west flash

Test, Confirm, Roll Back

A swap upgrade happens in two steps. First the new image is marked for a test boot. MCUboot swaps it in, and if the application doesn't confirm itself before the next reset, MCUboot swaps the old image back.

Confirming After a Self-Test

main.c
#include <zephyr/dfu/mcuboot.h>

int main(void)
{
    if (!boot_is_img_confirmed()) {
        /* Prove the new firmware actually works before keeping it */
        if (radio_selftest() == 0 && sensors_selftest() == 0 && cloud_connect() == 0) {
            boot_write_img_confirmed();
        } else {
            sys_reboot(SYS_REBOOT_COLD); /* MCUboot reverts to the previous image */
        }
    }
    /* ... */
}

Confirming right at the top of main() defeats the purpose. Confirm only after the device has proven it can still do the one thing it must never lose: receive the next update.

Lessons From the Field

  1. Lock the partition map early. Changing slot sizes after devices ship means a bootloader update, which is the riskiest update there is.
  2. Turn on downgrade prevention. Pair image versions with a hardware security counter so an attacker can't roll a fleet back to a vulnerable release.
  3. Test power loss on purpose. Cut power at random points during swaps, for hundreds of cycles, before every production release.
  4. Measure the swap time. On a 1 MB slot a swap can take tens of seconds. Make sure your watchdog and your users can wait that long.
  5. Protect the bootloader. Lock its flash region and disable debug access (APPROTECT on Nordic parts) in production units.

Conclusion

MCUboot does the heavy lifting, but a reliable update pipeline is a system: partitioning, key management, transport, self-tests and manufacturing all have to line up. Get those right once and every future release becomes a routine push instead of a risk.