OTA Guide
Introduction
OTA (Over-the-Air) is a method for delivering firmware updates to remote devices using a network connection. Although the name implies a wireless connection, updates received over a wired connection (such as Ethernet) are still commonly referred to as OTA updates.
Zephyr supports multiple OTA upgrade schemes, as shown in the following table:
Example |
Path |
|---|---|
|
|
|
|
|
|
|
Among them, SMP Server provides a complete OTA solution, combining MCUboot bootloader with MCUmgr device management framework to achieve secure and reliable firmware upgrades. The OTA upgrade process will be introduced based on this example.
OTA Key Components
Implementing a secure OTA update primarily relies on the collaboration of three core components:
MCUboot: An open-source, secure bootloader. It is responsible for verifying the integrity and authenticity of application firmware during device boot, and managing firmware switching and update processes in Flash storage areas.
SMP Server: A Simple Management Protocol service built into your application. It is responsible for receiving and processing various commands from external management tool MCUmgr, including firmware upload, status query, etc.
MCUmgr: A client management tool running on your development host. You can use it to send commands to the SMP Server on the device side through various methods such as UART/BT/UDP, thereby triggering and controlling the entire OTA process.
OTA Module Hierarchy Diagram
Implementing secure OTA updates involves the following Zephyr submodules, with their hierarchical relationship shown in the diagram:
Upgrade Process
Using the above OTA Key Components, a typical upgrade flow diagram is shown below:
Note
The diagram illustrates the Swap_using_offset and Swap_using_move upgrade methods.
For specific command usage, please refer to OTA Upgrade Operation Process, and for firmware format, please refer to Firmware Format.
Firmware Storage Layout
Flash Partition Mapping
Flash map is a partition table that divides device flash memory into independent areas (flash areas), each assigned a unique numerical ID. MCUboot and applications use these IDs to find specific physical addresses and sizes for reading, writing, erasing, upgrading, and other operations.
Typically, we allocate two slots for each firmware: Primary slot and Secondary slot. The following is a Flash partition configuration diagram for a two-firmware scenario:
&flash0 {
reg = <0x103FF000 DT_SIZE_M(4)>;
status = "okay";
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
/* flash area ID 0 */
boot_partition: partition@0 {
label = "bootloader";
reg = <0x00000000 0x00014000>;
read-only;
};
/* Allocate primary slot (slot0_partition) and secondary slot (slot1_partition) for AP (firmware 0) */
/* flash area ID 1 */
slot0_partition: partition@14000 {
label = "image-0";
reg = <0x00014000 0x00080000>;
};
/* flash area ID 2 */
slot1_partition: partition@94000 {
label = "image-1";
reg = <0x00094000 0x00080000>;
};
/* Allocate primary slot (slot2_partition) and secondary slot (slot3_partition) for NP (firmware 1) */
/* flash area ID 3 */
slot2_partition: partition@114000 {
label = "image-2";
reg = <0x00114000 0x00080000>;
};
/* flash area ID 4 */
slot3_partition: partition@194000 {
label = "image-3";
reg = <0x00194000 0x00080000>;
};
};
};
Firmware Format
In Zephyr’s OTA scenario, application firmware booted by MCUboot must conform to the firmware format defined by MCUboot, including: Firmware Header, Firmware Body, TLV Area (Optional) and Firmware Trailer.
The schematic diagram is shown below:
Note
The diagram shows the format requirements for application firmware, not the firmware format of MCUboot itself.
Firmware Header
The Zephyr build system reserves 0x200 bytes at the start of the firmware for the header (ih_hdr_size = 0x200).
#define IMAGE_MAGIC 0x96f3b83d
#define IMAGE_HEADER_SIZE 32
STRUCT_PACKED image_version {
uint8_t iv_major;
uint8_t iv_minor;
uint16_t iv_revision;
uint32_t iv_build_num;
};
/** Image header. All fields are in little endian byte order. */
STRUCT_PACKED image_header {
uint32_t ih_magic;
uint32_t ih_load_addr;
uint16_t ih_hdr_size; /* Size of image header (bytes). */
uint16_t ih_protect_tlv_size; /* Size of protected TLV area (bytes). */
uint32_t ih_img_size; /* Does not include header. */
uint32_t ih_flags; /* IMAGE_F_[...]. */
struct image_version ih_ver;
uint32_t _pad1;
};
TLV Area (Type-Length-Value)
The TLV area is located after the firmware body and is optional, typically storing fields such as hash, signature, and security counter.
When a protected TLV area exists, the IMAGE_TLV_PROT_INFO_MAGIC information header must be present, and this area is included in the hash calculation. If not present, the hash only covers “firmware header + firmware body”.
To ensure rollback protection is effective, IMAGE_TLV_SEC_CNT, 0x50 needs to be written to the protected TLV area. Using imgtool’s --security-counter option will place it in the protected TLV area.
#define IMAGE_TLV_INFO_MAGIC 0x6907
#define IMAGE_TLV_PROT_INFO_MAGIC 0x6908
/** Image TLV header. All fields in little endian. */
STRUCT_PACKED image_tlv_info {
uint16_t it_magic;
uint16_t it_tlv_tot; /* size of TLV area (including tlv_info header) */
};
/** Image trailer TLV format. All fields in little endian. */
STRUCT_PACKED image_tlv {
uint16_t it_type; /* IMAGE_TLV_[...]. */
uint16_t it_len; /* Data length (not including TLV header). */
};
#define IMAGE_TLV_KEYHASH 0x01 /* hash of the public key */
#define IMAGE_TLV_SHA256 0x10 /* SHA256 of image hdr and body */
#define IMAGE_TLV_RSA2048_PSS 0x20 /* RSA2048 of hash output */
#define IMAGE_TLV_ECDSA224 0x21 /* ECDSA of hash output - Not supported anymore */
#define IMAGE_TLV_ECDSA_SIG 0x22 /* ECDSA of hash output */
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
#define IMAGE_TLV_ED25519 0x24 /* ED25519 of hash output */
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW-128 or 256 */
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-P256 */
#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */
#define IMAGE_TLV_SEC_CNT 0x50 /* security counter */
Firmware Trailer
Used to record swap/status metadata at the end of the slot, and this space cannot be used to store firmware body.
The firmware Trailer structure is as follows (in bytes):
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ ~
~ Swap status (BOOT_MAX_IMG_SECTORS * min-write-size * s) ~
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Encryption key 0 (16 octets) [*] |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xff padding as needed |
| (BOOT_MAX_ALIGN minus 16 octets from Encryption key 0) [*] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Encryption key 1 (16 octets) [*] |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xff padding as needed |
| (BOOT_MAX_ALIGN minus 16 octets from Encryption key 1) [*] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Swap size (4 octets) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xff padding as needed |
| (BOOT_MAX_ALIGN minus 4 octets from Swap size) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Swap info | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Copy done | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Image OK | 0xff padding (BOOT_MAX_ALIGN minus 1 octet) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 0xff padding as needed |
| (BOOT_MAX_ALIGN minus 16 octets from MAGIC) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| MAGIC (16 octets) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- Parameter Description
- BOOT_MAX_IMG_SECTORS:
Default value is the number of sectors occupied by
slot0_partition.- min-write-size:
Flash minimum write granularity.
- s:
s = 3 (Swap_using_move), s= 2 (Swap_using_offset)
- Swap status:
Per-sector Swap Status record for recovery after power loss.
- Encryption keys:
(Optional) Encryption keys, only present when encryption is enabled.
- Swap size:
Total amount of data to be moved in this swap (covering firmware body + TLV area).
- Swap info:
1 byte valid, BOOT_MAX_ALIGN aligned; lower 4 bits are Swap Type, upper 4 bits are firmware number.
- Copy done:
1 byte valid, BOOT_MAX_ALIGN aligned; indicates copy phase completion status: 0x01=Set, 0xFF=Unset.
- Image OK:
1 byte valid, BOOT_MAX_ALIGN aligned; indicates whether new firmware has been confirmed, unconfirmed will revert on next boot. 0x01=Set, 0xFF=Unset.
- MAGIC:
16 bytes, marker for trailer area validity.
When
BOOT_MAX_ALIGN=8, it is a fixed 16-byte pattern:const union boot_img_magic_t boot_img_magic = { .val = { 0x77, 0xc2, 0x95, 0xf3, 0x60, 0xd2, 0xef, 0x7f, 0x35, 0x52, 0x50, 0x0f, 0x2c, 0xb6, 0x79, 0x80 } };
Otherwise, the first 2 bytes are the alignment value, and the last 14 bytes are a fixed pattern:
const union boot_img_magic_t boot_img_magic = { .align = BOOT_MAX_ALIGN, .magic = { 0x2d, 0xe1, 0x5d, 0x29, 0x41, 0x0b, 0x8d, 0x77, 0x67, 0x9c, 0x11, 0x0f, 0x1f, 0x8a } };
Note
This area is located at the end of the firmware slot, not immediately following the firmware body. Therefore, the allocated slot needs to reserve Trailer space and be sector-aligned.
Upgrade Mechanism
MCUboot supports multiple firmware upgrade methods, as shown in the following table. For details, please refer to MCUboot official documentation .
Upgrade Method |
Characteristics |
Upgrade only |
Directly overwrites old firmware with new firmware, no swap, no rollback |
Swap using scratch |
Uses scratch partition as intermediate storage to complete new/old firmware swap, rollback supported |
Swap using offset |
Relies on offset layout within partitions for swapping, no scratch partition needed, rollback supported |
Swap using move |
Completes swap by moving data, no scratch partition needed, rollback supported |
Direct XIP |
Execute in place, no swap needed |
RAM load |
Load firmware completely into RAM before execution |
Firmware loader |
Upgrade through dedicated loader |
Currently, the following two upgrade methods are supported:
Swap_using_move
Swap_using_move is a firmware swap algorithm that does not require temporary storage (scratch), suitable for dual-slot (primary slot/secondary slot) OTA upgrade scenarios. Its core is to complete firmware swap by moving all primary slot sectors down by one position and alternately copying primary and secondary slot contents.
This upgrade method can be enabled by configuring the macro CONFIG_BOOT_SWAP_USING_MOVE. When using –sysbuild, configure SB_CONFIG_MCUBOOT_MODE_SWAP_USING_MOVE=y in the application’s sysbuild.conf
Working Principle
Sector Move Down: First, move all primary slot sectors down by one sector position.
Alternate Copy: Starting from the 1st sector, execute sequentially:
Copy secondary slot sector N to primary slot sector N;
Repeat until all sectors are swapped.
From the diagram, each sector swap has 3 states:
Primary slot[N] → Primary slot[N+1] completed
Secondary slot[N] → Primary slot[N] completed
Primary slot[N+1] → Secondary slot[N] completed
Swap_using_offset
Swap_using_offset is a firmware swap algorithm that does not require temporary storage (scratch), an enhanced version of Swap_using_move. Its core is to use one sector of the secondary slot as a buffer and alternately copy primary and secondary slot contents to complete firmware swap.
Enable by configuring the macro CONFIG_BOOT_SWAP_USING_OFFSET; when using –sysbuild, configure SB_CONFIG_MCUBOOT_MODE_SWAP_USING_OFFSET=y in the application’s sysbuild.conf.
Working Principle
Firmware Placement: The new firmware to be upgraded must be stored starting from the second sector of the secondary slot.
Alternate Copy: Starting from the 1st sector, execute sequentially:
Copy primary slot sector N to secondary slot sector N;
Copy secondary slot sector N+1 to primary slot sector N;
Repeat until all sectors are swapped.
From the diagram, each sector swap has 2 states:
Primary slot[N] → Secondary slot[N] completed
Secondary slot[N+1] → Primary slot[N] completed
Swap Management
Swap Type
In non-recovery scenarios (no abnormal interruption during the upgrade process), MCUboot determines the swap type to execute based on the flag bits in the firmware trailer. Due to Flash hardware limitations, the trailer design is not intuitive, and directly reading its bytes makes it difficult to restore the device state. Therefore, MCUboot maps “various possible trailer combination states” to “swap types” and determines them in priority order.
State I scenario: During the risk window before executing REVERT in Swap_using_offset, recording magic and copy-done to the secondary slot, the next boot will continue to execute REVERT.
State I (swap using offset only)
| primary slot | secondary slot |
-----------------+--------------+----------------|
magic | Any | Good |
image-ok | Any | Unset |
copy-done | Any | Set |
-----------------+--------------+----------------'
result: BOOT_SWAP_TYPE_REVERT |
-------------------------------------------------'
State II scenario: Secondary slot firmware is valid and unconfirmed, execute “test swap”. The system will swap from secondary slot to primary slot and boot. The new firmware needs to set image-ok in the application for confirmation; if not confirmed, the next boot will revert.
State II
| primary slot | secondary slot |
-----------------+--------------+----------------|
magic | Any | Good |
image-ok | Any | Unset |
copy-done | Any | Any |
-----------------+--------------+----------------'
result: BOOT_SWAP_TYPE_TEST |
-------------------------------------------------'
State III scenario: Secondary slot firmware is pre-marked as image-ok, execute “permanent swap”, no rollback after upgrade.
State III
| primary slot | secondary slot |
-----------------+--------------+----------------|
magic | Any | Good |
image-ok | Any | 0x01 |
copy-done | Any | Any |
-----------------+--------------+----------------'
result: BOOT_SWAP_TYPE_PERM |
-------------------------------------------------'
State IV scenario: Primary slot has completed copy (copy-done=Set), but new firmware is unconfirmed (image-ok=Unset), so revert is executed on this boot, restoring to the old firmware.
State IV
| primary slot | secondary slot |
-----------------+--------------+----------------|
magic | Good | Any |
image-ok | 0xff | Any |
copy-done | 0x01 | Any |
-----------------+--------------+----------------'
result: BOOT_SWAP_TYPE_REVERT |
-------------------------------------------------'
If none of the above State I-IV match, MCUboot will not attempt to swap images, but will execute one of the three swap types in the State V table.
State V
| primary slot | secondary slot |
-----------------+--------------+----------------|
magic | Any | Any |
image-ok | Any | Any |
copy-done | Any | Any |
-----------------+--------------+----------------'
result: BOOT_SWAP_TYPE_NONE, |
BOOT_SWAP_TYPE_FAIL, or |
BOOT_SWAP_TYPE_PANIC |
-------------------------------------------------'
Note
Lower State number indicates higher priority. Once a state is matched, the corresponding swap type is immediately determined and matching stops.
Swap types:
BOOT_SWAP_TYPE_NONE: No upgrade, directly boot primary slot firmware.BOOT_SWAP_TYPE_TEST: Test run; if not confirmed (write image-ok=0x01), revert on next boot.BOOT_SWAP_TYPE_PERM: Permanent swap.BOOT_SWAP_TYPE_REVERT: Previous TEST was not confirmed, revert to the previous old firmware.BOOT_SWAP_TYPE_FAIL: Target firmware is invalid (verification failed, etc.).BOOT_SWAP_TYPE_PANIC: Swap encountered unrecoverable error (abort).
Swap Status
Swap status is used for power-loss recovery and is recorded in the Trailer of the primary slot. When a reboot occurs during firmware swap, MCUboot can restore the state based on the recorded swap status and continue the unfinished swap operation. This area consists of a series of “single-byte records”, each written independently and aligned according to the device’s minimum write granularity. The normal swap process is as follows:
Initialization: Erase both primary and secondary slot Trailers; then write swap_info, swap_size, and MAGIC markers in the primary slot Trailer.
Per-sector Swap: Only swap sectors actually occupied by firmware (including TLV), and record the status of each sector according to the selected algorithm.
Finalization: After completion, write copy done in the primary slot Trailer to mark the swap as complete.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sec127,state 0 |sec127,state 1 |sec127,state 2 |sec126,state 0 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sec126,state 1 |sec126,state 2 |sec125,state 0 |sec125,state 1 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|sec125,state 2 | |
+-+-+-+-+-+-+-+-+ +
~ ~
~ [Records for indices 124 through 1 ~
~ ~
~ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
~ |sec000,state 0 |sec000,state 1 |sec000,state 2 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Note
The diagram assumes min-write-size = 1, where each “sector index” corresponds to 3 state records, applicable to Swap_using_move mode; whereas in Swap_using_offset mode, each sector has only 2 state records, requiring less total space.
Anti-Rollback
To prevent devices from being downgraded to firmware versions with known vulnerabilities, MCUboot supports anti-rollback policies, divided into software anti-rollback and hardware anti-rollback. Software anti-rollback can be further divided into version number-based and security counter-based approaches.
Software Anti-Rollback (Version Number Based)
Version number-based software anti-rollback only exists in !BOOT_DIRECT_XIP upgrade mode. This method is purely software-based anti-rollback and does not prevent physical attacks (such as Flash erase/rewrite).
Principle:
MCUboot compares firmware version numbers at each boot.
If the new firmware version number is lower than the currently running firmware version number, boot is rejected.
If the new firmware version number is greater than or equal to the currently running firmware version, boot is allowed.
Configuration:
CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y
Embed version number during firmware signing:
# Example: Set in application prj.conf or board-specific configuration CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="0.0.2"
Software Anti-Rollback (Security Counter Based)
Security counter-based software anti-rollback only exists in (BOOT_SWAP_USING_MOVE || BOOT_SWAP_USING_SCRATCH || BOOT_SWAP_USING_OFFSET) mode.
This method is purely software-based anti-rollback and does not prevent physical attacks (such as Flash erase/rewrite).
Principle:
MCUboot compares security counter values at each boot.
If the new firmware’s security counter is less than the currently running firmware’s security counter, boot is rejected.
If the new firmware’s security counter is greater than or equal to the currently running firmware’s security counter, boot is allowed.
Configuration:
CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y # security counter option depends on this configuration CONFIG_MCUBOOT_DOWNGRADE_PREVENTION_SECURITY_COUNTER=y
Embed security counter during firmware signing:
# Example: Set in application prj.conf or board-specific configuration CONFIG_MCUBOOT_IMGTOOL_SIGN_SECURITY_COUNTER=2
Note
Currently, NP firmware always uses the same security counter as AP.
Hardware Anti-Rollback (OTP Based)
Principle:
MCUboot saves the currently accepted security counter to a hardware counter (OTP).
If the new firmware’s security counter is less than the OTP recorded value, boot is rejected.
If the new firmware’s security counter is greater than or equal to the OTP recorded value, boot is allowed.
Configuration:
CONFIG_MCUBOOT_HW_DOWNGRADE_PREVENTION=y
Embed security counter during firmware signing:
# Example: Set in application prj.conf or board-specific configuration CONFIG_MCUBOOT_IMGTOOL_SIGN_SECURITY_COUNTER=2
Note
Currently, NP firmware always uses the same security counter as AP.
Both NP and AP firmware hardware counters have upper limits; please only update when necessary, as reaching the upper limit may cause device boot failure.
Quick Start
Environment Setup and Configuration
1. Install MCUmgr Command Line Tool on PC Host
You can download the corresponding platform’s newtmgr tool package from the Apache Mynewt official website:
Windows 64-bit: apache-mynewt-newtmgr-bin-windows-1.14.0.tgz
Linux 64-bit: apache-mynewt-newtmgr-bin-linux-1.14.0.tgz
Add the extracted newtmgr tool package path to the environment variable of the corresponding platform.
Execute newtmgr –help in the command line. If global options are displayed, the configuration is successful.
2. Zephyr Device-side Project Configuration
Sample path: zephyr/samples/subsys/mgmt/mcumgr/smp_svr.
Flash Partition
The flash partition layout used by the smp_svr sample can be configured with reference to Flash Partition Mapping.
Basic MCUboot and SMP Configuration
You need to ensure that the smp_svr sample’s configuration file (such as prj.conf or board-specific configuration file) contains the following key configurations:
# Enable MCUboot bootloader
CONFIG_BOOTLOADER_MCUBOOT=y
CONFIG_UPDATEABLE_IMAGE_NUMBER=2 # AP (firmware 0) and NP (firmware 1)
CONFIG_MCUMGR_GRP_IMG_ALLOW_CONFIRM_NON_ACTIVE_IMAGE_ANY=y # Allow confirmation of non-running firmware
# Enable MCUmgr necessary command groups
CONFIG_MCUMGR_GRP_IMG=y # Firmware management command group
CONFIG_MCUMGR_GRP_OS=y # Basic OS command group
# Enable MCUmgr and SMP services
CONFIG_MCUMGR=y
CONFIG_MCUMGR_SMP_UART=y # Use UART as transport layer
# Configure UART buffer and MTU (Maximum Transmission Unit)
CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE=1024
CONFIG_UART_MCUMGR_RX_BUF_SIZE=256 # Needs to match MTU set in MCUmgr tool
You need to specify the upgrade method in the application’s sysbuild configuration file sysbuild.conf, otherwise the top level will choose swap_using_move method by default.
# Configure upgrade method
SB_CONFIG_MCUBOOT_MODE_SWAP_USING_OFFSET=y
UART Transport Layer Configuration
You need to specify the UART pins used in the device tree (overlay file) and ensure the UART port is properly configured and enabled.
/ {
chosen {
zephyr,uart-mcumgr = &uart2;
};
};
&uart2 {
pinctrl-0 = <&uart2_default>;
pinctrl-names = "default";
current-speed = <115200>;
status = "okay";
};
Build Command
./nuwa.py build -d rtl8721f_evb//mcuboot -a zephyr/samples/subsys/mgmt/mcumgr/smp_svr --sysbuild -p
Or
west build -b rtl8721f_evb//mcuboot zephyr/samples/subsys/mgmt/mcumgr/smp_svr --sysbuild -p
After device power-on/reset, open a serial terminal and confirm that the sample has started and printed initialization logs:
*** Booting Zephyr OS build f50378385a85 ***
<inf> smp_sample: build time: Jan 7 2026 11:52:35
OTA Upgrade Operation Process
Assume the device is already running firmware containing the smp_svr sample, and the selected UART port is connected to the PC.
Establish MCUmgr Connection
Configure Connection
Command format: newtmgr conn add <connection_name> type=<type> connstring="<key=value[,key=value...]>"
Example:
$ newtmgr conn add myConn type=serial connstring=\"dev=<COM3>,baud=115200,mtu=256\"
Connection profile myConn successfully added
Note
Baud rate configuration needs to be consistent with the setting in device tree. MTU configuration needs to be less than or equal to
CONFIG_UART_MCUMGR_RX_BUF_SIZEin application configuration.For other transport methods of newtmgr conn configuration, please refer to official documentation.
View Firmware List
Command format: newtmgr image list -c <connection_profile>
Example:
$ newtmgr image list -c myConn Images: image=0 slot=0 version: 0.0.0 bootable: true flags: active confirmed hash: d0d1fe6e6f39a65d2442009e6a620736ea88e437c7bd297abdd9e9eaf1e3e257 image=1 slot=0 version: 0.0.0 bootable: true flags: active confirmed hash: 8ea9150f95da9c3f97134984b731928ae93e14752c54fe53b629d005ab94a948
- Parameter Description
- image:
Firmware number when there are multiple firmwares.
- slot:
Slot (0=primary slot, 1=secondary slot)
- version/hash:
Version number and hash
- bootable:
Whether the slot contains valid firmware (firmware header is correct and verifiable)
- flags:
activeindicates the currently running firmware slotpendingindicates MCUboot will test this firmware slot on next resetconfirmedindicates this firmware slot has been confirmed and will not roll back
Note
When building new firmware, you can modify the version number
CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSIONfor easier version management and querying.Currently NP firmware always uses the same version number as AP firmware.
Upload New Firmware
Use the image upload command to send the newly compiled and signed firmware to the device.
Command format: newtmgr image upload <image-file> -c <conn_profile> [-n <image_int>]
Example:
$ newtmgr -c myConn image upload -n 0 /path/to/your/image_0.bin 77.55 KiB / 77.55 KiB [=======================================================================] 100.00% 4.38 KiB/s 17s Done $ newtmgr -c myConn image upload -n 1 /path/to/your/image_1.bin 228.48 KiB / 228.48 KiB [=====================================================================] 100.00% 4.44 KiB/s 51s Done
- Parameter Description
- -n:
Specify firmware number, defaults to firmware 0 when omitted.
Mark as Pending Test
After successful transfer, the new firmware will be stored in the secondary slot partition of the corresponding firmware. Use the following command to mark the new firmware as test, and MCUboot will try to run it on the next boot.
Command format: newtmgr -c <conn_profile> image test <hex-image-hash>
Example:
$ newtmgr -c myConn image test 99bb5f0867744a238693f522b31be146a74fca2ad587d878feebef70b7d1e812
Images:
image=0 slot=0
version: 0.0.0
bootable: true
flags: active confirmed
hash: d0d1fe6e6f39a65d2442009e6a620736ea88e437c7bd297abdd9e9eaf1e3e257
image=0 slot=1
version: 0.0.1
bootable: true
flags: pending
hash: 99bb5f0867744a238693f522b31be146a74fca2ad587d878feebef70b7d1e812
image=1 slot=0
version: 0.0.0
bootable: true
flags: active confirmed
hash: 8ea9150f95da9c3f97134984b731928ae93e14752c54fe53b629d005ab94a948
image=1 slot=1
version: 0.0.1
bootable: true
flags:
hash: 137d5f84dc5c302f2d15d22ca7fa76c48e030a5d5c6f73b6ae89598143af92fe
Split status: N/A (0)
$ newtmgr -c myConn image test 137d5f84dc5c302f2d15d22ca7fa76c48e030a5d5c6f73b6ae89598143af92fe
Images:
image=0 slot=0
version: 0.0.0
bootable: true
flags: active confirmed
hash: d0d1fe6e6f39a65d2442009e6a620736ea88e437c7bd297abdd9e9eaf1e3e257
image=0 slot=1
version: 0.0.1
bootable: true
flags: pending
hash: 99bb5f0867744a238693f522b31be146a74fca2ad587d878feebef70b7d1e812
image=1 slot=0
version: 0.0.0
bootable: true
flags: active confirmed
hash: 8ea9150f95da9c3f97134984b731928ae93e14752c54fe53b629d005ab94a948
image=1 slot=1
version: 0.0.1
bootable: true
flags: pending
hash: 137d5f84dc5c302f2d15d22ca7fa76c48e030a5d5c6f73b6ae89598143af92fe
Split status: N/A (0)
Note
You can see in the information of the firmware slot specified for testing:
flags: pending.
Reset Device
You can send a reset command through the MCUmgr tool, or manually reset the device.
After triggering reset, MCUboot detects that the secondary slot is marked as test, and based on the configured Upgrade Mechanism, decides whether to perform primary/secondary slot swap; when using swap_using_xxx strategy, the swap will be completed before the application starts.
Command format: newtmgr reset -c <conn_profile>
Example:
$ newtmgr -c myConn reset
Done
Confirm New Firmware
After the device restarts and successfully runs the new firmware, you must perform a confirmation operation. Zephyr provides two confirmation methods:
Application self-confirmation
After the device boots and verifies the new firmware successfully, the application actively calls the confirmation interface
boot_write_img_confirmed()provided by MCUboot to mark the current firmware asconfirmed.Send confirmation command through MCUmgr tool
Command format:
newtmgr image confirm [hex-image-hash] -c <conn_profile>Example:
$ newtmgr -c myConn image confirm 137d5f84dc5c302f2d15d22ca7fa76c48e030a5d5c6f73b6ae89598143af92fe Images: image=0 slot=0 version: 0.0.1 bootable: true flags: active confirmed hash: 99bb5f0867744a238693f522b31be146a74fca2ad587d878feebef70b7d1e812 image=1 slot=0 version: 0.0.1 bootable: true flags: active confirmed hash: 137d5f84dc5c302f2d15d22ca7fa76c48e030a5d5c6f73b6ae89598143af92fe
Note
You can see in the confirmed firmware slot information:
flags: confirmed.The current smp_svr sample uses the second confirmation method.