diff options
| -rw-r--r-- | .claude/agents/target-debugger.md | 1 | ||||
| -rw-r--r-- | .claude/skills/esp-target-debug/SKILL.md | 99 | ||||
| -rw-r--r-- | .claude/skills/target-debug/SKILL.md | 2 |
3 files changed, 102 insertions, 0 deletions
diff --git a/.claude/agents/target-debugger.md b/.claude/agents/target-debugger.md index 78110b179..68e431683 100644 --- a/.claude/agents/target-debugger.md +++ b/.claude/agents/target-debugger.md @@ -16,6 +16,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 | | 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 new file mode 100644 index 000000000..ca6c7c401 --- /dev/null +++ b/.claude/skills/esp-target-debug/SKILL.md @@ -0,0 +1,99 @@ +--- +name: esp-target-debug +description: Use when debugging TinyUSB firmware on Espressif boards (ESP32-S3/P4 on the rig — dcd_dwc2 examples, idf.py builds) with the chips' built-in USB-Serial-JTAG — attach/halt/backtrace, breakpoints, FreeRTOS task lists, console capture — or when JTAG "could not find or open device", the 303a:1001 port vanishes, or the S3's debug port turns into the TinyUSB device. +--- + +# esp-target-debug — Espressif built-in USB-JTAG backend + +Methodology — intrusiveness ladder, board locks, dual-side capture, diagnosis +standards — lives in `target-debug`; this skill is the Espressif backend: a +different gdb, a different openocd (fork), no probe serial (the debugger IS a +USB device), and a PHY story that decides whether JTAG exists at all. +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!` | + +- 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. +- 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). + +## 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 +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". +- 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). + +## Technique mapping (vs the `target-debug` arsenal) + +| target-debug technique | Espressif backend | +|------------------------|-------------------| +| GDB autopsy, bp/wp | same flow via openocd-esp32 :3333; RISC-V triggers (P4) / Xtensa 2 bp + 2 wp (S3) | +| Vector catch | none — breakpoint the panic handler; `mcause`/`mepc`/`mtval` on P4 | +| SWO / DWT data trace | none — apptrace over JTAG is the analog (untested: needs CONFIG_APPTRACE + app init) | +| RTT / TU_LOG | console on **UART0 = the CP2102 flasher tty** by default (verified); USB-SJ console needs sdkconfig `ESP_CONSOLE_USB_SERIAL_JTAG` (untested) | +| FreeRTOS threads | native — `set ESP_RTOS FreeRTOS` (see Attach) | +| verifybin | `esptool.py verify_flash` (untested) | + +## 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 + conflict the same way J-Link clients do. +- Reflash-pristine before release applies unchanged. + +## TODO — external JTAG (needs hardware) + +S3 JTAG pins GPIO39–42 (MTCK/MTDO/MTDI/MTMS) + any adapter openocd-esp32 +supports (ESP-Prog/FT2232-class); would give S3 debugging under live USB +traffic. Mind `EFUSE_DIS_PAD_JTAG` / JTAG-source strapping. Unverified. diff --git a/.claude/skills/target-debug/SKILL.md b/.claude/skills/target-debug/SKILL.md index 2514db86f..ff3f45d4e 100644 --- a/.claude/skills/target-debug/SKILL.md +++ b/.claude/skills/target-debug/SKILL.md @@ -44,6 +44,8 @@ family, `flasher.uid` the **probe serial** (many identical probes on the rig): `ls -d hw/bsp/*/boards/<board>`. - Run on the host that owns the probe — config `test/hil/tinyusb.json` on ci, `local.json` on htpc (`hil` skill). +- Espressif boards (S3/P4): different toolchain, probe model, and PHY + constraints entirely — read `esp-target-debug` first. ## Pick the least intrusive technique that can answer the question |
