STM32N657 NUCLEO standalone ROM flash boot locks, but same FSBL works via GDB launch
Summary
On a NUCLEO-N657X0-Q I have a custom (non-CubeMX-template) FSBL that copies an
"LRUN" application image from external XSPI flash into AXISRAM and jumps to it. The
byte-identical signed FSBL runs completely when I stage it with the debugger in
Development boot (monitor reset → load → jump Reset_Handler) — the app runs end to
end. But in true ROM flash-boot (BOOT pins set for boot-from-flash, power-cycle, no
debugger), the FSBL reaches main() (user LEDs light) and then locks up before its
first clock-configuration step. The lock-up is invisible to SWD, UART, and even fault
handlers, which points at a processor LOCKUP tied to the state the boot ROM leaves at
the FSBL entry in flash-boot (security / RIF / clock), which differs from the debugger
path. I would like to understand what minimal init my FSBL must do at entry in flash-boot.
Hardware / tools
- Board: NUCLEO-N657X0-Q (MB1940), STM32N657X0H, Cortex-M55 + Neural-ART. Device ID 0x486, Rev Z. Lifecycle state: OPEN (SWD attaches in Dev boot).
- External flash: MX25UM51245G (XSPI2), external loader MX25UM51245G_STM32N6570-NUCLEO.stldr.
- Tools: STM32CubeCLT 1.21.0 (arm-none-eabi-gcc 14.3.1, CMake/Ninja), STM32CubeProgrammer 2.22.0, ST-LINK gdb server. ST-LINK FW V3J17M11.
Boot architecture (copy-to-RAM, single image, no XIP)
Boot ROM → signed FSBL (linked + executes at 0x34180000, AXISRAM2) → configures the
system clock → maps XSPI2 memory-mapped @50 MHz → copies the application image
(0x70100000 → 0x34000400, AXISRAM1) → jumps to it. External-flash map:
| address | image | signed |
|---|---|---|
| 0x70000000 | FSBL-trusted.bin (~62 KB) | yes (-hv 2.1) |
| 0x70100000 | application (raw LRUN, ~286 KB) | no |
| 0x70200000 | data blob (~5.8 MB) | no |
The FSBL is compiled for Cortex-M55 with -mcmse (secure) but currently does no SAU /
security-partition init (no partition_stm32n657xx.h; SystemInit does not call
TZ_SAU_Setup). What the FSBL does after reset: HAL_Init() → light 3 user LEDs →
HAL_RCC clock config (PLL1=800 / PLL2=600 → CPU 600 MHz, AHB 100 MHz; the ST Edge AI
"no-overdrive" tree) → XSPI2 map → copy → jump.
Signing & flashing (in Development boot, JP2 = 1)
STM32_SigningTool_CLI -bin FSBL.bin -nk -of 0x80000000 -t fsbl -o FSBL-trusted.bin -hv 2.1
STM32_Programmer_CLI -c port=SWD mode=UR --extload MX25UM51245G_STM32N6570-NUCLEO.stldr \
--download FSBL-trusted.bin 0x70000000 -v # "Download verified successfully"
What WORKS — debugger-staged launch (Development boot, JP2 = 1)
Staging the identical signed FSBL and jumping to its reset vector — which reproduces the
ROM's copy-to-RAM + jump — runs the whole chain successfully (FSBL + app, full UART output):
ST-LINK_gdbserver -d --apid 1 -e -p 61234 -cp <CubeProgrammer\bin>
arm-none-eabi-gdb FSBL.elf -ex "target extended-remote :61234" \
-ex "monitor reset" -ex "load" -ex "jump Reset_Handler"
What FAILS — true ROM flash-boot (no debugger)
Set the BOOT pins for boot-from-flash (on this board JP1 = 0, JP2 = 0), full power-cycle,
no debugger. Result: the FSBL runs (the 3 user LEDs light at main()), then locks up
before the first clock-config step (an LED probe that would turn off at clock-config entry
never executes). Evidence that it is a LOCKUP, not a recoverable hang or fault:
- SWD will not attach in flash-boot: STM32_Programmer_CLI -c port=SWD mode=HotPlug → "No STM32 target found."
- UART is silent: both HAL UART and a bare-metal, HSI-clocked, polled USART1 (PE5/PE6, no HAL/SysTick/IRQ) placed *immediately after* the (confirmed-reached) LED init emit nothing.
- Fault handlers never fire: I installed LED-encoded HardFault/MemManage/BusFault/UsageFault/SecureFault handlers (with SCB->SHCSR MEM/BUS/USG/SECUREFAULTENA set) whose first action turns all LEDs off and then blinks a code. They never run — the LEDs main() set stay frozen. A fault that never reaches its handler ⇒ processor lockup.
- 5-minute wait: no progress, no output.
What I have already ruled out
- Forcing HSI on first; an HSI-park preamble; several clock trees.
- ST-style MPU_config (mark 0x70000000 Normal/RO/exec, enable MPU).
- HAL_PWREx_ConfigSupply(PWR_EXTERNAL_SOURCE_SUPPLY) (confirmed correct supply mode for this board — external TPS62864) and __enable_irq().
- The boot provisioning is working: the ROM loads + launches the signed FSBL (main runs), so this is not a boot-address/signature problem. Option bytes are N/A (-ob displ → *"not supported for STM32N6"*; the N6 uses BSEC OTP / lifecycle).
- The same image runs fully via the gdb-staged jump Reset_Handler, so it is not the FSBL or application *logic* — it is the entry-state the ROM leaves in flash-boot.
Questions
1. In a true ROM flash-boot, what security / RIF / RISAF / clock state does the boot ROM leave at the FSBL entry that differs from the Development-boot jump Reset_Handler path, and that could cause a secure-context lockup when the FSBL accesses peripherals (USART1 / RCC) or reconfigures clocks?
2. Is there a required minimal secure init (SAU partition, RIFSC, RISAF, IAC) that an FSBL must perform at entry in flash-boot but that the debugger-staged path does not require?
3. Is a custom copy-to-RAM FSBL supported for ROM flash-boot, or must the FSBL follow ST's reference SNS secure-boot structure (secure FSBL → secure app → non-secure)?
4. Is there a documented difference in the ROM → FSBL handoff entry-state between Dev boot (debugger) and flash boot that explains *"byte-identical image runs via gdb-staged jump Reset_Handler but locks up via ROM flash-boot"*?
Any pointer to the N6 boot-from-flash FSBL requirements (beyond signing + placement at
0x70000000) would be greatly appreciated.
