summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.claude/agents/target-debugger.md1
-rw-r--r--.claude/skills/esp-target-debug/SKILL.md99
-rw-r--r--.claude/skills/target-debug/SKILL.md2
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