Skip to content

Commit fedaf00

Browse files
committed
Add wolfBoot port for STM32N6 (NUCLEO-N657X0-Q)
Add HAL, build system, test app, and documentation for the STM32N6 (Cortex-M55) targeting the NUCLEO-N657X0-Q board. wolfBoot runs from SRAM as FSBL and boots a signed application via XIP from external NOR flash on XSPI2.
1 parent 2277dfa commit fedaf00

File tree

13 files changed

+1638
-0
lines changed

13 files changed

+1638
-0
lines changed

.github/workflows/test-configs.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,12 @@ jobs:
449449
arch: arm
450450
config-file: ./config/examples/stm32h5-tz-dualbank-otp-lms.config
451451

452+
stm32n6_test:
453+
uses: ./.github/workflows/test-build.yml
454+
with:
455+
arch: arm
456+
config-file: ./config/examples/stm32n6.config
457+
452458
stm32h7_test:
453459
uses: ./.github/workflows/test-build.yml
454460
with:

Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ ifeq ($(TARGET),sama5d3)
269269
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
270270
endif
271271

272+
ifeq ($(TARGET),stm32n6)
273+
# wolfBoot runs from SRAM, app from XIP on external NOR - no contiguous factory.bin
274+
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
275+
endif
276+
272277
ifeq ($(TARGET),rp2350)
273278
MAIN_TARGET:=include/target.h keytools wolfboot_signing_private_key.der pico-sdk-info
274279
endif
@@ -647,6 +652,12 @@ stack-usage: wolfboot.bin
647652
image-header-size: wolfboot.bin
648653
$(Q)echo $(IMAGE_HEADER_SIZE) > .image_header_size
649654

655+
## Target-specific flash targets
656+
ifeq ($(TARGET),stm32n6)
657+
flash: wolfboot.bin test-app/image_v1_signed.bin
658+
$(Q)tools/scripts/stm32n6_flash.sh --skip-build
659+
endif
660+
650661

651662
cppcheck:
652663
cppcheck -f --enable=warning --enable=portability \

arch.mk

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,17 @@ ifeq ($(ARCH),ARM)
263263

264264
endif
265265

266+
ifeq ($(TARGET),stm32n6)
267+
CORTEX_M33=1
268+
CFLAGS+=-Ihal -mcpu=cortex-m55
269+
LDFLAGS+=-mcpu=cortex-m55
270+
ARCH_FLASH_OFFSET=0x70000000
271+
WOLFBOOT_ORIGIN=0x34000000
272+
EXT_FLASH=1
273+
PART_UPDATE_EXT=1
274+
PART_SWAP_EXT=1
275+
endif
276+
266277
ifeq ($(TARGET),rp2350)
267278
CORTEX_M33=1
268279
CFLAGS+=-Ihal

config/examples/stm32n6.config

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
ARCH?=ARM
2+
TARGET?=stm32n6
3+
SIGN?=ECC256
4+
HASH?=SHA256
5+
DEBUG?=0
6+
VTOR?=1
7+
CORTEX_M0?=0
8+
CORTEX_M33?=1
9+
NO_ASM?=0
10+
NO_MPU=1
11+
EXT_FLASH?=1
12+
PART_UPDATE_EXT?=1
13+
PART_SWAP_EXT?=1
14+
SPI_FLASH?=0
15+
ALLOW_DOWNGRADE?=0
16+
NVM_FLASH_WRITEONCE?=0
17+
WOLFBOOT_VERSION?=1
18+
V?=0
19+
SPMATH?=1
20+
RAM_CODE?=0
21+
WOLFBOOT_SECTOR_SIZE?=0x1000
22+
WOLFBOOT_PARTITION_SIZE?=0x100000
23+
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x70020000
24+
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x00120000
25+
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x00010000
26+
IMAGE_HEADER_SIZE?=1024

