7.6 KiB
Unbricking the STM32N6 (TSV + system DFU)
Use this when OBL or BF in XSPI flash is broken and the board no longer
boots into a usable state — bl rom from the BF CLI, OBL DFU on a
crashed BF, and SWD-load workflows are all unavailable. The boot ROM's
built-in system DFU is always reachable, but it can't write the on-board
XSPI flash on its own; CubeProgrammer drives it through a TSV that
stages two helper binaries into RAM first.
Why the on-chip DFU can't just write XSPI
The N6 boot ROM exposes a system DFU bootloader (0483:DF11 with the
ST descriptor "STM32 BOOTLOADER", reached via BOOT0=DEV) but the alts
it offers are RAM- and OTP-shaped:
@FSBL /0x34180400/01*512Kg -- staged FSBL → AXISRAM2 secure
@RSSE_FW ...
@RSSE_BLOB ...
@RSSE_PLUGIN ...
@virtual ...
There's no @nor0 alt and no XSPI alt — the ROM has no XSPI driver. To
write nor0 you have to:
- Upload a signed FSBL into RAM via the
@FSBLalt. The ROM verifies it, copies it to AXISRAM2, and runs it. - The FSBL you upload is itself a DFU loader (ST's "OpenBootloader")
that exposes
@nor0plus an "external memory loader" alt for the chosen flash chip's driver. - Upload the matching XSPI flash driver into RAM via the
@External memory loaderalt; the OpenBootloader links it in and the rest of the DFU session can read/write nor0. - Now write your application binary to nor0 at the right offset.
The TSV (Target Sequence Vector) file is just a script for
STM32_Programmer_CLI -d <FlashLayout.tsv> that orchestrates these
four steps in order so it looks like a single flash operation from the
host's point of view.
When to use this
bl romfrom BF CLI / OBL DFU:leavedoesn't reboot the chip into a working state.- BF crashes early enough that the BF↔OBL IWDG-recovery path doesn't trigger (e.g., a fault before OBL's iwdg_start runs, or OBL itself is corrupt).
- You want to nuke and re-flash both OBL and BF from a clean slate.
If the chip is reachable via SWD (BOOT1 in the position that bypasses the FSBL on the dev kit, or BF still alive enough that OBL DFU comes up), prefer the SWD-load or OBL-DFU paths — they don't require touching hardware switches.
What you need
- STM32CubeProgrammer 2.18+ with the N6 patches installed. The Linux build prior to 2.22 has bugs around the N6 external-loader workflow; current ST tooling works.
OpenBootloader_STM32N6570-DK-trusted.stm32— ST's signed OpenBootloader image. Ships in CubeN6 atlib/modules/STM32N6/Projects/STM32N6570-DK/Applications/OpenBootloader/Binaries/NOR_Binary/.MX66UW1G45G_STM32N6570-DK.bin— XSPI flash driver matching the on-board MX66UW1G45G. Same directory in CubeN6.- The binaries you want in nor0:
obl_mx66uw1g45g_signed.stm32— our OBL, output ofmake -C lib/main/STM32/n6_obl signed.- Optionally
betaflight_<version>_STM32N657_<config>.bin— your BF build, if you're flashing OBL + BF together. Skip when you want only the OBL written and the BF slot zeroed (next section).
Recovery image variants
| Variant | What lands in nor0 | When to use |
|---|---|---|
| OBL + BF combined | OBL at 0x0..0x87A0, zeros to 0x100000, BF at 0x100000+ |
Normal flash after both binaries are ready. |
| OBL only, BF erased | OBL at 0x0..0x87A0, zeros from end-of-OBL through 0x200000 |
After an OBL change that may make BF crash on first boot (e.g. when OBL now transfers to BF in NS state). The empty BF slot fails OBL's vector-table validity check, so the next boot lands straight in OBL DFU recovery — no IWDG round-trip needed. |
Combined image construction (OBL + BF)
cp lib/main/STM32/n6_obl/prebuilt/obl_mx66uw1g45g_signed.stm32 /tmp/obl_bf_combined.bin
truncate -s 1048576 /tmp/obl_bf_combined.bin
cat obj/betaflight_*_OPENN657V1.bin >> /tmp/obl_bf_combined.bin
Layout to use: lib/main/STM32/n6_fsbl/FlashLayout_OBL.tsv.
OBL-only image construction (BF slot erased)
install -m 0644 lib/main/STM32/n6_obl/prebuilt/obl_mx66uw1g45g_signed.stm32 \
lib/main/STM32/n6_obl/prebuilt/obl_only_combined.bin
truncate -s 2097152 lib/main/STM32/n6_obl/prebuilt/obl_only_combined.bin
The 2 MiB size covers both the 1 MiB OBL slot and the 1 MiB BF slot with
a single contiguous write at nor0 offset 0; everything past the OBL
payload is zero from truncate, so the BF slot lands erased.
Layout to use: lib/main/STM32/n6_fsbl/FlashLayout_OBL_only.tsv.
TSV layout
Save as Unbricking.tsv next to OpenBootloader_STM32N6570-DK-trusted.stm32
and MX66UW1G45G_STM32N6570-DK.bin, then edit the two
<...your-path...> lines to point at your OBL and BF artefacts.
#Opt Id Name Type IP Offset Binary
P 0x1 fsbl-openbl Binary none 0x0 OpenBootloader_STM32N6570-DK-trusted.stm32
P 0x3 fsbl-extfl Binary none 0x0 MX66UW1G45G_STM32N6570-DK.bin
P 0x2 obl-app Binary nor0 0x0 <path/to>/obl_mx66uw1g45g_signed.stm32
P 0x4 bf-app Binary nor0 0x100000 <path/to>/obj/betaflight_<version>_STM32N657_<config>.bin
Columns:
Opt:P= program (write);PE= program + erase first.Id: ST's partition ID. The OpenBootloader recognises:0x1→ @FSBL: stage a signed FSBL image to AXISRAM2.0x2→ nor0 offset 0 (OBL slot, signed.stm32artefact).0x3→ @External memory loader: stage the XSPI driver to RAM.0x4→ nor0 offset 0x100000 (BF slot).
Name: free-text label, shown in CubeProg output.Type:Binaryfor raw bytes;Force not usedto skip a row.IP: target memory —nonemeans "load to RAM" (used by Id 0x1 and 0x3);nor0is the on-board XSPI flash.Offset: byte offset inside the target memory.Binary: path (relative to the TSV) of the file to write.
Procedure
-
Power cycle the board.
-
Slide BOOT0 to DEV (toward the edge of the board on the N6570-DK; the boot ROM samples this pin at reset and enters system DFU when high).
-
Press the reset button.
lsusbshould now show:Bus xxx Device xxx: ID 0483:df11 STMicroelectronics STM Device in DFU Mode -
Run CubeProg against the TSV (substitute
FlashLayout_OBL_only.tsvif you want OBL written and the BF slot erased):~/STMicroelectronics/STM32Cube/STM32CubeProgrammer/bin/STM32_Programmer_CLI \ -c port=USB1 -d Unbricking.tsvYou'll see four phases scroll past —
fsbl-openblupload, then a re-enumeration as the OpenBootloader starts, thenfsbl-extflupload, thenobl-appandbf-appwrites to nor0. -
Slide BOOT0 back to USER.
-
Press reset. The chip boots from XSPI into our OBL → BF.
Verifying
After the reset in step 6:
lsusb | grep 0483
# Expect:
# Bus xxx Device xxx: ID 0483:3754 STMicroelectronics STLINK-V3
# Bus xxx Device xxx: ID 0483:5740 STMicroelectronics Virtual COM Port
/dev/ttyACM1 is the BF VCP. Send # + LF to escape MSP into the BF
CLI; version should report the build you just flashed.
Footnotes
STM32_Programmer_CLI -el .stldr -wwith the.stldrform of the XSPI driver SIGSEGVs on Linux at least up to v2.22.0; the TSV path works around that.port=USB1selects the first USB DFU device; if you have several DFU devices attached, addsn=<serial>to disambiguate. List withSTM32_Programmer_CLI --list usb.- The TSV's relative-path resolution is done from the TSV's own directory, which is why ST's two helper binaries are kept alongside it. OBL and BF artefact paths can be absolute or relative to that same directory.