Build, Load & Debug: RP2350 (S/NS)
Build, load, and debug programs with S/NS segregation on RP2350
Overview
This document describes how to build, load, and run RTK-based programs with S/NS segregation for the RP2350 for debugging.
-
S/NS programs comprise two ELF files, one for the Secure program and the NSC veneers, one for the Non-secure program.
-
Since two images must be loaded, the UF2 path is not available – ELF binaries via the debugger (or
picotoolfor the partition-table case) are the load format. -
make-elf creates the ELF files. It creates and embeds the necessary DWARF debug data. Note that the executable binaries are 100% the same with or without debug data, and consequently there is no "debug overhead" with debug data included if run outside a debugger.
-
The S image is the bootable image and includes the
IMAGE_DEFmetadata block; the NS image is loaded by the S image and does not needIMAGE_DEF. The framework default is Path A (see IMAGE_DEF). -
Other guides:
- Secure/Non-secure without debugging: Build & Load: RP2350 (S/NS)
- Non-S/NS, without debugging: Build & Load: RP2350
- Non-S/NS, with debugging: Build, Load & Debug: RP2350
See also Practical Notes.
Set-up
Prerequisites
The build and debug tools must be set up as explained in:
Flash Layout
RP2350 S/NS programs can be built for two flash layouts:
-
without flash partitions – single contiguous flash region; both images use absolute addresses.
-
with flash partitions – the S image and NS image live in separate partitions; the S image configures QMI address translation so the CPU fetches NS code from a translated virtual address.
Two reference example programs illustrate the difference:
<repo>/examples/v3.1/rpi/pico2/Secure– without flash partitions<repo>/examples/v3.1/rpi/pico2/SecurePart– with flash partitions
See Compile and Link: RP2350 for the address-range tables.
Project
-
Directories:
- S program in
<project-dir>/sec - NS program in
<project-dir>/nonsec
- S program in
-
Commands as shown are run with
cwd = <project-dir>. -
Two Astrobe configuration files are required, one for the Secure and one for the Non-secure program. An easy way to provide the configuration files is to place them directly in the project directories
secandnonsec, where they can be picked up by the build scripts. -
Refer to Compile and Link: RP2350 for the address ranges as used by the example programs.
Steps
1. Build the ELF Files
Building the two debug ELF files for the Secure and the Non-secure program is a multi-step process, which is best implemented and executed using a build script.
The S/NS example programs provide build-db-elf.cmd, which builds both the Secure and Non-secure debug ELF binaries, called S-program.elf and NS-program.elf below. This script can serve as basis for your own projects and programs.
To continue, the build must complete without errors or alerts; warnings are OK.
2. Load the ELF Files
The ELF files are loaded by the debugger:
- GUI: Cortex-Debug inside Visual Studio Code – see Debugging § VS Code + Cortex-Debug
- command line: OpenOCD and GDB – see Debugging § GDB Command Line
Hence, with a partition table:
- put the RP2350 in
BOOTSELmode, which mounts the virtual volumeRP2350 - load both images with
picotoolas below - use the attach flow in Debugging § Loading Without Flashing (Attach)
For loading into partitions (assuming partition 0 for S, partition 1 for NS):
picotool load -p 1 nonsec/<NS-program>.elf -v
picotool load -p 0 sec/<S-program>.elf -v -x
Inside the Build Script
The build script executes the following steps. Upon error, the script terminates.
-
Compile the Secure program, running AstrobeBuild, which recursively compiles all modules as needed.
-
Run sec-epilogue to add the Secure epilogues to all procedures that are exposed to the Non-secure world.
-
Re-compile the Secure program to ensure that it contains the Secure epilogues.
-
Link the Secure program, running AstrobeLink.
-
Run gen-secure to create the Non-secure Callable (NSC) binary, containing one gateway veneer block per procedure exposed to the Non-secure world, plus the interface modules for the Non-secure code to call into the Secure world via the gateways.
-
Run gen-rdb to create an
.alstfile for each module in the Secure program, plus_startup.alstfor the start-up sequence inserted by the linker at the end of the program;make-elfrequires the.alstfiles to create symbols and DWARF debug data. -
Run make-elf to create the Secure debug ELF binary in
sec, with the NSC binary embedded, theIMAGE_DEFblock prepended (--image-def), DWARF debug data, and symbol prefixS. -
Compile the Non-secure program, running AstrobeBuild.
-
Link the Non-secure program, running AstrobeLink.
-
Run gen-rdb to create the
.alstfiles for the Non-secure program. -
Run make-elf to create the Non-secure debug ELF binary in
nonsec, with DWARF debug data and symbol prefixNS. NoIMAGE_DEFis needed – the NS image is loaded by the S image rather than booted by the boot ROM.
Last updated: 17 May 2026