Backend skill for debugging TinyUSB firmware on Espressif targets (rig: espressif_p4_function_ev, espressif_s3_devkitm) via the chips' built-in USB-Serial-JTAG, with external JTAG documented as a TODO until the rig has an adapter. Companion to target-debug, which keeps the architecture-neutral methodology (intrusiveness ladder, board locks, dual-side capture, diagnosis standards) — this skill is the Espressif toolchain/probe backend, the same boundary that makes usb-kernel-debug its own skill.
target-debug ethos).board_test (TinyUSB off — PHY free), verified failure mode with a USB device example, external-JTAG escape hatch documented as TODO.New skill .claude/skills/esp-target-debug/SKILL.md; two integration edits:
target-debug gains a 2-line pointer under the probe-mapping bullets: Espressif boards use a different toolchain, probe model, and trace story — read esp-target-debug.target-debugger agent table gains an esp-target-debug row (name-only, aligned columns, per the established conventions).Skill content (order):
Role + defer line — methodology lives in target-debug; this file is the Espressif backend. Built-in USB-SJ now; external JTAG TODO.
PHY-conflict map —
board_test), dies for USB device examples (verified boundary, exact symptom recorded). External JTAG = the future escape hatch (TODO).Toolchain & attach — . $HOME/code/esp-idf/export.sh provides openocd-esp32 + riscv32-esp-elf-gdb (P4) / xtensa-esp32s3-elf-gdb (S3). Rig path is raw openocd (HIL firmware isn't an idf project on disk): openocd -f board/esp32p4-builtin.cfg with adapter serial <uid> (USB-SJ is VID 303A:1001; uid = the flasher.uid already in tinyusb.json), gdb on :3333. idf.py openocd / idf.py gdb noted for idf-project work.
Technique mapping table (aligned) — ARM technique → Espressif equivalent:
| target-debug technique | Espressif backend |
|---|---|
| GDB autopsy, bp/wp | same flow; RISC-V trigger module (P4) / Xtensa 2 bp + 2 wp (S3); budget read verified on P4 |
| Vector catch | none — breakpoint the panic handler; decode mcause/mepc/mtval (P4) |
| SWO / DWT data trace | none — apptrace over JTAG is the analog (gated spike; lands (untested) if it fails) |
| RTT / TU_LOG | USB-SJ console — on P4 it coexists with DUT traffic |
| FreeRTOS threads | native in openocd-esp32 — info threads out of the box |
| verifybin | esptool.py verify_flash |
Rig discipline deltas — same board_lock.py protocol; flasher is esptool (serial-port-by-uid); reflash pristine before release; one client per USB-SJ device.
External JTAG — TODO — S3 JTAG pins, adapter classes openocd-esp32 supports, and the efuse caveat (JTAG pin selection), unverified.
All under board locks, serial, evidence in commit messages:
bt, resume — device stays functional after resume.info threads lists ESP-IDF tasks (usbd task visible).(untested) tag.board_test flashed → attach works (halt+bt); then a USB device example → record the exact JTAG failure symptom when the PHY switches. No further S3 work (external JTAG TODO).claude/improve-debug-skill-agent; commit per gate; pre-commit before each; no Co-Authored-By trailers.export.sh first (CLAUDE.md); P4/S3 examples build via idf.py — reuse existing HIL-built firmware where possible instead of rebuilding.(untested) or not at all.