summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-07-24 14:48:44 +0700
committerhathach <[email protected]>2026-07-24 14:55:59 +0700
commit22a155f091283596ee34550c42c075967841159b (patch)
treeb3e8202756db055c82e54b8cead301002f71862f
parent5066ac7b31445f64aa6007fbe28f03e049aec0b6 (diff)
docs(skills): tighten esp-target-debug/target-debug; agent routes backends by board family
- esp-target-debug: de-narrated (~1000 -> 847 words) — session-diary phrasing ('this unit', dates, 'we measured') replaced with durable reference facts; restructured per-board (P4 vs S3 notes); new Scripted-session gotchas section consolidates telnet-halt pattern, ESP_ONLYCPU, and ROM-frame guidance; UART-reset recipe stated once - target-debug: fix run-on seam from the -singlerun insertion - target-debugger agent: charter now resolves the board family FIRST and routes Espressif boards to esp-target-debug as primary playbook; skills table re-aligned - retrieval regression: 4/4 (agent routing, S3 keep-alive quirk, OpenOCD RTT on ST-Link, ROM-frame guidance)
-rw-r--r--.claude/agents/target-debugger.md7
-rw-r--r--.claude/skills/esp-target-debug/SKILL.md103
-rw-r--r--.claude/skills/target-debug/SKILL.md7
3 files changed, 64 insertions, 53 deletions
diff --git a/.claude/agents/target-debugger.md b/.claude/agents/target-debugger.md
index 68e431683..e25ffa7f1 100644
--- a/.claude/agents/target-debugger.md
+++ b/.claude/agents/target-debugger.md
@@ -8,7 +8,10 @@ You debug one failing USB behavior on one physical board until you can name the
mechanism — or report exactly what you ruled out. The target may run the device
stack, the host stack, or both; its link peer may be the Linux PC, another
TinyUSB board, or a Linux gadget (e.g. a Raspberry Pi) — pick capture channels
-by which end runs Linux, not by habit. These repo skills (each at
+by which end runs Linux, not by habit. Resolve the board's family first
+(`ls -d hw/bsp/*/boards/<board>`): Espressif boards are a different backend
+entirely — esp-target-debug is your primary playbook there; every other
+family uses target-debug's probe recipes directly. These repo skills (each at
`.claude/skills/<name>/SKILL.md`) are your source of truth; read the relevant
one BEFORE acting:
@@ -16,7 +19,7 @@ one BEFORE acting:
|--------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| target-debug | primary playbook — technique choice by intrusiveness, channel choice by link topology, capture recipes, bp/wp budget + cost model, vector catch + fault autopsy, SWO trace, GDB autopsy, rig warnings |
| hil | host/config selection, board lock protocol, `hil_test.py` invocation |
-| esp-target-debug | Espressif S3/P4 backend: built-in USB-Serial-JTAG attach, PHY-conflict map, FreeRTOS threads via ESP_RTOS |
+| esp-target-debug | PRIMARY playbook for Espressif boards — built-in USB-Serial-JTAG attach, the PHY map that decides whether JTAG exists, FreeRTOS threads via ESP_RTOS; target-debug still supplies the methodology |
| usbmon | Linux-host URB capture; only when a Linux PC is the link's host (default posture: dual-side, both ends simultaneously) |
| usb-sniffer | wire-level capture (hardware tap): host can't see the bus, usbmon vs target logs disagree, or TinyUSB is the host (no usbmon anywhere) |
| usb-kernel-debug | why the Linux kernel acted (dmesg/dynamic debug); PC host or a Linux gadget peer's device side |
diff --git a/.claude/skills/esp-target-debug/SKILL.md b/.claude/skills/esp-target-debug/SKILL.md
index ca6c7c401..c6d76c801 100644
--- a/.claude/skills/esp-target-debug/SKILL.md
+++ b/.claude/skills/esp-target-debug/SKILL.md
@@ -13,65 +13,74 @@ Built-in USB-Serial-JTAG only; external JTAG is a TODO (no rig adapter).
## The PHY map — decides everything (verified on the rig)
-| Board | USB-SJ vs TinyUSB OTG | JTAG while USB device runs? |
-|--------------------------|---------------------------------------------------|-----------------------------|
-| espressif_p4_function_ev | separate pins: USB-SJ GPIO24/25 (FS), OTG own HS PHY | **yes — coexist** (verified: 303a:1001 + cafe:4008 enumerated simultaneously, gdb attach during live CDC traffic) |
-| espressif_s3_devkitm | ONE shared PHY/port | **no** — the same hub port flips 303a:1001 → cafe:4008 as the app boots (verified in dmesg); openocd then fails `esp_usb_jtag: could not find or open device!` |
+| Board | USB-SJ vs TinyUSB OTG | JTAG while USB device runs? |
+|--------------------------|------------------------------------------------------|-----------------------------|
+| espressif_p4_function_ev | separate pins: USB-SJ GPIO24/25 (FS), OTG own HS PHY | **yes — coexist** (verified: 303a:1001 + cafe:4008 simultaneously, gdb attach during live CDC traffic) |
+| espressif_s3_devkitm | ONE shared PHY/port | **no** — the same hub port flips 303a:1001 → cafe:4008 as the app boots; openocd fails `esp_usb_jtag: could not find or open device!` |
-- S3 debugging windows: non-USB firmware (`board_test` — attach, halt, and
- symbol resolution verified; `usb_new_phy` confirmed absent from the ELF
- when `CFG_TUD/TUH_ENABLED` are 0), bootloader/ROM (always stable — chip
- parked in download mode enumerates cleanly for minutes), or external JTAG
- (TODO).
-- **S3 app-context keep-alive quirk (verified)**: with app firmware running
- and nothing attached, USB-SJ drops ~4 s after boot (device-side disconnect,
- then half-dead `-71` setup failures until reset). Attach a client inside
- the window — or once it survives the window it stays up. Recovery is
- UART-side: `esptool.py --after hard_reset read_mac` on the CP2102 tty.
-- **S3 batch-automation caveats**: this unit's cpu1 debug logic can fail
- examination (`OCD_ID = 00000000`) — `-c 'set ESP_ONLYCPU 1'` degrades to
- cpu0-only; xtensa-gdb batch `continue`/`interrupt` is async-flaky — for
- scripted state reads, halt via telnet :4444 first, then attach gdb to the
- stopped target (verified). Interactive sessions are unaffected.
+Flashing works in ANY PHY state: the rig flashes via the boards' CP2102N UART
+bridges (hence `tinyusb.json` esptool uids are CP210x serials, not MACs). The
+UART side is also the remote reset: `esptool.py --after hard_reset read_mac`.
+
+### P4 (Function-EV) notes
+
+- The board has **no USB-SJ connector** — GPIO24 (D−, white) / GPIO25 (D+,
+ green) / GND are broken out from header J1 to a rig hub port. Swapped
+ D+/D− enumerates as `new low-speed USB device` + error -71; correct shows
+ `new full-speed`.
+
+### S3 (DevKitM) notes
+
+- Debugging windows: non-USB firmware (`board_test` — attach/halt/symbol
+ resolution verified; `usb_new_phy` is absent from the ELF when
+ `CFG_TUD/TUH_ENABLED` are 0), bootloader/ROM (always stable), or external
+ JTAG (TODO).
+- **Keep-alive quirk (verified)**: with app firmware running and nothing
+ attached, USB-SJ drops ~4 s after boot (device-side disconnect, then
+ half-dead `-71` setup failures until reset). Attach a client inside the
+ window — once it survives the window it stays up. Recover via the UART
+ reset above.
- PHY mux reference: `RTC_CNTL_RTC_USB_CONF_REG` (0x60008120) bits
- `SW_HW_USB_PHY_SEL`/`SW_USB_PHY_SEL` (TRM 10.56) — 0 = eFuse/hardware
- control (the default we measured). `esptool.py read_mem/write_mem` peeks
- and pokes registers over plain UART with the chip in download mode.
-- P4 Function-EV has **no USB-SJ connector** — GPIO24 (D−, white) / GPIO25
- (D+, green) / GND are broken out from header J1 to a rig hub port (wired
- 2026-07-23). Miswired D+/D− shows as `new low-speed USB device` + error
- -71; correct shows `new full-speed`.
-- Flashing always works regardless of PHY state: the rig flashes via the
- CP2102N UART bridges (that's why `tinyusb.json` esptool uids are CP210x
- serials, not MACs).
+ `SW_HW_USB_PHY_SEL`/`SW_USB_PHY_SEL` (TRM 10.56); 0 = eFuse/hardware
+ control (default). `esptool.py read_mem/write_mem` peeks and pokes
+ registers over plain UART with the chip in download mode.
## Attach
```bash
. $HOME/code/esp-idf/export.sh # openocd-esp32, riscv32-/xtensa-esp32s3-elf-gdb, esptool
openocd -c 'set ESP_RTOS FreeRTOS' -f board/esp32p4-builtin.cfg \
- -c 'adapter serial 60:55:F9:F9:87:15' & # P4; S3: board/esp32s3-builtin.cfg + its MAC
+ -c 'adapter serial <MAC-with-colons>' & # S3: board/esp32s3-builtin.cfg
riscv32-esp-elf-gdb -batch -ex 'target extended-remote :3333' \
-ex 'tbreak tud_task_ext' -ex continue -ex bt -ex 'info threads' -ex detach <elf>
```
-- `adapter serial` = the chip MAC **with colons** (`lsusb -v -d 303a:1001`,
- or `/dev/serial/by-id/usb-Espressif_USB_JTAG_serial_debug_unit_<MAC>-if00`).
-- `set ESP_RTOS FreeRTOS` must precede the board cfg: with it, `info
- threads` lists every task with name/state/CPU (verified: usbd Running
- @CPU0, IDLE1 @CPU1, blinky, io, ipc0/1); without it, one bare
- "Remote target".
+- `adapter serial` = the chip MAC **with colons** (`lsusb -v -d 303a:1001`, or
+ `/dev/serial/by-id/usb-Espressif_USB_JTAG_serial_debug_unit_<MAC>-if00`).
+- `set ESP_RTOS FreeRTOS` must precede the board cfg: with it, `info threads`
+ lists every task with name/state/CPU (verified: usbd Running @CPU0, IDLE1
+ @CPU1, ...); without it, one bare "Remote target".
- The ELF: `idf.py -B <builddir> -DBOARD=<board> build` under the example
(CLAUDE.md Espressif notes) — symbolized app backtraces verified
(`tud_task_ext` ← `usb_device_task` ← `vPortTaskWrapper`).
-- **Attach may reset the target** — after a tbreak-continue the FreeRTOS
- tick read 2 (boot-fresh) on a minutes-old session. Until pinned down, do
- NOT trust built-in-JTAG attach for post-mortem autopsy of a wedged board
- (`target-debug`'s attach-and-halt-only rule); capture state via console
- or treat the reset as part of the reproduce cycle.
-- Halting still stops USB service: expect the host to drop the DUT during
- long halts; after detach the device may need a reset to re-enumerate
- (UART-side `esptool.py read_mac` is a handy remote reset).
+- **Attach may reset the target** (a boot-fresh FreeRTOS tick observed on a
+ minutes-old session). Until pinned down, do NOT trust built-in-JTAG attach
+ for post-mortem autopsy of a wedged board (`target-debug`'s
+ attach-and-halt-only rule); capture state via console or treat the reset
+ as part of the reproduce cycle.
+- Halting still stops USB service: the host may drop the DUT during long
+ halts; after detach the device may need the UART reset to re-enumerate.
+
+## Scripted-session gotchas (verified)
+
+- xtensa-gdb batch `continue`/`interrupt` is async-flaky — for scripted
+ state reads, halt via openocd telnet :4444 first, then attach gdb to the
+ stopped target. Interactive sessions are unaffected.
+- cpu1 debug-logic examination can fail (`OCD_ID = 00000000`) —
+ `-c 'set ESP_ONLYCPU 1'` degrades to cpu0-only debugging.
+- ROM-frame backtraces (`0x4004xxxx` on S3, `0x4fc0xxxx` on P4, all `??`)
+ mean the core idles in ROM — break in app code (`tbreak tud_task_ext`)
+ for symbolized frames.
## Technique mapping (vs the `target-debug` arsenal)
@@ -86,11 +95,9 @@ riscv32-esp-elf-gdb -batch -ex 'target extended-remote :3333' \
## Rig deltas
-- Locks/flash per `hil` skill; espressif flasher = esptool over the CP210x
- UART tty (works with any PHY state, any firmware).
-- One client per USB-SJ: openocd and any terminal on the USB-SJ CDC side
+- Locks per `hil` skill; reflash-pristine before release applies unchanged.
+- One client per USB-SJ: openocd and a terminal on the USB-SJ CDC side
conflict the same way J-Link clients do.
-- Reflash-pristine before release applies unchanged.
## TODO — external JTAG (needs hardware)
diff --git a/.claude/skills/target-debug/SKILL.md b/.claude/skills/target-debug/SKILL.md
index ff3f45d4e..ab754dc09 100644
--- a/.claude/skills/target-debug/SKILL.md
+++ b/.claude/skills/target-debug/SKILL.md
@@ -252,9 +252,10 @@ reads don't halt the target.
## GDB — state autopsy and watchpoints
Connect/load recipes per probe family (J-Link, OpenOCD for ST-Link /
-CMSIS-DAP / WCH-Link) are in CLAUDE.md "GDB Debugging". Scripted sessions: JLinkGDBServer `-singlerun` (exits with the
-connection) — back-to-back relaunches race the probe handle and hang. Release builds keep DWARF (`MinSizeRel`), so `p`/struct access works
-on HIL firmware.
+CMSIS-DAP / WCH-Link) are in CLAUDE.md "GDB Debugging"; script sessions with
+JLinkGDBServer `-singlerun` — the server exits with the connection, and
+back-to-back relaunches race the probe handle and hang. Release builds keep
+DWARF (`MinSizeRel`), so `p`/struct access works on HIL firmware.
**Autopsy of a wedged board: attach and halt ONLY** — skip CLAUDE.md's
`monitor reset halt` + `load` (those are for fresh starts; a reset destroys