esp-target-debug — Espressif built-in USB-JTAG backend

SkillFiles & storage

Lets your agent debug TinyUSB firmware on ESP32-S3/P4 boards over USB-Serial-JTAG, with breakpoints and task inspection.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the esp-target-debug — Espressif built-in USB-JTAG backend skill

About this capability

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 v

What this skill tells your AI

The instructions your AI receives, as published by hathach/tinyusb in .claude/skills/esp-target-debug/SKILL.md and read by ahel’s review.

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)

BoardUSB-SJ vs TinyUSB OTGJTAG while USB device runs?
espressif_p4_function_evseparate pins: USB-SJ GPIO24/25 (FS), OTG own HS PHYyes — coexist (verified: 303a:1001 + cafe:4008 simultaneously, gdb attach during live CDC traffic)
espressif_s3_devkitmONE shared PHY/portno — the same hub port flips 303a:1001 → cafe:4008 as the app boots; openocd fails esp_usb_jtag: could not find or open device!

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 (default). esptool.py read_mem/write_mem peeks and pokes registers over plain UART with the chip in download mode.

Attach

. "$IDF_PATH/export.sh"                 # openocd-esp32, riscv32-/xtensa-esp32s3-elf-gdb, esptool
openocd -c 'set ESP_RTOS FreeRTOS' -f board/esp32p4-builtin.cfg \
        -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>
# S3 is Xtensa: use xtensa-esp32s3-elf-gdb with the same arguments
  • adapter serial = the chip MAC with colons — the USB-SJ device's iSerial exactly as lsusb -v -d 303a:1001 or /dev/serial/by-id/usb-Espressif_USB_JTAG_serial_debug_unit_<MAC>-if00 prints it. (The tinyusb.json esptool uids are the CP2102N flasher serials — a different port; never pass those to openocd.)
  • 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_extusb_device_taskvPortTaskWrapper).
  • 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)

target-debug techniqueEspressif backend
GDB autopsy, bp/wpsame flow via openocd-esp32 :3333; RISC-V triggers (P4) / Xtensa 2 bp + 2 wp (S3)
Vector catchnone — breakpoint the panic handler; mcause/mepc/mtval on P4
SWO / DWT data tracenone — apptrace over JTAG is the analog (untested: needs CONFIG_APPTRACE + app init)
RTT / TU_LOGconsole on UART0 = the CP2102 flasher tty by default (verified); USB-SJ console needs sdkconfig ESP_CONSOLE_USB_SERIAL_JTAG (untested)
FreeRTOS threadsnative — set ESP_RTOS FreeRTOS (see Attach)
verifybinesptool.py verify_flash (untested)

Rig deltas

  • 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.

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.

Signals

GitHub stars
7k
Forks
2k
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
esp-target-debug
Source
github.com/hathach/tinyusb