Skip to content

Commit fdc4f2e

Browse files
committed
samples: Add split slot A/B sample
Add a variant of the A/B sample that presents how to perform A/B updates in a system, where application and radio images uses separate images and slots. Ref: NCSDK-35733 Signed-off-by: Tomasz Chyrowicz <[email protected]>
1 parent a72be82 commit fdc4f2e

File tree

14 files changed

+784
-0
lines changed

14 files changed

+784
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
8+
cmake_minimum_required(VERSION 3.20.0)
9+
10+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
11+
project(ab_split)
12+
13+
target_sources(app PRIVATE src/main.c)
14+
target_sources(app PRIVATE src/ab_utils.c)
15+
16+
target_include_directories(
17+
app PRIVATE
18+
${ZEPHYR_MCUBOOT_MODULE_DIR}/boot/bootutil/include
19+
${ZEPHYR_MCUBOOT_MODULE_DIR}/boot/zephyr/include
20+
${ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src
21+
)
22+
23+
target_sources_ifdef(CONFIG_MCUMGR_TRANSPORT_BT app PRIVATE
24+
${ZEPHYR_BASE}/samples/subsys/mgmt/mcumgr/smp_svr/src/bluetooth.c)

samples/dfu/ab_split/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
config N_BLINKS
8+
int "Number of fast blinks"
9+
default 1
10+
11+
config EMULATE_APP_HEALTH_CHECK_FAILURE
12+
bool "Blocks confirmation of being healthy after the update"
13+
14+
source "Kconfig.zephyr"

samples/dfu/ab_split/README.rst

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
.. _ab_split_sample:
2+
3+
A/B with MCUboot and separated slots
4+
####################################
5+
6+
.. contents::
7+
:local:
8+
:depth: 2
9+
10+
The A/B with MCUboot and separated slots sample demonstrates how to configure the application for updates using the A/B method using MCUboot.
11+
This sample is a variant of the :ref:`A/B sample <ab_sample>`, where the application and radio images are not merged, but reside in separate MCUboot slots.
12+
This split increases demand on the number of memory areas that should be individually locked from accidental writes as well as requires additional care when preparing updates, so only a compatible set of slots are booted.
13+
The additional dependency check during the boot process increases the time to boot the system.
14+
15+
It also includes an example to perform a device health check before confirming the image after the update.
16+
You can update the sample using the Simple Management Protocol (SMP) with UART or Bluetooth® Low Energy.
17+
18+
To prevent the build system from merging slots, the sysbuild :kconfig:option:`SB_CONFIG_MCUBOOT_SIGN_MERGED_BINARY` option is disabled.
19+
To enable slot-based dependency management, the :kconfig:option:`CONFIG_BOOT_VERSION_CMP_USE_SLOT_NUMBER` option is enabled in the :file:`sysbuild/mcuboot/prj.conf` file.
20+
21+
Requirements
22+
************
23+
24+
The sample supports the following development kits:
25+
26+
.. table-from-sample-yaml::
27+
28+
You need the nRF Device Manager app for update over Bluetooth Low Energy:
29+
30+
* `nRF Device Manager mobile app for Android`_
31+
* `nRF Device Manager mobile app for iOS`_
32+
33+
34+
Overview
35+
********
36+
37+
This sample demonstrates firmware update using the A/B method.
38+
This method allows two copies of the application in the NVM memory.
39+
It is possible to switch between these copies without performing a swap, which significantly reduces time of device's unavailability during the update.
40+
The switch between images can be triggered by the application or, for example, by a hardware button.
41+
42+
This sample implements an SMP server.
43+
SMP is a basic transfer encoding used with the MCUmgr management protocol.
44+
For more information about MCUmgr and SMP, see :ref:`device_mgmt`.
45+
46+
The sample supports the following MCUmgr transports by default:
47+
48+
* Bluetooth
49+
* Serial (UART)
50+
51+
A/B functionality
52+
=================
53+
54+
When the A/B with separated slots functionality is used, the device has two slots for each application and radio firmwares: slot A and slot B.
55+
The slots are equivalent, and the device can boot from either of them.
56+
By design, the slot A of the application image boots the slot A of the radio image, so there is a slot-based dependency required to correctly verify the correctness of the images.
57+
In the case of MCUboot, this is achieved by using the Direct XIP feature.
58+
Thus, note that the terms slot 0, primary slot, slot A and slot 1, secondary slot, slot B are used interchangeably throughout the documentation.
59+
This configuration allows a background update of the non-active slot while the application runs from the active slot.
60+
After the update is complete, the device can quickly switch to the updated slot on the next reboot.
61+
62+
The following conditions decide which slot will be booted (active) on the next reboot:
63+
64+
1. If one of the slots contains a valid image, it is marked as valid only if the same slot of the other image is also valid.
65+
#. If one of the slots is not valid, the other slot is selected as active.
66+
#. If both slots are valid, the slot marked as "preferred" is selected as active.
67+
#. If both slots are valid and none is marked as "preferred," the slot with the higher version number is selected as active.
68+
#. If none of the above conditions is met, slot A is selected as active.
69+
70+
You can set the preferred slot using the ``boot_request_set_preferred_slot`` function.
71+
Currently, this only sets the boot preference for a single reboot.
72+
73+
Identifying the active slot
74+
---------------------------
75+
76+
If the project uses the Partition Manager, the currently running slot can be identified by checking if ``CONFIG_NCS_IS_VARIANT_IMAGE`` is defined.
77+
If it is defined, the application is running from slot B.
78+
Otherwise, it is running from slot A.
79+
80+
If the project does not use the Partition Manager (a configuration currently only supported on the nRF54H20), the currently running slot can be identified by comparing the address pointed `zephyr,code-partition` to specific node addresses defined in the device tree.
81+
The following node partitions are used by default:
82+
83+
* ``cpuapp_slot0_partition`` - Application core, slot A
84+
* ``cpuapp_slot1_partition`` - Application core, slot B
85+
* ``cpurad_slot0_partition`` - Radio core, slot A
86+
* ``cpurad_slot1_partition`` - Radio core, slot B
87+
88+
For example, verifying that the application is running from slot A can be done by using the following macro:
89+
90+
.. code-block:: c
91+
92+
#define IS_RUNNING_FROM_SLOT_A \
93+
(FIXED_PARTITION_NODE_OFFSET(DT_CHOSEN(zephyr_code_partition)) == \
94+
FIXED_PARTITION_OFFSET(cpuapp_slot0_partition))
95+
96+
.. _ab_split_build_files:
97+
98+
Build files
99+
-----------
100+
101+
This sample overrides the default build strategy, so application and radio images are built separately.
102+
In this case, the following files should be sent to the device when performing an update:
103+
104+
* :file:`build/mcuboot_secondary_app/zephyr/zephyr.signed.bin` - Contains the slot B of the application image.
105+
This file should be uploaded to the secondary slot when the device is running from slot A.
106+
* :file:`build/ipc_radio_secondary_app/zephyr/zephyr.signed.bin` - Contains the slot B of the radio image.
107+
This file should be uploaded to the secondary slot when the device is running from slot A.
108+
* :file:`build/ab/zephyr/zephyr.signed.bin` - Contains the slot A of the application image.
109+
This file should be uploaded to the primary slot when the device is running from slot B.
110+
* :file:`build/ipc_radio/zephyr/zephyr.signed.bin` - Contains the slot A of the radio image.
111+
This file should be uploaded to the primary slot when the device is running from slot B.
112+
113+
User interface
114+
**************
115+
116+
LED 0:
117+
This LED indicates that the application is running from slot A.
118+
It is controlled as active low, meaning it will turn on once the application is booted and blinks (turns off) in short intervals.
119+
The number of short blinks is configurable using the :kconfig:option:`CONFIG_N_BLINKS` Kconfig option.
120+
It will remain off if the application is running from slot B.
121+
122+
LED 1:
123+
This LED indicates that the application is running from slot B.
124+
It is controlled as active low, meaning it will turn on once the application is booted and blinks (turns off) in short intervals.
125+
The number of short blinks is configurable using the :kconfig:option:`CONFIG_N_BLINKS` Kconfig option.
126+
It will remain off if the application is running from slot A.
127+
128+
Button 0:
129+
By pressing this button, the non-active slot will be selected as the preferred slot on the next reboot.
130+
This preference applies only to the next boot and is cleared after the subsequent reset.
131+
132+
Configuration
133+
*************
134+
135+
|config|
136+
137+
Configuration options
138+
=====================
139+
140+
Check and configure the following configuration option for the sample:
141+
142+
.. _CONFIG_N_BLINKS:
143+
144+
CONFIG_N_BLINKS - The number of blinks.
145+
This configuration option sets the number of times the LED corresponding to the currently active slot blinks (LED0 for slot A, LED1 for slot B).
146+
The default value of the option is set to ``1``, causing a single blink to indicate *Version 1*.
147+
You can increment this value to represent an update, such as set it to ``2`` to indicate *Version 2*.
148+
149+
.. _CONFIG_EMULATE_APP_HEALTH_CHECK_FAILURE:
150+
151+
CONFIG_EMULATE_APP_HEALTH_CHECK_FAILURE - Enables emulation of a broken application that fails the self-test.
152+
This configuration option emulates a broken application that does not pass the self-test.
153+
154+
Additional configuration
155+
========================
156+
157+
Check and configure the :kconfig:option:`CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION` library Kconfig option specific to the MCUboot library.
158+
This configuration option sets the version to pass to imgtool when signing.
159+
To ensure the updated build is preferred after a DFU, set this option to a higher version than the version currently running on the device.
160+
161+
In addition, set the :kconfig:option:`CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS` library Kconfig option specific to the MCUboot library to specify the slot-specific image dependencies.
162+
For example, to ensure that there is a valid radio image with version ``1.0.0`` or greater in the radio primary slot set:
163+
164+
.. code-block:: console
165+
166+
CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS="--dependencies \"(0,primary,1.0.0)\""
167+
168+
The slot-specific dependency is automatically converted to point to the secondary slot when building the second variant of each image.
169+
170+
Building and running
171+
********************
172+
173+
.. |sample path| replace:: :file:`samples/dfu/ab`
174+
175+
.. include:: /includes/build_and_run.txt
176+
177+
Testing
178+
=======
179+
180+
To perform DFU using the `nRF Connect Device Manager`_ mobile app, complete the following steps:
181+
182+
.. include:: /app_dev/device_guides/nrf52/fota_update.rst
183+
:start-after: fota_upgrades_over_ble_nrfcdm_common_dfu_steps_start
184+
:end-before: fota_upgrades_over_ble_nrfcdm_common_dfu_steps_end
185+
186+
Instead of using the :file:`dfu_application.zip` file, you can also send the appropriate binary file directly, as described in :ref:`ab_build_files`.
187+
Make sure to select the correct file based on the currently running slot.
188+
189+
Dependencies
190+
************
191+
192+
This sample uses the following |NCS| library:
193+
194+
* :ref:`MCUboot <mcuboot_index_ncs>`
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
*/
6+
7+
#include "../sysbuild/nrf54h20dk_nrf54h20_memory_map.dtsi"
8+
9+
/ {
10+
chosen {
11+
zephyr,boot-mode = &boot_request;
12+
};
13+
};

samples/dfu/ab_split/prj.conf

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Enable MCUmgr and dependencies.
2+
CONFIG_NET_BUF=y
3+
CONFIG_ZCBOR=y
4+
CONFIG_CRC=y
5+
CONFIG_MCUMGR=y
6+
CONFIG_STREAM_FLASH=y
7+
CONFIG_FLASH_MAP=y
8+
9+
# Some command handlers require a large stack.
10+
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304
11+
CONFIG_MAIN_STACK_SIZE=2176
12+
13+
# Ensure an MCUboot-compatible binary is generated.
14+
CONFIG_BOOTLOADER_MCUBOOT=y
15+
16+
# Enable flash operations.
17+
CONFIG_FLASH=y
18+
19+
# Required by the `taskstat` command.
20+
CONFIG_THREAD_MONITOR=y
21+
22+
# Support for taskstat command
23+
CONFIG_MCUMGR_GRP_OS_TASKSTAT=y
24+
25+
# Enable statistics and statistic names.
26+
CONFIG_STATS=y
27+
CONFIG_STATS_NAMES=y
28+
29+
# Enable most core commands.
30+
CONFIG_FLASH=y
31+
CONFIG_IMG_MANAGER=y
32+
CONFIG_MCUMGR_GRP_IMG=y
33+
CONFIG_MCUMGR_GRP_OS=y
34+
CONFIG_MCUMGR_GRP_STAT=y
35+
36+
# Enable logging
37+
CONFIG_LOG=y
38+
CONFIG_MCUBOOT_UTIL_LOG_LEVEL_WRN=y
39+
40+
# Disable debug logging
41+
CONFIG_LOG_MAX_LEVEL=3
42+
43+
# Enable boot requests through retained memory.
44+
CONFIG_RETAINED_MEM=y
45+
CONFIG_RETENTION=y
46+
CONFIG_NRF_MCUBOOT_BOOT_REQUEST=y
47+
48+
CONFIG_RETENTION_BOOT_MODE=y
49+
CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE=y
50+
51+
# Enable DK LED/button library
52+
CONFIG_DK_LIBRARY=y
53+
54+
# Configure bluetooth
55+
56+
CONFIG_BT=y
57+
CONFIG_BT_PERIPHERAL=y
58+
59+
# Allow for large Bluetooth data packets.
60+
CONFIG_BT_L2CAP_TX_MTU=498
61+
CONFIG_BT_BUF_ACL_RX_SIZE=502
62+
CONFIG_BT_BUF_ACL_TX_SIZE=502
63+
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
64+
65+
# Enable the Bluetooth mcumgr transport (unauthenticated).
66+
CONFIG_MCUMGR_TRANSPORT_BT=y
67+
CONFIG_MCUMGR_TRANSPORT_BT_CONN_PARAM_CONTROL=y
68+
69+
# Enable the Shell mcumgr transport.
70+
CONFIG_BASE64=y
71+
CONFIG_CRC=y
72+
CONFIG_SHELL=y
73+
CONFIG_SHELL_BACKEND_SERIAL=y
74+
CONFIG_MCUMGR_TRANSPORT_SHELL=y
75+
76+
# Enable the mcumgr Packet Reassembly feature over Bluetooth and its configuration dependencies.
77+
# MCUmgr buffer size is optimized to fit one SMP packet divided into five Bluetooth Write Commands,
78+
# transmitted with the maximum possible MTU value: 498 bytes.
79+
CONFIG_MCUMGR_TRANSPORT_BT_REASSEMBLY=y
80+
CONFIG_MCUMGR_TRANSPORT_NETBUF_SIZE=2475
81+
CONFIG_MCUMGR_GRP_OS_MCUMGR_PARAMS=y
82+
CONFIG_MCUMGR_TRANSPORT_WORKQUEUE_STACK_SIZE=4608
83+
84+
# Enable the LittleFS file system.
85+
CONFIG_FILE_SYSTEM=y
86+
CONFIG_FILE_SYSTEM_LITTLEFS=y
87+
88+
# Enable file system commands
89+
CONFIG_MCUMGR_GRP_FS=y
90+
91+
# Enable the storage erase command.
92+
CONFIG_MCUMGR_GRP_ZBASIC=y
93+
CONFIG_MCUMGR_GRP_ZBASIC_STORAGE_ERASE=y
94+
95+
# Disable Bluetooth ping support
96+
CONFIG_BT_CTLR_LE_PING=n
97+
98+
# Disable shell commands that are not needed
99+
CONFIG_CLOCK_CONTROL_NRF_SHELL=n
100+
CONFIG_DEVICE_SHELL=n
101+
CONFIG_DEVMEM_SHELL=n
102+
CONFIG_FLASH_SHELL=n
103+
104+
# Define dependencies
105+
CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="1.0.0"
106+
CONFIG_MCUBOOT_EXTRA_IMGTOOL_ARGS="--dependencies \"(1,primary,1.0.0)\""

samples/dfu/ab_split/sample.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
sample:
2+
description: AB update sample with separated slots
3+
name: ab_split
4+
common:
5+
sysbuild: true
6+
build_only: true
7+
tags:
8+
- dfu_ab
9+
- ci_samples_dfu
10+
11+
tests:
12+
sample.dfu.ab_split:
13+
sysbuild: true
14+
platform_allow:
15+
- nrf54h20dk/nrf54h20/cpuapp
16+
integration_platforms:
17+
- nrf54h20dk/nrf54h20/cpuapp

0 commit comments

Comments
 (0)