Build and Load: STM32 (S/NS)
Building and loading programs with S/NS segregation on the STM32.
Overview
This document describes how to build, load, and run RTK-based programs with S/NS segregation for the Cortex-M33 STM32 series of MCUs for two scenarios:
- simple loading, without debugger
- with debugger
Tested with STM32U585 and STM32H573.
S/NS programs comprise two images, one for the Secure program and the NSC veneers, one for the Non-secure programs.
For programs without Secure/Non-secure segregation refer to Build and Load: STM32.
See also Practical Notes.
STM32 Configuration
We assume this MCU configuration:
-
TrustZone is enabled
-
the 2MB flash memory has been configured, via option bytes
- block 1 of 1 MB is Secure (address alias: 0C000000H)
- block 2 of 1 MB is Non-secure (address alias: 08100000H)
Project Set-up
-
Address ranges: see Build RTK-based Programs.
-
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>. -
For debugging, the additional tools must be installed and configured (see section Tools below).
Build and Load, no Debugging
Build the Secure Program
1. Insert Secure epilogues for each S-side module that is exposed to NS
> python -m sec-epilogue <M0>.mod <M1>.mod ...
Notes:
- this only needs to be run when a module is changed
- use
--no-clearto omit the register clearing sequence
2. Build the S program.
3. Run gen-secure to create the NSC veneers binary, and the interface modules for the NS program:
> python -m gen-secure sec/<Sprogram>.map [options]
Notes:
- options: see gen-secure
- config file: in lieu of specifying the options a configuration file can be used – example:
[gen-secure]
nsc-addr = 00C0FE000H
ns-dir = nonsec/ns_
nsc-dir = sec
const-leaf = BASE
modules =
S0
4. Make the ELF file for the S program
> python -m make-elf sec/<Sprogram>.bin:C000000 sec/NSC.bin:C0FE000
Build the Non-secure Program
5. Build the NS program
6. Make the ELF file for the NS program
> python -m make-elf nonsec/<NSprogram>.bin
Note: load address is read from the .map file
Load the Images
7. For loading, we have two options:
-
STM32CubeProgrammer GUI:
- connect via ST-Link (right top green/yellow-ish button)
- left hand side, tab "Memory & File editing"
- two new tabs => open
sec/<Sprogram>.elfandnonsec/<NSprogram>.elf - blue-ish Download button for each file
- after downloading both files, press the board reset button to start the program
-
STM32_Programmer_CLI
- run:
> STM32_Programmer_CLI.exe -c port=SWD -d nonsec/<NSprogram>.elf
> STM32_Programmer_CLI.exe -c port=SWD -d sec/<Sprogram>.elf -s
Build and Load for Debugging
Build the Secure Program
1. sec-epilogue: as above
2. Build: as above
3. gen-secure: as above
4. Run gen-rdb to create an .alst file for each module in the S program, plus _startup.alst for the startup sequence inserted by the linker at the end of the program; make-elf requires the .alst files to create symbols and DWARF debug data:
> python -m gen-rdb sec/<Sprogram>.map --rdb-dir sec/rdb --nsc-dir sec
5. Make the debug ELF file for the S program:
> python -m make-elf sec/<Sprogram>.bin:C000000 sec/NSC.bin:C0FE000 --rdb-dir sec/rdb --debug --sym-prefix S
Build the Non-secure Program
6. Build: as step 5 above in the non-debug scenario
7. Run gen-rdb to create an .alst file for each module in the NS program, plus _startup.alst:
> python -m gen-rdb nonsec/<NSprogram>.map --rdb-dir nonsec/rdb
8. Make the debug ELF file for the NS program:
> python -m make-elf nonsec/<NSprogram>.bin --rdb-dir nonsec/rdb --debug --sym-prefix NS
Load the Images
9. Load the two ELF files to the STM32:
- Refer to Debugging:
- GUI: Cortex-Debug inside VisualStudio Code
- command line: OpenOCD and GDB
Tools
Examples (Repository)
<repo-root>/examples/v3.1/stm/u585i-iot/Secure5<repo-root>/examples/v3.1/stm/h573i-dk/Secure5
Last updated: 17 April 2026