This topic focuses on some key concepts related to defining custom board definitions for SoCs with multiple board targets, like the nRF54L, nRF53, and nRF91.
In terms of custom board definitions, a significant difference between the nRF52 Series and the nRF54L/nRF53/nRF91 Series is the architecture and CPU they use. The nRF52 Series implements the Armv7-M architecture and has a Cortex-M4 CPU, whereas the nRF54L, nRF53, and nRF91 Series all implement the Armv8-M architecture and has a Cortex-M33 CPU with TrustZone, which supports TF-M.
| Series | CPU | Architecture | Number of user-programmable cores | TrustZone |
|---|---|---|---|---|
| nRF52 | Cortex-M4 | Armv7-M | 1 | No |
| nRF54L | Cortex-M33 & Nordic FLPR | Armv8-M & RISC-V (VPR) | 2 | Yes |
| nRF53 | Cortex-M33 | Armv8-M | 2 | Yes |
| nRF91 | Cortex-M33 | Armv8-M | 1 | Yes |
In addition to TF-M, the nRF53 Series features dual cores, each fully user-programmable. Furthermore, the nRF54L includes a RISC-V co-processor (Fast Lightweight Peripheral Processor – FLPR). This introduces some challenges when defining a custom board, which we will address in this topic and in Exercise 2.
Trusted Firmware-M (TF-M)
Trusted Firmware-M (TF-M) is a blueprint for constructing a Secure Processing Environment (SPE) tailored to Arm M-profile architectures. TF-M relies on the principle of security through separation to safeguard sensitive credentials and code. Additionally, TF-M extends its protective capabilities to applications by offering security services, including Protected Storage, Cryptography, and Attestation.
The Nordic Semiconductor SoC Series that implements the Armv8-M architecture (Arm Cortex-M33) all incorporate TrustZone technology. This technology enforces hardware-based segregation between Secure and Non-Secure Processing Environments, effectively creating separate Trusted and Non-Trusted build images.

This means that we have two options when building applications for boards based on the nRF54L, nRF53, and nRF91 Series.
- Option 1: Security by separation
- Board target:
<board_target>/ns - Enforce security by separation by utilizing TF-M and have our application run in the Non-Secure Processing Environment while TF-M runs in the Secure Processing Environment. When building for this target, the application will be built as a Non-Secure image. Hence, you will get security by separation as TF-M will automatically be built as the Secure image. The two images will be merged to form a combined image that will be used when programming or updating the device.
- Board target:

<board_target>/ns- Option 2: No security by separation
- Board target:
<board_target> - Do not enforce security by separation by having our application run as a single image with full access privileges. When building for this target, the application is built as a single image without security by separation.
- Board target:

