diff options
| author | hathach <[email protected]> | 2026-07-24 14:48:44 +0700 |
|---|---|---|
| committer | hathach <[email protected]> | 2026-07-24 14:55:59 +0700 |
| commit | 22a155f091283596ee34550c42c075967841159b (patch) | |
| tree | b3e8202756db055c82e54b8cead301002f71862f | |
| parent | 5066ac7b31445f64aa6007fbe28f03e049aec0b6 (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.md | 7 | ||||
| -rw-r--r-- | .claude/skills/esp-target-debug/SKILL.md | 103 | ||||
| -rw-r--r-- | .claude/skills/target-debug/SKILL.md | 7 |
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 |