config/openocd/openocd_stm32n6.cfg

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# OpenOCD config for NUCLEO-N657X0-Q with MX25UM51245G NOR on XSPI2
2+
3+
source [find interface/stlink.cfg]
4+
transport select swd
5+
6+
set CHIPNAME stm32n6x
7+
set WORKAREASIZE 0x10000
8+
9+
source [find target/stm32n6x.cfg]
10+
11+
# Work-area above wolfBoot SRAM region
12+
$_TARGETNAME configure -work-area-phys 0x34020000 -work-area-size $WORKAREASIZE -work-area-backup 0
13+
14+
# XSPI2 NOR flash bank (memory-mapped at 0x70000000, regs at 0x5802A000)
15+
set XSPI2_BANK_ID [llength [flash list]]
16+
flash bank $CHIPNAME.xspi2 stmqspi 0x70000000 0 0 0 $CHIPNAME.cpu 0x5802A000
17+
18+
# Mark VDDIO supplies valid (required for XSPI2 GPIO)
19+
proc pwr_enable_io_supply {} {
20+
mmw 0x5602825C 0x00040000 0 ;# RCC_AHB4ENR: PWR clock
21+
mmw 0x56024834 0x00000100 0 ;# SVMCR1: VDDIO4SV
22+
mmw 0x56024838 0x00000100 0 ;# SVMCR2: VDDIO5SV
23+
mmw 0x5602483C 0x00000300 0 ;# SVMCR3: VDDIO2SV + VDDIO3SV
24+
}
25+
26+
# Port N GPIO for XSPI2 (PN0-PN11, AF9, very high speed)
27+
proc xspi2_gpio_init {} {
28+
mmw 0x5602825C 0x00002000 0 ;# RCC_AHB4ENR: GPION clock
29+
sleep 1
30+
mmw 0x56023400 0x00AAAAAA 0x00555555 ;# MODER: AF mode
31+
mmw 0x56023408 0x00FFFFFF 0 ;# OSPEEDR: very high
32+
mmw 0x5602340C 0 0x00FFFFFF ;# PUPDR: no pull
33+
mww 0x56023420 0x99999999 ;# AFRL: AF9
34+
mww 0x56023424 0x00009999 ;# AFRH: AF9
35+
}
36+
37+
# XSPI2 init: single-SPI, /16 prescaler, NOR reset, enter mmap mode
38+
proc xspi2_init {} {
39+
mmw 0x56028260 0x00003000 0 ;# RCC_AHB5ENR: XSPI2 + XSPIM clocks
40+
mmw 0x56028248 0x00000008 0 ;# RCC_MISCENR: XSPI PHY comp clock
41+
sleep 1
42+
43+
mww 0x5802A000 0x00000000 ;# CR: disable
44+
sleep 1
45+
mww 0x5802A008 0x001A0308 ;# DCR1: DLYBYP, DEVSIZE=26, CSHT=3
46+
mww 0x5802A00C 0x0000000F ;# DCR2: prescaler /16
47+
sleep 1
48+
mww 0x5802A000 0x00000001 ;# CR: enable
49+
50+
# NOR flash software reset (0x66 + 0x99)
51+
mmw 0x5802A000 0x00000002 0 ;# abort
52+
sleep 1
53+
mww 0x5802A024 0x0000000B ;# FCR: clear flags
54+
mww 0x5802A100 0x00000001 ;# CCR: IMODE=single
55+
mww 0x5802A108 0x00000000 ;# TCR: no dummy
56+
mww 0x5802A110 0x00000066 ;# IR: Reset Enable
57+
sleep 1
58+
59+
mmw 0x5802A000 0x00000002 0 ;# abort
60+
sleep 1
61+
mww 0x5802A024 0x0000000B
62+
mww 0x5802A100 0x00000001
63+
mww 0x5802A108 0x00000000
64+
mww 0x5802A110 0x00000099 ;# IR: Reset Memory
65+
sleep 10
66+
67+
xspi2_mem_mapped
68+
}
69+
70+
# Memory-mapped fast-read mode (single-SPI, 4-byte addr, 8 dummy cycles)
71+
proc xspi2_mem_mapped {} {
72+
mmw 0x5802A000 0x00000002 0 ;# abort
73+
sleep 1
74+
mww 0x5802A000 0x30000001 ;# CR: mmap + enable
75+
mww 0x5802A100 0x01003101 ;# CCR: IMODE=1, ADMODE=1, ADSIZE=3, DMODE=1
76+
mww 0x5802A108 0x40000008 ;# TCR: DCYC=8, SSHIFT
77+
mww 0x5802A110 0x0000000C ;# IR: Fast Read 4B
78+
}
79+
80+
# Set NOR flash params manually (SFDP not readable in single-SPI mode)
81+
proc xspi2_flash_set {} {
82+
global XSPI2_BANK_ID
83+
stmqspi set $XSPI2_BANK_ID MX25UM51245G 0x4000000 0x100 0x13 0 0x12 0x60 0x1000 0x21
84+
}
85+
86+
# Full reinit for use when XSPI2 may already be configured
87+
proc xspi2_reinit {} {
88+
global XSPI2_BANK_ID
89+
pwr_enable_io_supply
90+
xspi2_gpio_init
91+
xspi2_init
92+
xspi2_flash_set
93+
flash probe $XSPI2_BANK_ID
94+
xspi2_flash_set
95+
}
96+
97+
$_TARGETNAME configure -event reset-init {
98+
global XSPI2_BANK_ID
99+
pwr_enable_io_supply
100+
xspi2_gpio_init
101+
xspi2_init
102+
xspi2_flash_set
103+
flash probe $XSPI2_BANK_ID
104+
# Re-set after probe (stmqspi driver quirk)
105+
xspi2_flash_set
106+
}
107+
108+
init