<board_target>Working with specific SoCs
nRF53 Series
The nRF5340 is the only System on Chip (SoC) in the nRF53 Series. It is a wireless ultra-low-power multicore SoC with two fully programmable Arm Cortex-M33 processors: a network core and an application core.
Network core: An Arm Cortex-M33 processor with a reduced feature set designed for ultra-low-power operation. It can be used for radio communication and real-time processing tasks involving low-level radio protocol layers.
- Build target:
<board_target>/cpunet
Application core: A full-featured Arm Cortex-M33 processor that includes DSP instructions and FPU. Use this core for tasks that require high performance and for application-level logic.
The M33 TrustZone, one of the Cortex-M Security Extensions (CMSE), can divide the application MCU into Secure Processing Environment (SPE) and Non-Secure Processing Environment (NSPE). When the MCU boots, it always starts executing from the secure area.
- Build targets:
<board_target>/cpuapp(TF-M disabled).<board_target>/cpuapp/ns(TF-M enabled, SPE firmware alongside the NSPE firmware).
See the nRF5340 Product Specification for more information about the nRF5340 SoC
nRF91 Series
The nRF91 Series is comprised of four members: nRF9160, nRF9161, nRF9131, and nRF9151 System in Packages (SiP). These are cellular ultra-low-power SiPs with only one fully programmable Arm Cortex-M33 core. The other core is dedicated to the Modem firmware; you can only flash it with a precompiled modem firmware binary.
- Build targets:
(TF-M disabled).<board_target>(TF-M enabled, SPE firmware alongside the NSPE firmware).<board_target>/ns
nRF54L Series
The nRF54L15, together with the nRF54L10 and nRF54L05, make up the nRF54L Series. All nRF54L Series SoCs integrate an Arm Cortex-M33 application processor and a RISC-V coprocessor. The RISC-V coprocessor is called Fast Lightweight Peripheral Processor (FLPR), which is designed to address challenges associated with time-critical tasks that need to be managed concurrently with the main processor. In certain situations, it can serve as a replacement for an external MCU used to meet these requirements.
In nRF Connect SDK/Zephyr, code could run on nRF54L SoCs on either the Arm Cortex-M33 application core (cpuapp) or the RISC-V coprocessor (cpuflpr).
Application core (Arm Cortex-M33)
- Build targets:
<board_target>/cpuapp(TF-M disabled).<board_target>/cpuapp/ns(TF-M enabled, SPE firmware alongside the NSPE firmware).
RISC-V coprocessor (FLPR)
Building for the FLPR core is slightly different from the default nRF Connect SDK procedure. Using the FLPR core also requires additional configurationS to enable it. Building the FLPR target is similar to the application core, however, the application core build must incorporate an overlay that enables the FLPR core.
- Build targets:
(FLPR runs from SRAM, which is the recommended method. To build FLPR image with this variant, the application core image must include the<board_target>/cpuflprnordic-flprsnippet.)(FLPR runs from RRAM. To build FLPR image with this variant, the application core image must include the<board_target>/pr/xipcpuflnordic-flpr-xipsnippet.)
Enabling TF-M in board definition
The custom board directory is a single folder with both build target files (< & >board_target<) in one folder. Consider the board “>/nsboard_targetDevAcademy L3E2” with the nRF9151 SiP onboard, which we will create in Exercise 2.
Custom board Kconfig and metadata files
1. board.yml metadata file needs to include the ns variant.
Below is a snippet for the custom board “DevAcademy L3E2“.
board:
name: devacademyl3e2
vendor: nordic
socs:
- name: nrf9151
variants:
- name: 'ns'2. A single Kconfig.defconfig file that should detect the passed normalized build target BOARD_DEVACADEMYL3E2_NRF9151_NS or BOARD_DEVACADEMYL3E2_NRF9151 and adjust the FLASH_LOAD_SIZE FLASH_LOAD_OFFSET accordingly.
For the secure board version, firmware is linked at the flash’s start or in the devicetree defined code-partition for MCUboot loading. When combined with a non-secure image, the secure firmware must fit within its code partition. For the non-secure board version, firmware must always be linked to the non-secure devicetree defined code-partition. This is done by setting Kconfig symbols based on devicetree partition details (step 4).
Below is a snippet of a Kconfig.defconfig for the “DevAcademy L3E2” board.
# nRF9151 DK NRF9151 board configuration
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
if BOARD_DEVACADEMYL3E2_NRF9151 || BOARD_DEVACADEMYL3E2_NRF9151_NS
# For the secure version of the board the firmware is linked at the beginning
# of the flash, or into the code-partition defined in DT if it is intended to
# be loaded by MCUboot. If the secure firmware is to be combined with a non-
# secure image (TRUSTED_EXECUTION_SECURE=y), the secure FW image shall always
# be restricted to the size of its code partition.
# For the non-secure version of the board, the firmware
# must be linked into the code-partition (non-secure) defined in DT, regardless.
# Apply this configuration below by setting the Kconfig symbols used by
# the linker according to the information extracted from DT partitions.
# Workaround for not being able to have commas in macro arguments
DT_CHOSEN_Z_CODE_PARTITION := zephyr,code-partition
config FLASH_LOAD_SIZE
default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION))
depends on BOARD_NRF9151DK_NRF9151 && TRUSTED_EXECUTION_SECURE
if BOARD_NRF9151DK_NRF9151_NS
config FLASH_LOAD_OFFSET
default $(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_CODE_PARTITION))
config FLASH_LOAD_SIZE
default $(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_CODE_PARTITION))
endif # BOARD_NRF9151DK_NRF9151_NS
config BT_HCI_VS
default y if BT
config BT_WAIT_NOP
default BT && $(dt_nodelabel_enabled,nrf5340_reset)
config I2C
default $(dt_compat_on_bus,$(DT_COMPAT_NXP_PCAL6408A),i2c)
endif # BOARD_DEVACADEMY_NRF9151DK_NRF9151 || BOARD_DEVACADEMY_NRF9151DK_NRF9151_NS
Kconfig3. Two _defconfig files, one for each board target: devacademyl3e2_nrf9151_ns_defconfig and devacademyl3e2_nrf9151_defconfig.
In addition to what we discussed in Creating board files, we need to do the following:
3.1 In the file, we need to enable devacademyl3e2_nrf9151_defconfigCONFIG_ARM_TRUSTZONE_M.
# SPDX-License-Identifier: Apache-2.0
# Enable MPU
CONFIG_ARM_MPU=y
# Enable hardware stack protection
CONFIG_HW_STACK_PROTECTION=y
# Enable TrustZone-M
CONFIG_ARM_TRUSTZONE_M=y
# Enable GPIO
CONFIG_GPIO=y
# Enable UART driver
CONFIG_SERIAL=y
# Enable console
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
Kconfig3.2 In the file, we need to enable both _nrf9151_ns_defconfigdevacademyl3e2
to enable TrustZone APIs for the non-secure domain (Application).CONFIG_ARM_TRUSTZONE_MCONFIG_TRUSTED_EXECUTION_NONSECUREto imply building Non-Secure firmware.
A Non-Secure firmware image will execute in the Non-Secure state. Therefore, it shall not access CPU resources (memory areas, peripherals, interrupts etc.) belonging to the Secure domain.
# SPDX-License-Identifier: Apache-2.0
# Enable MPU
CONFIG_ARM_MPU=y
# Enable hardware stack protection
CONFIG_HW_STACK_PROTECTION=y
# Enable TrustZone-M
CONFIG_ARM_TRUSTZONE_M=y
# This board implies building Non-Secure firmware
CONFIG_TRUSTED_EXECUTION_NONSECURE=y
# Enable GPIO
CONFIG_GPIO=y
# Enable UART driver
CONFIG_SERIAL=y
# Enable console
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
KconfigCustom board Devicetree files
4. Building an application with TF-M results in building both Secure and Non-Secure images.
The secure image should be placed in flash0 (or in slot0, if the MCUboot bootloader is present). Secure image will use sram0_s for system memory. The Non-Secure image should be placed in slot0_ns, and use sram0_ns for system memory. This can be done by including the SoC default partitioning .dtsi file available in the SDK (<SDK Installation Path>/dts/common/nordic).
4.1 Create a common Devicetree file (see Exercise 2 source code). In the common Devicetree file, two devicetree files need to be included:_nrf9151_common.dtsidevacademyl3e2
- One common pinctrl file
devacademy_nrf9151_common-pinctrl.dtsi(See Exercise 2 source code).
- Default memory partition configuration file for the SoC, for the nRF9151:
#include <common/nordic/nrf91xx_partition.dtsi>
For use-cases where Multi-image build is utilized, the partitioning information provided in the Devicetree is ignored (aka the DTS partitioning). Instead, the Partition Mananger controls the partitions. This will be covered in-depth in Lesson 9 – Bootloaders and DFU/FOTA.
4.2 Create a per-image Devicetree file ( and _nrf9151.dtsdevacademyl3e2) to select the chosen nodes for flash and RAM and disable peripherals allocated to the other image._nrf9151_ns.dtsdevacademyl3e2
Example :_nrf9151.dtsdevacademyl3e2
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/dts-v1/;
#include <nordic/nrf9151_laca.dtsi>
#include "devacademyl3e2_nrf9151_common.dtsi"
/ {
chosen {
zephyr,sram = &sram0_s;
zephyr,flash = &flash0;
zephyr,code-partition = &slot0_partition;
zephyr,sram-secure-partition = &sram0_s;
zephyr,sram-non-secure-partition = &sram0_ns;
};
};
DevicetreeExample :_nrf9151_ns.dtsdevacademyl3e2
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
/dts-v1/;
#include <nordic/nrf9151ns_laca.dtsi>
#include "devacademyl3e2_nrf9151_common.dtsi"
/ {
chosen {
zephyr,flash = &flash0;
zephyr,sram = &sram0_ns_app;
zephyr,code-partition = &slot0_ns_partition;
};
};
/* Disable UART1, because it is used by default in TF-M */
&uart1 {
status = "disabled";
};
Devicetree