Skip to content

tools/flash.sh: work around OpenOCD program-sector-0 bug on GD32F205#32

Open
RAR wants to merge 1 commit into
mainfrom
flash-sh-gd32-sector0-fix
Open

tools/flash.sh: work around OpenOCD program-sector-0 bug on GD32F205#32
RAR wants to merge 1 commit into
mainfrom
flash-sh-gd32-sector0-fix

Conversation

@RAR
Copy link
Copy Markdown
Owner

@RAR RAR commented May 24, 2026

The bug

OpenOCD 0.12.0 + stm32f1x driver targeting GD32F205 (CPUTAPID 0x1ba01477)
silently fails to write flash sector 0 via the high-level `program` command.

Symptoms:

  • "Programming Finished" / "Verified OK" both reported, no errors
  • Chip hard-faults on reset
  • SWD halt shows PC=0x0F0E0D0C (chip trying to load reset vector, getting garbage)
  • Reading 0x08000000-0x0800003F returns the address-byte pattern:
    `0x08000000: 03020100 07060504 0b0a0908 0f0e0d0c` — bytes 00 01 02 03 04...
  • Code/data at 0x08008000+ reads correctly — only sector 0 is broken

Root cause (best guess): OpenOCD's stm32f1x loader algorithm has a subtle
interaction bug with the GD32F205 flash controller for sector 0. The verify
step uses the same broken path so the bug is invisible to OpenOCD.

Hardware verified healthy: manual unlock + direct flash controller poke
(KEY1/KEY2, set PG, half-word write, wait EOP) writes sector 0 correctly.
Only the loader-algorithm path is broken.

The fix

Replace the `program` invocation with:

  1. Manual unlock (write KEY1 + KEY2 to FLASH_KEYR)
  2. Manual mass erase via direct FLASH_CR.MER + STRT (avoids whatever
    sector-0 specific issue the loader has)
  3. `reset halt` to get the chip into clean state for the write loader
  4. `flash write_image` + `verify_image` (lower-level path, works correctly)

Also adds a post-flash reminder: after SWD flash, the external GFCI/CCID
chip is latched in fail-safe (MCU was halted >6 s during flash, exceeding
the chip's refresh watchdog). A power-cycle of the unit is required before
the boot self-test will pass. Documented in the post-flash message so
future operators don't lose time to it.

Cost

This bug + the GD32 PLL cache trap (separate finding) together cost ~12 hours
of debugging on 2026-05-24. After we noticed it, fix was 30 minutes. Saving
the next operator from the same trap.

Detection recipe

If you suspect this bit you on a previously-flashed unit:
```bash
openocd -f tools/openocd-gd32f205.cfg -c "init" -c "halt" \
-c "mdw 0x08000000 4" -c "shutdown"
```
If you see `03020100 07060504 0b0a0908 0f0e0d0c` — yep.

Test Plan

  • Bench-validated on rippleon ROC001 wall unit recovery (2026-05-24)
  • Vector table reads correctly after flash via this path
  • Chip boots to running firmware (no HardFault)
  • Post-flash power-cycle → GFCI self-test PASS → READY

🤖 Generated with Claude Code

Bench-confirmed 2026-05-24: OpenOCD 0.12.0 + stm32f1x driver targeting
GD32F205 (CPUTAPID 0x1ba01477) silently fails to write flash sector 0
via the high-level `program` command. The "Verified OK" reports a
false pass because verify_image uses the same broken loader path and
reads back the same address-byte garbage (00 01 02 03 04 ...) that
write produced. Chip then hard-faults on next reset trying to load
the corrupted reset vector.

Manual proof that hardware is fine: direct FLASH_KEYR unlock + PG/STRT
write of a half-word at 0x08000000 lands correctly and reads back
right. Silicon is healthy, only the OpenOCD loader-algorithm path
is broken.

Workaround: manual mass erase via direct FLASH_CR poking, then
`flash write_image` + `verify_image` (lower-level path that doesn't
use the broken loader). Tested on rippleon ROC001 — wall unit
recovered from yesterday's busy_wait incident now boots cleanly.

Also adds a post-flash message reminding the operator to power-cycle
the unit before expecting the GFCI self-test to pass: the SWD halt
during flash exceeds the external CCID chip's refresh-cycle watchdog
window, latching the chip into fail-safe. Power cycle clears it.

See feedback memory feedback-openocd-program-skips-sector0-gd32f205
for full detail + detection recipe.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant