Files
PX4-Autopilot/Tools/flash_fault_injection/brick_ecc.c
Jacob Dahl 183b3e38d5 fix(bootloader): scrub uncorrectable flash ECC errors on STM32H7 before boot (#27642)
* fix(bootloader): scrub uncorrectable flash ECC errors on STM32H7 before boot

A torn write to a flash row (power lost mid program/erase) can leave it
with inconsistent ECC. On H7 a CPU read of such a row raises an
uncorrectable double-bit ECC error -> bus fault, so the application hard
faults on every boot before printing anything, and only a mass erase
recovers it: reflashing does not, because neither the app nor the
bootloader image touches the parameter sector.

Scan the application and parameter flash with DMA right after clock_init
(a DMA read latches FLASH_SR DBECCERR instead of bus-faulting the CPU)
and erase any sector that holds an uncorrectable error. A corrupt
parameter sector then re-seeds to defaults on the next app boot; corrupt
app flash fails the image check and stays in the bootloader for reflash.
Mirrors ArduPilot's bootloader ECC scrub. H7-gated; the scan runs before
the interface DMA is brought up, so DMA1 stream 0 is uncontended.

* test(tools): add STM32H7 flash ECC fault injection tool

A bench helper that deterministically plants an uncorrectable (double-bit)
flash ECC error on an STM32H7, reproducing the torn-write parameter-store
brick. Used to validate the bootloader ECC scrub and the parameter re-seed
recovery on hardware: plant the fault, then confirm the board boots clean
instead of hard-faulting every boot.

brick_ecc.c is a freestanding stub that double-programs one flash word with
two different single-bit clears (the recipe that yields an inconsistent ECC);
brick_ecc.sh builds it, loads it into AXI SRAM over ST-Link, runs it, and
resets the board. README documents usage and how to retarget another board.

* fix(bootloader): require DMA transfer-complete for a clean ECC scan chunk

The stream self-disables on both transfer-complete and transfer-error.
A non-ECC bus error (unreachable scan buffer, rejected FIFO config)
previously read as a clean chunk, silently turning the scan into a
no-op. Require TCIF so an unread chunk takes the skip-the-scan
fallback instead of passing.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>

---------

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
2026-06-12 19:21:01 -06:00

2.6 KiB