Environment
- Board: Seeed XIAO nRF54LM20A
- platform-seeedboards version: installed from
https://github.com/Seeed-Studio/platform-seeedboards.git (git-pinned in platformio.ini, not a registry release) — commit dd790080f5847f04680b079b3a7f24db4a56ccfa
- PlatformIO Core version: 6.1.19
- OpenOCD version bundled/used: 3.1200.7
- pyocd version: 0.45.1
- Host OS: Windows 11 Home, build 26200.9168
- Debug probe: CMSIS-DAPv2, VID:PID 0x2886:0x0068 (Seeed vendor ID — onboard SWD debugger), FW 2.0.0, serial 14F20522
- Framework: Zephyr (native, no Arduino option for this board)
Summary
Reproduced with a single, controlled test on one continuous session against the same
chip state (not pieced together from separate attempts):
- Confirmed no serial output on COM5 beforehand.
- Mass-erased the chip:
pyocd erase --target nrf54lm20a --chip (succeeds cleanly).
- Immediately attempted
pyocd flash on the freshly-erased chip — the target
crashes mid-program (CPU reports IPSR=3 / HardFault); the write never
completes. COM5 remained silent afterward.
- Immediately attempted
pio run -t upload (OpenOCD) on that same,
still-erased/crashed chip — OpenOCD logs clearing lockup after double fault
and Polling failed, trying to reexamine, then still reports [SUCCESS].
COM5 remained silent afterward.
- Power-cycled the board (full power-on reset, not just a soft reset) to rule out
"the CPU is just halted after flashing and needs a reset" as an explanation —
COM5 still showed no output. The board is genuinely non-functional after both
attempts, not merely halted in a debug state.
So: both tools fail to produce working firmware when flashing a chip that was just
mass-erased. pyocd fails loudly (crash, non-zero-equivalent failure state). OpenOCD
fails silently — it reports [SUCCESS] and exit-codes as if the upload worked, even
though the chip never boots. The [SUCCESS] status is not a reliable indicator that
the flash actually succeeded.
Both tools also log a persistent warning throughout — "not in a secure state" —
which is consistent with this being a TrustZone-M secure/non-secure debug-attach
state issue specific to this SoC, rather than a wiring/hardware fault (the same
board/cable/probe flashes correctly when the chip is not freshly erased — see
Additional notes).
Steps to reproduce
- Start from a XIAO nRF54LM20A with working firmware already flashed (e.g. a Zephyr
build produced via pio run -t upload on this same project). Confirm serial
output on the expected COM port beforehand if you want a clean before/after.
- Mass-erase the chip:
pyocd erase --target nrf54lm20a --chip.
- Immediately attempt
pyocd flash --target nrf54lm20a <path to firmware.hex> —
observe the crash with IPSR=3 (HardFault) during programming (see log below).
Check the serial port: no output.
- On that same chip (still in the failed/erased state from step 3), immediately
attempt pio run -t upload (project: Zephyr, board seeed-xiao-nrf54lm20a,
platform installed from Seeed-Studio/platform-seeedboards git HEAD) —
observe the clearing lockup after double fault / Polling failed errors
followed by a reported [SUCCESS] (see log below). Check the serial port
again: still no output.
- Power-cycle the board and check the serial port a third time to rule out a
halted-CPU/needs-reset explanation — output is still absent.
Expected behavior
Flash completes successfully and the resulting firmware boots and produces the
expected serial output, regardless of whether the chip was previously erased —
matching normal OpenOCD/pyocd behavior on other Cortex-M / TrustZone-M targets.
At minimum, a tool that cannot verify the target booted should not report
[SUCCESS].
Actual behavior — logs
Step 2: pyocd erase (succeeds)
PS C:\Users\steve\.platformio\platforms\seeedstudio\scripts\factory_reset\.venv\Scripts> ./pyocd.exe erase --target nrf54lm20a --chip
0000960 W NRF54LM20A is not in a secure state [target_nRF54LM20A]
0001270 I Erasing chip... [eraser]
0001647 I Chip erase complete [eraser]
Step 3: pyocd flash on the freshly-erased chip (crashes)
PS C:\Users\steve\.platformio\platforms\seeedstudio\scripts\factory_reset\.venv\Scripts> .\pyocd.exe flash --target nrf54lm20a "E:\Users\Steve\Documents\PlatformIO\Projects\weather_station_lm20a\.pio\build\seeed-xiao-nrf54lm20a\firmware.hex"
0001082 W NRF54LM20A is not in a secure state [target_nRF54LM20A]
0001395 I Loading E:\Users\Steve\Documents\PlatformIO\Projects\weather_station_lm20a\.pio\build\seeed-xiao-nrf54lm20a\firmware.hex [load_cmd]
0001476 I Erasing... [loader]
[==================================================] 100%
0001682 I Programming... [loader]
0001912 C target was not halted as expected after calling flash algorithm routine (IPSR=3) [__main__]
Step 4: pio run -t upload (OpenOCD) on the same chip, right after step 3 (reports false-positive SUCCESS)
PS E:\Users\Steve\Documents\PlatformIO\Projects\weather_station_lm20a> pio run -t upload
Processing seeed-xiao-nrf54lm20a (platform: https://github.com/Seeed-Studio/platform-seeedboards.git; framework: zephyr; board: seeed-xiao-nrf54lm20a)
-------------------------------------------------------------------------------------------------------------------------------
PLATFORM: Seeed Studio Xiao Series (1.0.0+sha.dd79008) > Seeed Studio XIAO nRF54LM20A
HARDWARE: NRF54LM20A 128MHz, 512KB RAM, 1.99MB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, jlink)
[west/pip dependency-check output omitted for brevity]
Checking size .pio\build\seeed-xiao-nrf54lm20a\firmware.elf
RAM: [ ] 2.9% (used 15344 bytes from 524288 bytes)
Flash: [ ] 3.4% (used 71700 bytes from 2084864 bytes)
Configuring upload protocol...
AVAILABLE: cmsis-dap, jlink, probe-rs, pyocd
CURRENT: upload_protocol = cmsis-dap
Uploading .pio\build\seeed-xiao-nrf54lm20a\firmware.hex
xPack Open On-Chip Debugger 0.12.0+dev-02228-ge5888bda3-dirty (2025-10-04-22:44)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Warn : Adapter driver already configured, ignoring
Error: [nrf54lm20a.cpu] clearing lockup after double fault
Error: [nrf54lm20a.cpu] Polling failed, trying to reexamine
================================================ [SUCCESS] Took 14.20 seconds ================================================
Confirmed: despite [SUCCESS], COM5 showed no output — checked immediately
after upload, and again after a full power-cycle of the board (ruling out a
halted-CPU/needs-manual-reset explanation).
Additional notes / working theory
- The
"<device> is not in a secure state" warning appears on every pyocd
invocation against this board, including the successful erase, which points at
this being a TrustZone-M Secure/Non-Secure debug-access-port state issue rather
than an intermittent/timing bug.
- Flashing succeeds reliably when overwriting existing, already-booting firmware
(both tools work fine in that case); it is specifically attach-and-program
against a blank/erased (all-0xFF, no valid vector table) chip that triggers
the crash/lockup in both tools.
- OpenOCD's false-positive
[SUCCESS] is arguably the more actionable part of
this report for tooling maintainers: the process exit code does not reflect
whether the flash actually produced working firmware, which could silently
ship broken firmware to anyone who doesn't independently verify serial output.
This was specifically confirmed not to be a "just needs a reset" situation —
we power-cycled the board and it still produced no output.
- This is a very new chip (nRF54LM20A), so it's plausible neither pyocd's flash
algorithm nor this platform's OpenOCD config/reset sequence has been
validated yet against this specific erase-then-attach case.
- Happy to test candidate fixes (alternate
reset_config, adapter speed,
explicit secure-AP dap selection, srst/sysresetreq sequencing, etc.) against
hardware if maintainers can suggest something to try.
Workarounds tried
- Retrying
pio run -t upload multiple times without erasing first — this is the
only thing that has reliably worked, and only when the chip was never mass-erased
to begin with. Once a mass-erase has been performed, the chip appears to remain
in this broken state; reflashing (via either tool) no longer recovers it.
Environment
https://github.com/Seeed-Studio/platform-seeedboards.git(git-pinned inplatformio.ini, not a registry release) — commitdd790080f5847f04680b079b3a7f24db4a56ccfaSummary
Reproduced with a single, controlled test on one continuous session against the same
chip state (not pieced together from separate attempts):
pyocd erase --target nrf54lm20a --chip(succeeds cleanly).pyocd flashon the freshly-erased chip — the targetcrashes mid-program (CPU reports IPSR=3 / HardFault); the write never
completes. COM5 remained silent afterward.
pio run -t upload(OpenOCD) on that same,still-erased/crashed chip — OpenOCD logs
clearing lockup after double faultand
Polling failed, trying to reexamine, then still reports[SUCCESS].COM5 remained silent afterward.
"the CPU is just halted after flashing and needs a reset" as an explanation —
COM5 still showed no output. The board is genuinely non-functional after both
attempts, not merely halted in a debug state.
So: both tools fail to produce working firmware when flashing a chip that was just
mass-erased. pyocd fails loudly (crash, non-zero-equivalent failure state). OpenOCD
fails silently — it reports
[SUCCESS]and exit-codes as if the upload worked, eventhough the chip never boots. The
[SUCCESS]status is not a reliable indicator thatthe flash actually succeeded.
Both tools also log a persistent warning throughout —
"not in a secure state"—which is consistent with this being a TrustZone-M secure/non-secure debug-attach
state issue specific to this SoC, rather than a wiring/hardware fault (the same
board/cable/probe flashes correctly when the chip is not freshly erased — see
Additional notes).
Steps to reproduce
build produced via
pio run -t uploadon this same project). Confirm serialoutput on the expected COM port beforehand if you want a clean before/after.
pyocd erase --target nrf54lm20a --chip.pyocd flash --target nrf54lm20a <path to firmware.hex>—observe the crash with IPSR=3 (HardFault) during programming (see log below).
Check the serial port: no output.
attempt
pio run -t upload(project: Zephyr, boardseeed-xiao-nrf54lm20a,platform installed from
Seeed-Studio/platform-seeedboardsgit HEAD) —observe the
clearing lockup after double fault/Polling failederrorsfollowed by a reported
[SUCCESS](see log below). Check the serial portagain: still no output.
halted-CPU/needs-reset explanation — output is still absent.
Expected behavior
Flash completes successfully and the resulting firmware boots and produces the
expected serial output, regardless of whether the chip was previously erased —
matching normal OpenOCD/pyocd behavior on other Cortex-M / TrustZone-M targets.
At minimum, a tool that cannot verify the target booted should not report
[SUCCESS].Actual behavior — logs
Step 2: pyocd erase (succeeds)
Step 3: pyocd flash on the freshly-erased chip (crashes)
Step 4:
pio run -t upload(OpenOCD) on the same chip, right after step 3 (reports false-positive SUCCESS)Confirmed: despite
[SUCCESS], COM5 showed no output — checked immediatelyafter upload, and again after a full power-cycle of the board (ruling out a
halted-CPU/needs-manual-reset explanation).
Additional notes / working theory
"<device> is not in a secure state"warning appears on every pyocdinvocation against this board, including the successful erase, which points at
this being a TrustZone-M Secure/Non-Secure debug-access-port state issue rather
than an intermittent/timing bug.
(both tools work fine in that case); it is specifically attach-and-program
against a blank/erased (all-
0xFF, no valid vector table) chip that triggersthe crash/lockup in both tools.
[SUCCESS]is arguably the more actionable part ofthis report for tooling maintainers: the process exit code does not reflect
whether the flash actually produced working firmware, which could silently
ship broken firmware to anyone who doesn't independently verify serial output.
This was specifically confirmed not to be a "just needs a reset" situation —
we power-cycled the board and it still produced no output.
algorithm nor this platform's OpenOCD config/reset sequence has been
validated yet against this specific erase-then-attach case.
reset_config,adapter speed,explicit secure-AP
dapselection, srst/sysresetreq sequencing, etc.) againsthardware if maintainers can suggest something to try.
Workarounds tried
pio run -t uploadmultiple times without erasing first — this is theonly thing that has reliably worked, and only when the chip was never mass-erased
to begin with. Once a mass-erase has been performed, the chip appears to remain
in this broken state; reflashing (via either tool) no longer recovers it.