docs/Targets.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ This README describes configuration of supported targets.
4141
* [STM32F7](#stm32f7)
4242
* [STM32G0](#stm32g0)
4343
* [STM32H5](#stm32h5)
44+
* [STM32N6](#stm32n6)
4445
* [STM32H7](#stm32h7)
4546
* [STM32L0](#stm32l0)
4647
* [STM32L4](#stm32l4)
@@ -1613,6 +1614,123 @@ c
16131614
```
16141615

16151616

1617+
## STM32N6
1618+
1619+
The STM32N6 (Cortex-M55) has no internal flash — all firmware resides on external
1620+
NOR flash (Macronix MX25UM51245G, 64MB) connected via XSPI2. The on-chip Boot ROM
1621+
copies the FSBL (First Stage Boot Loader) from external flash to internal SRAM and
1622+
jumps to it. wolfBoot serves as the FSBL, performing image verification and
1623+
chain-loading the application from external flash in XIP (Execute-In-Place) mode.
1624+
1625+
Tested on: **NUCLEO-N657X0-Q** (STM32N657X0H, MB1940)
1626+
1627+
### Memory Layout
1628+
1629+
```
1630+
XSPI2 NOR Flash (memory-mapped at 0x70000000):
1631+
0x70000000 FSBL header area (128KB, future autonomous boot)
1632+
0x70010000 Swap partition (64KB, device-relative: 0x00010000)
1633+
0x70020000 Boot partition (1MB, app runs from here via XIP)
1634+
0x70120000 Update partition (1MB, device-relative: 0x00120000)
1635+
1636+
AXISRAM (0x34000000):
1637+
0x34000000 wolfBoot (loaded to SRAM via SWD or Boot ROM FSBL copy)
1638+
0x34020000 Stack / work area
1639+
```
1640+
1641+
### Build and Flash
1642+
1643+
Use the example configuration and build:
1644+
1645+
```sh
1646+
cp config/examples/stm32n6.config .config
1647+
make
1648+
make flash
1649+
```
1650+
1651+
`make flash` uses OpenOCD with the stmqspi driver to:
1652+
1. Program the signed application to NOR flash at 0x70020000
1653+
2. Load wolfBoot to SRAM at 0x34000000
1654+
3. Start wolfBoot, which verifies and boots the application via XIP
1655+
1656+
Prerequisites:
1657+
- OpenOCD 0.12+ with stm32n6x target support (build from source if needed)
1658+
- ST-Link connected to the Nucleo board
1659+
- arm-none-eabi toolchain in PATH
1660+
1661+
### Build Options
1662+
1663+
```sh
1664+
make TARGET=stm32n6 SIGN=ECC256
1665+
```
1666+
1667+
The example config uses:
1668+
- `EXT_FLASH=1` with `PART_UPDATE_EXT=1` and `PART_SWAP_EXT=1`
1669+
- Boot partition at 0x70020000 (XIP, not marked EXT)
1670+
- Update/swap partitions use device-relative offsets
1671+
- 4KB sector size (`WOLFBOOT_SECTOR_SIZE=0x1000`)
1672+
- ECC256 + SHA256 for signature verification
1673+
1674+
### XIP Constraints
1675+
1676+
Since the application executes directly from NOR flash via XSPI2 memory-mapped
1677+
mode, the following constraints apply:
1678+
1679+
- The application must NOT call `hal_init()` — XSPI2 is already configured by
1680+
wolfBoot for memory-mapped mode. Reinitializing XSPI2 would disable XIP and
1681+
crash the CPU.
1682+
- Calling `wolfBoot_success()` requires all flash write functions to be placed
1683+
in RAM (RAMFUNCTION). The HAL flash functions in `hal/stm32n6.c` need the
1684+
RAMFUNCTION attribute for this to work from an XIP application.
1685+
1686+
### Flash Script Options
1687+
1688+
The flash script supports several modes:
1689+
1690+
```sh
1691+
./tools/scripts/stm32n6_flash.sh # Build and flash all
1692+
./tools/scripts/stm32n6_flash.sh --skip-build # Flash only (existing binaries)
1693+
./tools/scripts/stm32n6_flash.sh --app-only # Flash signed app only
1694+
./tools/scripts/stm32n6_flash.sh --test-update # Flash v1 boot + v2 update
1695+
./tools/scripts/stm32n6_flash.sh --halt # Leave OpenOCD running
1696+
```
1697+
1698+
### Debugging
1699+
1700+
OpenOCD:
1701+
1702+
```sh
1703+
openocd -f config/openocd/openocd_stm32n6.cfg
1704+
```
1705+
1706+
After OpenOCD starts, connect via telnet (port 4444). To manually load wolfBoot
1707+
and start it:
1708+
1709+
```sh
1710+
reset halt
1711+
load_image wolfboot.bin 0x34000000 bin
1712+
reg msplim_s 0x00000000
1713+
reg psplim_s 0x00000000
1714+
reg msp 0x34020000
1715+
mww 0xE000ED08 0x34000000
1716+
resume <entry_address>
1717+
```
1718+
1719+
The entry address can be found with:
1720+
```sh
1721+
arm-none-eabi-nm wolfboot.elf | grep isr_reset
1722+
```
1723+
1724+
GDB:
1725+
1726+
```sh
1727+
arm-none-eabi-gdb wolfboot.elf
1728+
target remote :3333
1729+
mon halt
1730+
add-symbol-file test-app/image.elf 0x70020400
1731+
```
1732+
1733+
16161734
## STM32H7
16171735

16181736
The STM32H7 flash geometry must be defined beforehand.

0 commit comments

Comments
 (0)