Skip to content

Commit 5d0da1b

Browse files
zyczgrochu
authored andcommitted
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 5d0da1b

File tree

22 files changed

+765
-0
lines changed

22 files changed

+765
-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: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
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+
cpurad_data_ram: sram@23020000 {
90+
compatible = "mmio-sram";
91+
reg = <0x23020000 0x10000>; /* 64 KB for data */
92+
};
93+
94+
#. MRAM partitions:
95+
96+
.. code-block:: devicetree
97+
98+
&mram1x {
99+
/delete-node/ partitions;
100+
101+
partitions {
102+
compatible = "fixed-partitions";
103+
#address-cells = <1>;
104+
#size-cells = <1>;
105+
106+
cpurad_loader_partition: partition@92000 {
107+
label = "cpurad_loader_partition";
108+
reg = <0x92000 DT_SIZE_K(8)>; /* 8 KB allocated (~4 KB actual) */
109+
};
110+
111+
cpurad_loaded_fw: partition@94000 {
112+
label = "cpurad_loaded_fw";
113+
reg = <0x94000 DT_SIZE_K(128)>; /* 128 KB fixed */
114+
};
115+
};
116+
};
117+
118+
Automatic firmware relocation
119+
*****************************
120+
121+
The remote firmware must be relocated to match the MRAM partition address where it will be stored.
122+
This is automatically done by Zephyr's ``CONFIG_BUILD_OUTPUT_ADJUST_LMA`` feature when the devicetree chosen nodes are configured correctly.
123+
124+
How it works
125+
============
126+
127+
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.
128+
129+
The configuration automatically detects the ``fw-to-relocate`` chosen node in your devicetree.
130+
When present, it calculates the LMA adjustment to relocate firmware from MRAM to TCM.
131+
Without this chosen node, firmware runs directly from the ``zephyr,code-partition`` location (standard XIP behavior).
132+
133+
Simply configure the devicetree chosen nodes correctly in your firmware's overlay:
134+
135+
.. code-block:: devicetree
136+
137+
/{
138+
chosen {
139+
/* VMA: where code runs (TCM) */
140+
zephyr,code-partition = &cpurad_ram0;
141+
zephyr,sram = &cpurad_data_ram;
142+
143+
/* LMA: where to load from (MRAM partition) - enables relocation */
144+
fw-to-relocate = &cpurad_loaded_fw;
145+
};
146+
};
147+
148+
Zephyr automatically calculates the Load Memory Address (LMA) adjustment based on your chosen nodes:
149+
150+
**With fw-to-relocate chosen node** (for radio loader pattern):
151+
152+
.. code-block:: text
153+
154+
LMA_adjustment = fw-to-relocate address - zephyr,code-partition address
155+
= cpurad_loaded_fw - cpurad_ram0
156+
= 0x94000 - 0x23000000
157+
158+
**Without fw-to-relocate** (standard behavior):
159+
160+
.. code-block:: text
161+
162+
LMA_adjustment = zephyr,code-partition address - zephyr,sram address
163+
164+
The build system then adjusts the hex file so that the firmware is loaded from MRAM (``0x94000``), but runs from TCM (``0x23000000``).
165+
166+
Building and running
167+
********************
168+
169+
.. |test path| replace:: :file:`samples/nrf54h20/idle_relocated_tcm`
170+
171+
.. include:: /includes/build_and_run_test.txt
172+
173+
Testing
174+
=======
175+
176+
After programming the test to your development kit, complete the following steps to test it:
177+
178+
1. |connect_terminal|
179+
#. Reset the kit.
180+
#. Observe the console output for both cores:
181+
182+
* For the application core, the output should be as follows:
183+
184+
.. code-block:: console
185+
186+
*** Booting nRF Connect SDK zephyr-v3.5.0-3517-g9458a1aaf744 ***
187+
build time: Nov 22 2025 17:00:59
188+
Multicore idle test on [email protected]/nrf54h20/cpuapp
189+
Multicore idle test iteration 0
190+
Multicore idle test iteration 1
191+
...
192+
193+
* For the radio core, the output should be as follows:
194+
195+
.. code-block:: console
196+
197+
*** Booting nRF Connect SDK zephyr-v3.5.0-3517-g9458a1aaf744 ***
198+
build time: Nov 22 2025 17:00:29
199+
Multicore idle test on [email protected]/nrf54h20/cpurad
200+
Current PC (program counter) address: 0x23000ae0
201+
Multicore idle test iteration 0
202+
Multicore idle test iteration 1
203+
...
204+
205+
The radio loader first loads the firmware from MRAM (``0x0e094000``) to TCM (``0x23000000``) and then jumps to the loaded firmware.
206+
This process is transparent and happens during the early boot stage.
207+
208+
#. Verify the DFU process:
209+
210+
#. Build the firmware for the secondary app slot, increase the version number in the :file:`prj.conf` file (uncomment the line):
211+
212+
.. code-block:: kconfig
213+
214+
CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="0.0.1+0"
215+
216+
#. Build the firmware:
217+
218+
.. code-block:: console
219+
220+
west build -p -b nrf54h20dk/nrf54h20/cpuapp
221+
222+
#. Program the firmware to the secondary application slot:
223+
224+
.. code-block:: console
225+
226+
nrfutil device program --firmware build/zephyr_secondary_app.merged.hex --options chip_erase_mode=ERASE_NONE
227+
228+
Reset the development kit.
229+
The firmware must boot from the secondary application slot.
230+
Observe the change in build time in the console output.

0 commit comments

Comments
 (0)