Skip to content

Commit a8f3051

Browse files
committed
samples: Add idle relocated TCM multicore test for nRF54H20
Introduce a new sample demonstrating a multicore idle test with firmware relocated to the radio core's TCM. The test showcases the radio loader pattern, where firmware is loaded from MRAM to TCM at runtime, ensuring efficient execution. JIRA: NCSDK-36461 Signed-off-by: Jan Zyczkowski <[email protected]>
1 parent 7e8bb54 commit a8f3051

File tree

22 files changed

+766
-0
lines changed

22 files changed

+766
-0
lines changed

CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,8 @@
523523
/samples/nrf5340/empty_app_core/ @nrfconnect/ncs-si-muffin
524524
/samples/nrf5340/extxip_smp_svr/ @nrfconnect/ncs-eris
525525
/samples/nrf54h20/empty_app_core/ @nrfconnect/ncs-aurora
526+
/samples/nrf54h20/idle_relocated_tcm/ @nrfconnect/ncs-si-muffin
527+
/samples/nrf54h20/radio_loader/ @nrfconnect/ncs-si-muffin
526528
/samples/ironside_se/ @nrfconnect/ncs-aurora
527529
/samples/nrf_compress/ @nordicjm
528530
/samples/nrf_profiler/ @nrfconnect/ncs-si-bluebagel
@@ -646,6 +648,7 @@
646648
/samples/net/**/*.rst @nrfconnect/ncs-cia-doc
647649
/samples/net/coap_client/*.rst @nrfconnect/ncs-iot-oulu-tampere-doc
648650
/samples/nfc/**/*.rst @nrfconnect/ncs-si-muffin-doc
651+
/samples/nrf54h20/idle_relocated_tcm/*.rst @nrfconnect/ncs-si-muffin-doc
649652
/samples/nrf5340/empty_app_core/*.rst @nrfconnect/ncs-si-muffin-doc
650653
/samples/nrf5340/extxip_smp_svr/*.rst @nrfconnect/ncs-eris-doc
651654
/samples/nrf5340/netboot/*.rst @nrfconnect/ncs-eris-doc

doc/nrf/releases_and_maturity/releases/release-notes-changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,11 @@ Other samples
855855
* Added a new testing step demonstrating how to calculate event propagation statistics.
856856
Also added the related test preset for the :file:`calc_stats.py` script (:file:`nrf/scripts/nrf_profiler/stats_nordic_presets/app_event_manager_profiler_tracer.json`).
857857

858+
* Added:
859+
860+
* The :ref:`idle_relocated_tcm_sample` sample to demonstrate how to relocate the firmware to the TCM memory at boot time.
861+
The sample also uses the ``radio_loader`` sample image (located in :file:`nrf/samples/nrf54h20/radio_loader`), which cannot be tested as a standalone sample, to relocate the firmware from the MRAM to the TCM memory at boot time.
862+
858863
Drivers
859864
=======
860865

doc/nrf/samples/other.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ This section lists single |NCS| samples for various uses that are not part of ot
2525
../../../tests/benchmarks/multicore/*/README
2626
../../../samples/zephyr/smp_svr_mini_boot/README
2727
../../../samples/basic/*/README
28+
../../../samples/nrf54h20/*/README
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
cmake_minimum_required(VERSION 3.20.0)
8+
9+
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
10+
11+
if(NOT SYSBUILD)
12+
message(FATAL_ERROR
13+
" This is a multi-image application that should be built using sysbuild.\n"
14+
" Add --sysbuild argument to west build command to prepare all the images.")
15+
endif()
16+
17+
project(idle)
18+
19+
target_sources(app PRIVATE src/main.c)
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+
source "share/sysbuild/Kconfig"
8+
9+
choice NETCORE
10+
11+
default NETCORE_CUSTOM_RADIO
12+
13+
config NETCORE_CUSTOM_RADIO
14+
bool "Custom radio"
15+
help
16+
Use custom radio.
17+
18+
endchoice
19+
20+
config NETCORE_IMAGE_NAME
21+
default "remote_rad" if NETCORE_CUSTOM_RADIO
22+
23+
config NETCORE_IMAGE_PATH
24+
default "$(ZEPHYR_NRF_MODULE_DIR)/samples/nrf54h20/idle_relocated_tcm/remote" if NETCORE_CUSTOM_RADIO
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
.. _idle_relocated_tcm_sample:
2+
3+
Multicore idle test with firmware relocated to radio core TCM
4+
#############################################################
5+
6+
.. contents::
7+
:local:
8+
:depth: 2
9+
10+
The test benchmarks the idle behavior of an application that runs on multiple cores.
11+
It demonstrates a radio loader pattern where the radio core firmware is loaded from MRAM into TCM (Tightly Coupled Memory) at runtime.
12+
13+
Requirements
14+
************
15+
16+
The test supports the following development kit:
17+
18+
.. table-from-rows:: /includes/sample_board_rows.txt
19+
:header: heading
20+
:rows: nrf54h20dk_nrf54h20_cpuapp
21+
22+
Overview
23+
********
24+
25+
This test demonstrates how to build a multicore idle application with :ref:`configuration_system_overview_sysbuild` using a two-stage boot process for the radio core:
26+
27+
#. Radio Loader - A small bootloader that runs on the radio core, copies firmware from MRAM to TCM, and jumps to it.
28+
#. Remote Firmware - The actual application that runs from TCM after being loaded.
29+
30+
The test automatically relocates the remote firmware binary to the correct MRAM address during build time, ensuring it can be loaded by the radio loader.
31+
32+
Architecture
33+
============
34+
35+
The system uses the following memory layout:
36+
37+
* **MRAM (Non-volatile):**
38+
39+
* ``cpurad_loader_partition`` @ 0x92000 - Contains the radio loader (8 KB)
40+
* ``cpurad_loaded_fw`` @ 0x94000 - Contains the remote firmware binary (128 KB)
41+
42+
* **TCM (Volatile, fast execution):**
43+
44+
* ``cpurad_ram0`` @ 0x23000000 - Code execution region (128 KB)
45+
* ``cpurad_data_ram`` @ 0x23020000 - Data region (64 KB)
46+
47+
Additional files
48+
================
49+
50+
The test comes with the following additional files:
51+
52+
* :file:`sysbuild.conf` - Enables the radio loader by setting ``CONFIG_NRF_RADIO_LOADER=y``.
53+
* :file:`boards/memory_map.overlay` - Shared memory map configuration for both loader and remote firmware.
54+
* :file:`sysbuild/radio_loader/` - Radio loader configuration overrides (:file:`prj.conf`, overlay).
55+
* :file:`sysbuild/remote_rad/` - Radio core firmware configuration overrides (:file:`prj.conf`, overlay).
56+
57+
Enabling the Radio Loader
58+
*************************
59+
60+
The radio loader is automatically added to the build when you enable it in sysbuild configuration.
61+
62+
In :file:`sysbuild.conf`:
63+
64+
.. code-block:: kconfig
65+
66+
SB_CONFIG_NRF_RADIO_LOADER=y
67+
68+
This single configuration option:
69+
70+
#. Automatically adds the ``radio_loader`` application located in the :file:`nrf/samples/nrf54h20/radio_loader` folder.
71+
#. Builds it for the CPURAD core.
72+
#. No manual ``ExternalZephyrProject_Add()`` needed in sysbuild.
73+
74+
Memory map configuration
75+
========================
76+
77+
The memory map is defined in :file:`boards/memory_map.overlay` and is shared between the radio loader and remote firmware to ensure consistency.
78+
79+
The overlay defines:
80+
81+
#. TCM regions:
82+
83+
.. code-block:: devicetree
84+
85+
cpurad_ram0: sram@23000000 {
86+
compatible = "mmio-sram";
87+
reg = <0x23000000 0x20000>; /* 128 KB for code */
88+
};
89+
90+
cpurad_data_ram: sram@23020000 {
91+
compatible = "mmio-sram";
92+
reg = <0x23020000 0x10000>; /* 64 KB for data */
93+
};
94+
95+
#. MRAM partitions:
96+
97+
.. code-block:: devicetree
98+
99+
&mram1x {
100+
/delete-node/ partitions;
101+
102+
partitions {
103+
compatible = "fixed-partitions";
104+
#address-cells = <1>;
105+
#size-cells = <1>;
106+
107+
cpurad_loader_partition: partition@92000 {
108+
label = "cpurad_loader_partition";
109+
reg = <0x92000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */
110+
};
111+
112+
cpurad_loaded_fw: partition@94000 {
113+
label = "cpurad_loaded_fw";
114+
reg = <0x94000 DT_SIZE_K(128)>; /* 128 KB fixed */
115+
};
116+
};
117+
};
118+
119+
Automatic firmware relocation
120+
*****************************
121+
122+
The remote firmware must be relocated to match the MRAM partition address where it will be stored.
123+
This is automatically done by Zephyr's ``CONFIG_BUILD_OUTPUT_ADJUST_LMA`` feature when the devicetree chosen nodes are configured correctly.
124+
125+
How it works
126+
============
127+
128+
Firmware relocation is handled automatically by Zephyr's build system using the ``CONFIG_BUILD_OUTPUT_ADJUST_LMA`` configuration option, which is configured in ``zephyr/soc/nordic/nrf54h/Kconfig.defconfig.nrf54h20_cpurad`` for all nRF54H20 CPURAD projects.
129+
130+
The configuration automatically detects the ``fw-to-relocate`` chosen node in your devicetree.
131+
When present, it calculates the LMA adjustment to relocate firmware from MRAM to TCM.
132+
Without this chosen node, firmware runs directly from the ``zephyr,code-partition`` location (standard XIP behavior).
133+
134+
Simply configure the devicetree chosen nodes correctly in your firmware's overlay:
135+
136+
.. code-block:: devicetree
137+
138+
/{
139+
chosen {
140+
/* VMA: where code runs (TCM) */
141+
zephyr,code-partition = &cpurad_ram0;
142+
zephyr,sram = &cpurad_data_ram;
143+
144+
/* LMA: where to load from (MRAM partition) - enables relocation */
145+
fw-to-relocate = &cpurad_loaded_fw;
146+
};
147+
};
148+
149+
Zephyr automatically calculates the Load Memory Address (LMA) adjustment based on your chosen nodes:
150+
151+
**With fw-to-relocate chosen node** (for radio loader pattern):
152+
153+
.. code-block:: text
154+
155+
LMA_adjustment = fw-to-relocate address - zephyr,code-partition address
156+
= cpurad_loaded_fw - cpurad_ram0
157+
= 0x94000 - 0x23000000
158+
159+
**Without fw-to-relocate** (standard behavior):
160+
161+
.. code-block:: text
162+
163+
LMA_adjustment = zephyr,code-partition address - zephyr,sram address
164+
165+
The build system then adjusts the hex file so that the firmware is loaded from MRAM (``0x94000``), but runs from TCM (``0x23000000``).
166+
167+
Building and running
168+
********************
169+
170+
.. |test path| replace:: :file:`samples/nrf54h20/idle_relocated_tcm`
171+
172+
.. include:: /includes/build_and_run_test.txt
173+
174+
Testing
175+
=======
176+
177+
After programming the test to your development kit, complete the following steps to test it:
178+
179+
1. |connect_terminal|
180+
#. Reset the kit.
181+
#. Observe the console output for both cores:
182+
183+
* For the application core, the output should be as follows:
184+
185+
.. code-block:: console
186+
187+
*** Booting nRF Connect SDK zephyr-v3.5.0-3517-g9458a1aaf744 ***
188+
build time: Nov 22 2025 17:00:59
189+
Multicore idle test on [email protected]/nrf54h20/cpuapp
190+
Multicore idle test iteration 0
191+
Multicore idle test iteration 1
192+
...
193+
194+
* For the radio core, the output should be as follows:
195+
196+
.. code-block:: console
197+
198+
*** Booting nRF Connect SDK zephyr-v3.5.0-3517-g9458a1aaf744 ***
199+
build time: Nov 22 2025 17:00:29
200+
Multicore idle test on [email protected]/nrf54h20/cpurad
201+
Current PC (program counter) address: 0x23000ae0
202+
Multicore idle test iteration 0
203+
Multicore idle test iteration 1
204+
...
205+
206+
The radio loader first loads the firmware from MRAM (``0x0e094000``) to TCM (``0x23000000``) and then jumps to the loaded firmware.
207+
This process is transparent and happens during the early boot stage.
208+
209+
#. Verify the DFU process:
210+
211+
#. Build the firmware for the secondary app slot, increase the version number in the :file:`prj.conf` file (uncomment the line):
212+
213+
.. code-block:: kconfig
214+
215+
CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="0.0.1+0"
216+
217+
#. Build the firmware:
218+
219+
.. code-block:: console
220+
221+
west build -p -b nrf54h20dk/nrf54h20/cpuapp
222+
223+
#. Program the firmware to the secondary application slot:
224+
225+
.. code-block:: console
226+
227+
nrfutil device program --firmware build/zephyr_secondary_app.merged.hex --options chip_erase_mode=ERASE_NONE
228+
229+
Reset the development kit.
230+
The firmware must boot from the secondary application slot.
231+
Observe the change in build time in the console output.

0 commit comments

Comments
 (0)