In this exercise, we will learn how to add a custom Sysbuild image. As previously mentioned, the default images that come with the nRF Connect SDK are recommended for most use cases. In some advanced cases, you may want to create a custom image.
We will create a custom image that can run on either the nRF54L15 FLPR core or the nRF5340 network core, in addition to the regular application image that operates on the application core. This exercise will not cover the process of adding custom images for the same core, such as custom bootloaders.
Documentation on sysbuild images can be found under Sysbuild images docs. This exercise is loosely based on the Sysbuild Hello World sample.
This exercise is only supported on the nRF54L15 DK and the nRF5340 DK.
In this exercise, we are working with two images running on two different cores. This capability is currently available only on the nRF54L Series (nRF54L15, nRF54L10, nRF54L05 SoCs) and the nRF53 Series (nRF5340 SoC).
Series | Application Core | Extra “Secondary” core |
nRF54L | CPUAPP – Arm Cortex®-M33 processor | FLPR – VPR CPU (RISC-V architecture) |
nRF53 | CPUAPP – Arm Cortex®-M33 processor | CPUNET- Arm Cortex®-M33 processor |
1. In this exercise, we have two applications: l8_e2
, which is the normal one we expect to run on the application core, and custom_image
, which will run on the secondary core. Below is the folder structure for the two applications. They both live in the l8
directory.
1.1 Build l8_e2
for the application core.
First, just to warm up, we will build l8_e2
for the application core. Build and run this project as is for either nRF54l15dk/nrf54l15/cpuapp
or nrf5340dk/nrf5340/cpuapp
(depending on the board you are using) and flash it to your device.
View the terminal output, which should look like below
*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
This application is running on the Application Core (CPUAPP)
Hello from DevAcademy Intermediate, Lesson 8, Exercise 2
LED status: OFF
LED status: ON
LED status: OFF
LED status: ON
TerminalThe application prints log statements and toggles an LED every five seconds to demonstrate that something is running on the application core.
1.2 Build custom_image
for the application core.
The custom_image
application is a standalone nRF Connect SDK application that will print the Nordic logo in ASCII, do basic mathematical functions, and print over UART. The code provided for the custom_image
serves as a demonstration of something that can run on the core.
This project is not limited to secondary cores, therefore, we can now build and flash this to the application core, as we did with the other image in 1.1. It should log the following:
*** Booting nRF Connect SDK v2.9.0-7787b2649840 ***
*** Using Zephyr OS v3.7.99-1f8f3dc29142 ***
+---------------------------------------------------------------------------+
| |
| #### :::### |
| ############ :::::::###### |
| #################### :::::::::::########## |
| ############################ :::::::::::::::############## |
| ###################################:::::::::::::::################# |
| ::::###################################:::::::::::################# |
| ::::::::###################################:::::::################# |
| ::::::::::::###################################:::################# |
| ::::::::::::::::################################################### |
| ::::::::::::::::::::############################################### |
| ::::::::::::::::::::::::########################################### |
| ::::::::::::::::::::::::::::####################################### |
| ::::::::::::::::::::::::::::::::################################### |
| ::::::::::::::::::::::::::::::::::::############################### |
| ::::::::::::::::::::::::::::::::::::::::########################### |
| ::::::::::::::::::::::::::::::::::::::::::::####################### |
| ::::::::::::::::::::::::::::::::::::::::::::::::################### |
| :::::::::::::::::##::::::::::::::::::::::::::::::::################ |
| :::::::::::::::::#####:::::::::::::::::::::::::::::::::############ |
| :::::::::::::::::#########:::::::::::::::::::::::::::::::::######## |
| :::::::::::::::::##############:::::::::::::::::::::::::::::::::### |
| ::::::::::::::############## ::::::::::::::::::::::::::::: |
| ::::::::::########## :::::::::::::::::::::: |
| ::::::###### :::::::::::::: |
| ::## ::::::: |
| |
| @@ @@ @@@@@ @@@@@@ @@@@@@@ @@ @@@@@ |
| @@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ |
| @@ @@ @@ @@ @@ @@@@@@ @@ @@ @@ @@ |
| @@ @@@@ @@ @@ @@ @@ @@ @@ @@ @@ @@ |
| @@ @@ @@@@@ @@ @@ @@@@@@@ @@ @@@@@ |
| |
| S E M I C O N D U C T O R |
| |
+---------------------------------------------------------------------------+
Starting Benchmark Iteration: 1
Running Mathematical tasks...
[...]
TerminalThe logical next warm-up step would be to run the custom_image
on the secondary core. However, we will not do this because the secondary cores require some startup code from the application core, which makes it hard to run code on only the secondary cores. Instead, we will go straight to running code on both cores simultaneously: l8_e2
on the application core and custom_image
on the secondary core.
2. Following Sysbuild docs on Adding custom images, we first add a sysbuild.cmake
file to the l8_e2
application image. The l8_e2
application will be the image to drive the Sysbuild system. The sysbuild.cmake
file should contain the following
# STEP 2.1 - Add external project as sysbuild image for the FLPR core or Network Core
CMake2.1 Next, we add the CMake code, which includes custom_image
as a Sysbuild image. This will tell the Sysbuild build system to build both images and flash both images when we build and flash from VS Code or when we run west build
and west flash
.
# STEP 2.1 - Add external project as sysbuild image for the FLPR core or Network Core
ExternalZephyrProject_Add(
APPLICATION custom_image
SOURCE_DIR ${APP_DIR}/../custom_image
BOARD nrf54l15dk/nrf54l15/cpuflpr
)
CMake# STEP 2.1 - Add external project as sysbuild image for the FLPR core or Network Core
ExternalZephyrProject_Add(
APPLICATION custom_image
SOURCE_DIR ${APP_DIR}/../custom_image
BOARD nrf5340dk/nrf5340/cpunet
)
CMakeNote: For the network core specifically, the Sysbuild images docs has a section on Adding custom network core images, which uses Kconfig.sysbuild
instead of sysbuild.cmake. Both methods work, but in this course, we chose the sysbuild.cmake
method to keep the FLPR and Netcore as similar as possible.
The key CMake function here is ExternalZephyrProject_Add()
– which adds an extra project to the Sysbuild build system.
Key parameters:
APPLICATION
– Name of the application being builtSOURCE_DIR
– Specifies the path to the source code. We are using ${APP_DIR}
as a reference point to the current “main image” directory. You can specify other locations using this parameter. BOARD
– Specifies the board target (FLPR core of nRF54L Series) or (Net Core on the nRF53 Series)
To enable the Partition Manager with Sysbuild, you need to add extra lines in sysbuild.cmake
. These lines are located here in the Sysbuild Hello World sample.
2.2 The Sysbuild Hello World sample configures several settings related to the Partition Manager. However, to simplify this exercise, we will disable the Partition Manager instead. Remember, these lines can be easily reintroduced in sysbuild.cmake
if you decide to use the Partition Manager in the future. Please add the following to the sysbuild.conf
file to disable the Partition Manager:
# STEP 2.2 - Disable the Partition Manager
SB_CONFIG_PARTITION_MANAGER=n
Kconfig3.0 Next up we need to add code to the application core to initialize the secondary core.
3.1 Documentation on the FLPR core can be found at Working with the FLPR core. To enable the FLPR core from the application core, Nordic supplies a FLPR snippet. However, if the snippet is added to the project using the nRF Connect for VS Code extention , it is applied to all images. We only want the FLPR snippet applied to the application core image (l8_e2
) only and not to the custom_image
. This can either be done with the CMake argument -Dl8_e2_SNIPPET=nordic-flpr
, or by adding the FLPR DTS overlays manually to the application. We will do the latter in this exercise.
3.2 Add the following, based on the nordic-flpr
snippet, to boards/nrf54l15dk_nrf54l15_cpuapp.overlay
.
// STEP 3.2 - Add overlay to enable FLPR core
/ {
soc {
reserved-memory {
#address-cells = <1>;
#size-cells = <1>;
cpuflpr_code_partition: image@165000 {
/* FLPR core code partition */
reg = <0x165000 DT_SIZE_K(96)>;
};
};
cpuflpr_sram_code_data: memory@20028000 {
compatible = "mmio-sram";
reg = <0x20028000 DT_SIZE_K(96)>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x20028000 0x18000>;
};
};
};
&uart30 {
status = "reserved";
};
&cpuapp_sram {
reg = <0x20000000 DT_SIZE_K(160)>;
ranges = <0x0 0x20000000 0x28000>;
};
&cpuflpr_vpr {
status = "okay";
execution-memory = <&cpuflpr_sram_code_data>;
source-memory = <&cpuflpr_code_partition>;
};
&cpuapp_vevif_tx {
status = "okay";
};
CMake3.1 To start the network core on application core startup, add the following to boards/nrf5340dk_nrf5340_cpuapp.conf
:
# Step 3.1 - Enable Network Core on application core startup
CONFIG_SOC_NRF53_CPUNET_ENABLE=y
CMake4.0 Now we can build and flash the project as normal from VS Code. Make sure to do a Pristine Build for cpuapp
and flash using the normal method.
The APPLICATIONS view in nRF Connect for VS Code should look like below (if built for the nRF54L15 DK) :
4.1 Open both VCOMs from the CONNECTED DEVICES view. We will now see logs on one VCOM from the application core and from another VCOM from the secondary core. You should see the following:
4.2 The Network core use its UART0 to log by default and the FLPR core will use UART30 to log by default. These UARTs are routed to a VCOM on the DK. This is why we can read logs from both cores at the same times without we having to add anything extra to the projects.
If you want logging on other pins, you can add this to overlays in custom_image
as you would do with a normal project. For the FLPR core, you must remember to reserve peripherals used by the FLPR core in the application core overlay so you can see what has been done above for UART30. Please note that IPC between the FLPR and the application core is not covered in this lesson.