Skip to content

Commit f13c5c6

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 <tomasz.chyrowicz@nordicsemi.no>
1 parent 5cf7557 commit f13c5c6

File tree

14 files changed

+774
-0
lines changed

14 files changed

+774
-0
lines changed

CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@
498498
/samples/dect/dect_phy/dect_shell/ @nrfconnect/ncs-modem-tre
499499
/samples/dect/dect_phy/hello_dect/ @nrfconnect/ncs-modem
500500
/samples/dfu/ab/ @nrfconnect/ncs-eris
501+
/samples/dfu/ab_split/ @nrfconnect/ncs-eris
501502
/samples/dfu/dfu_target/ @nrfconnect/ncs-eris
502503
/samples/dfu/dfu_multi_image/ @nrfconnect/ncs-eris
503504
/samples/dfu/fw_loader/ @nrfconnect/ncs-eris
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: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
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 manifest-based dependency management, the :kconfig:option:`SB_CONFIG_MCUBOOT_MANIFEST_UPDATES=y` option is enabled in the :file:`sysbuild.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 firmware: slot A and slot B.
55+
The slots are equivalent, and the device can boot from either of them.
56+
In the case of MCUboot, this is achieved by using the Direct XIP feature.
57+
By design, the slot A of the application image boots the slot A of the radio image, so there is a manifest-based dependency required to correctly verify the correctness of the image pairs.
58+
There can be only one image that includes manifest TLV. Its index is configured using :kconfig:option:`SB_CONFIG_MCUBOOT_MANIFEST_IMAGE_NUMBER`.
59+
By default, the application image index (``0``) is selected. This image will be referred to as the manifest image.
60+
Thus, note that the terms slot 0, primary slot, slot A and slot 1, secondary slot, slot B are used interchangeably throughout the documentation.
61+
This configuration allows a background update of the non-active slot while the application runs from the active slot.
62+
After the update is complete, the device can quickly switch to the updated slot on the next reboot.
63+
64+
The following conditions decide which slot will be booted (active) on the next reboot:
65+
66+
1. If one of the slots of the manifest image contains a valid image, it is marked as valid only if all other images, described by the manifest are present and placed in the same slot as the manifest.
67+
#. If one of the slots of the manifest image is not valid, the other slot is selected as active.
68+
#. If both slots of the manifest image are valid, the slot marked as "preferred" is selected as active.
69+
#. If both slots of the manifest image are valid and none is marked as "preferred," the slot with the higher version number is selected as active.
70+
#. If none of the above conditions is met, slot A is selected as active.
71+
#. For all other images, the same slot is selected.
72+
73+
You can set the preferred slot using the ``boot_request_set_preferred_slot`` function.
74+
Currently, this only sets the boot preference for a single reboot.
75+
76+
Identifying the active slot
77+
---------------------------
78+
79+
If the project uses the Partition Manager, the currently running slot can be identified by checking if ``CONFIG_NCS_IS_VARIANT_IMAGE`` is defined.
80+
If it is defined, the application is running from slot B.
81+
Otherwise, it is running from slot A.
82+
83+
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 to by `zephyr,code-partition` to specific node addresses defined in the device tree.
84+
The following node partitions are used by default:
85+
86+
* ``cpuapp_slot0_partition`` - Application core, slot A
87+
* ``cpuapp_slot1_partition`` - Application core, slot B
88+
* ``cpurad_slot0_partition`` - Radio core, slot A
89+
* ``cpurad_slot1_partition`` - Radio core, slot B
90+
91+
For example, verifying that the application is running from slot A can be done by using the following macro:
92+
93+
.. code-block:: c
94+
95+
#define IS_RUNNING_FROM_SLOT_A \
96+
(FIXED_PARTITION_NODE_OFFSET(DT_CHOSEN(zephyr_code_partition)) == \
97+
FIXED_PARTITION_OFFSET(cpuapp_slot0_partition))
98+
99+
.. _ab_split_build_files:
100+
101+
Build files
102+
-----------
103+
104+
This sample overrides the default build strategy, so application and radio images are built separately.
105+
In this case, the following files should be sent to the device when performing an update:
106+
107+
* :file:`build/mcuboot_secondary_app/zephyr/zephyr.signed.bin` - Contains the slot B of the application image.
108+
This file should be uploaded to the secondary slot when the device is running from slot A.
109+
* :file:`build/ipc_radio_secondary_app/zephyr/zephyr.signed.bin` - Contains the slot B of the radio image.
110+
This file should be uploaded to the secondary slot when the device is running from slot A.
111+
* :file:`build/ab/zephyr/zephyr.signed.bin` - Contains the slot A of the application image.
112+
This file should be uploaded to the primary slot when the device is running from slot B.
113+
* :file:`build/ipc_radio/zephyr/zephyr.signed.bin` - Contains the slot A of the radio image.
114+
This file should be uploaded to the primary slot when the device is running from slot B.
115+
116+
User interface
117+
**************
118+
119+
LED 0:
120+
This LED indicates that the application is running from slot A.
121+
It is controlled as active low, meaning it will turn on once the application is booted and blinks (turns off) in short intervals.
122+
The number of short blinks is configurable using the :kconfig:option:`CONFIG_N_BLINKS` Kconfig option.
123+
It will remain off if the application is running from slot B.
124+
125+
LED 1:
126+
This LED indicates that the application is running from slot B.
127+
It is controlled as active low, meaning it will turn on once the application is booted and blinks (turns off) in short intervals.
128+
The number of short blinks is configurable using the :kconfig:option:`CONFIG_N_BLINKS` Kconfig option.
129+
It will remain off if the application is running from slot A.
130+
131+
Button 0:
132+
By pressing this button, the non-active slot will be selected as the preferred slot on the next reboot.
133+
This preference applies only to the next boot and is cleared after the subsequent reset.
134+
135+
Configuration
136+
*************
137+
138+
|config|
139+
140+
Configuration options
141+
=====================
142+
143+
Check and configure the following configuration option for the sample:
144+
145+
.. _CONFIG_N_BLINKS:
146+
147+
CONFIG_N_BLINKS - The number of blinks.
148+
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).
149+
The default value of the option is set to ``1``, causing a single blink to indicate *Version 1*.
150+
You can increment this value to represent an update, such as set it to ``2`` to indicate *Version 2*.
151+
152+
.. _CONFIG_EMULATE_APP_HEALTH_CHECK_FAILURE:
153+
154+
CONFIG_EMULATE_APP_HEALTH_CHECK_FAILURE - Enables emulation of a broken application that fails the self-test.
155+
This configuration option emulates a broken application that does not pass the self-test.
156+
157+
Additional configuration
158+
========================
159+
160+
Check and configure the :kconfig:option:`CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION` library Kconfig option specific to the MCUboot library.
161+
This configuration option sets the version to pass to imgtool when signing.
162+
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.
163+
164+
Building and running
165+
********************
166+
167+
.. |sample path| replace:: :file:`samples/dfu/ab_split`
168+
169+
.. include:: /includes/build_and_run.txt
170+
171+
Testing
172+
=======
173+
174+
To perform DFU using the `nRF Connect Device Manager`_ mobile app, complete the following steps:
175+
176+
.. include:: /app_dev/device_guides/nrf52/fota_update.rst
177+
:start-after: fota_upgrades_over_ble_nrfcdm_common_dfu_steps_start
178+
:end-before: fota_upgrades_over_ble_nrfcdm_common_dfu_steps_end
179+
180+
Instead of using the :file:`dfu_application.zip` file, you can also send the appropriate binary file directly, as described in :ref:`ab_split_build_files`.
181+
Make sure to select the correct file based on the currently running slot.
182+
183+
Dependencies
184+
************
185+
186+
This sample uses the following |NCS| library:
187+
188+
* :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: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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_IMG_NRF=y
34+
CONFIG_MCUMGR_GRP_OS=y
35+
CONFIG_MCUMGR_GRP_STAT=y
36+
37+
# Enable logging
38+
CONFIG_LOG=y
39+
CONFIG_MCUBOOT_UTIL_LOG_LEVEL_WRN=y
40+
41+
# Disable debug logging
42+
CONFIG_LOG_MAX_LEVEL=3
43+
44+
# Enable boot requests through retained memory.
45+
CONFIG_RETAINED_MEM=y
46+
CONFIG_RETENTION=y
47+
CONFIG_NRF_MCUBOOT_BOOT_REQUEST=y
48+
49+
CONFIG_RETENTION_BOOT_MODE=y
50+
CONFIG_MCUMGR_GRP_OS_RESET_BOOT_MODE=y
51+
52+
# Enable DK LED/button library
53+
CONFIG_DK_LIBRARY=y
54+
55+
# Configure bluetooth
56+
57+
CONFIG_BT=y
58+
CONFIG_BT_PERIPHERAL=y
59+
60+
# Allow for large Bluetooth data packets.
61+
CONFIG_BT_L2CAP_TX_MTU=498
62+
CONFIG_BT_BUF_ACL_RX_SIZE=502
63+
CONFIG_BT_BUF_ACL_TX_SIZE=502
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

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)