Skip to content

OpenOCD RP2350 flash driver clobbers CPACR on GDB attach → GPIO-coprocessor NOCP fatal (debugger-induced, not firmware) #458

Description

@Mikefly123

Summary

The z_fatal_error(reason=33) / usage-fault "hangs" observed during HWIL debugging on the V5e (RP2350) — on both main (b2437a9) and feat/sband-pr1-infra (2558ac3, PR #448) — are caused by the debugger, not by flight software. Both firmwares run indefinitely with clean telemetry when no debugger is attached.

OpenOCD's RP2350 flash driver executes an "RCP init" stub on the target that overwrites CPACR with 0xC000 (enabling only the redundancy coprocessor CP7), which disables the RP2350 GPIO coprocessor (CP0) and the DCP (CP4). The pico-sdk HAL uses CP0 for all GPIO access (mcr/mrc p0), so the next GPIO touch after resume raises a K_ERR_ARM_USAGE_NO_COPROCESSOR (reason=33) fatal, and Zephyr's default handler spins in arch_system_halt — which looks exactly like a firmware hang.

Mechanism

  • tools/openocd/src/flash/nor/rp2xxx.c, rcp_init_code (~line 101), run by rp2350_init_arm_core0 → setup_for_raw_flash_cmd → rp2xxx_flash_probe. The stub does str r1, [CPACR] with r1 = M33_CPACR_CP7_BITS only; a comment admits "we assume no other co-processors are enabled at this point to save space."
  • Flash auto-probe fires when GDB connects (memory-map query), so a plain gdb attach to a healthy running board is enough — no flashing needed.
  • The driver saves/restores the core's security state and ACCESSCTRL around ROM calls, but not CPACR.

Evidence (V5e HWIL, probe E663AC91D32D6A39, 2026-07-19)

  1. Faulting instruction at gpio_rpi_port_get_raw is 0xee103018 = MRC p0, #0, r3, c0, c1, #0 — a genuine CP0 access, not an assert/UDF trap (rules out an F´ FW_ASSERT explanation).
  2. reason=33 = K_ERR_ARM_USAGE_NO_COPROCESSOR; Zephyr only assigns this when the hardware UFSR NOCP bit is set.
  3. Healthy running board: CPACR = 0xC303 (CP0 enabled — set by soc_reset_hook → runtime_init_per_core_enable_coprocessors() at every boot). No code in Zephyr/HAL/F´ writes CPACR at runtime; no PM/sleep configured.
  4. Standalone runs clean: main firmware 90 s, sband firmware 3+ min, steady telemetry, including the watchdog-pet GPIO path that "faulted immediately" under the debugger.
  5. Causation on demand: attach OpenOCD+GDB to the healthy running board → CPACR reads 0xC000 at first halt → continue → immediate NOCP fatal, identical backtrace (watchdog pet on sband; SX126x BUSY-pin read on main — simply whichever code touches GPIO first after resume).
  6. rp2350.cfg sets no cortex_m vector_catch; the static halt is Zephyr's stock for(;;) — after the debugger-manufactured fault.

Impact

  • Any RP2350 HWIL session that attaches GDB (or runs a flash command) while firmware is running will fatal the board on the next GPIO access. Easily misdiagnosed as a firmware GPIO/coprocessor bug — it already cost multiple debug sessions here, and likely explains the earlier GRC-board "NOCP fault on every LoRa TX" (June 2026) that was worked around with PICO_USE_GPIO_COPROCESSOR=0.
  • PR feat(sband) 1/3: StackMonitor + dynamic-thread-alloc infrastructure #448 is not implicated; the fault reproduces identically on main.

Possible fixes (for later discussion)

  1. Patch our vendored OpenOCD: make rcp_init_code read-modify-write CPACR (OR in CP7 bits instead of overwriting), or save/restore CPACR like ACCESSCTRL. Upstream-reportable to raspberrypi/openocd.
  2. Bench workaround: after any GDB attach, restore with mww 0xE000ED88 0xC303 before resuming.
  3. Build workaround for debug sessions: PICO_USE_GPIO_COPROCESSOR=0 (MMIO SIO GPIO, immune to the clobber).

🤖 Generated with Claude Code

https://claude.ai/code/session_019gMrPNe6LwGtBS6Y7B5bo8

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    • Status
      No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions