build
Phase 3 of AI Closed-Loop Programming — the Build phase, and the driver of the whole loop: locate the project on the chain, name the next act, design and…
Remote GDB debugging of ESP32 devices via the testbench. Covers USB JTAG (C3/S3), dual-USB (S3 two-port), and ESP-Prog (FT2232H) approaches. Use when setting up JTAG debugging, connecting GDB, configuring OpenOCD, or troubleshooting debug connections. Triggers on "GDB", "JTAG",
$ npx -y skills add SensorsIot/Embedded-AI-Harness --skill testbench-debug --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/testbench-debugContext preview
The summary Claude sees to decide when to auto-load this skill.
Remote GDB debugging of ESP32 devices via the testbench. Covers USB JTAG (C3/S3), dual-USB (S3 two-port), and ESP-Prog (FT2232H) approaches. Use when setting up JTAG debugging, connecting GDB, configuring OpenOCD, or troubleshooting debug connections. Triggers on "GDB", "JTAG",
name: testbench-debug description: Remote GDB debugging of ESP32 devices via the testbench. Covers USB JTAG (C3/S3), dual-USB (S3 two-port), and ESP-Prog (FT2232H) approaches. Use when setting up JTAG debugging, connecting GDB, configuring OpenOCD, or troubleshooting debug connections. Triggers on "GDB", "JTAG", "debug", "OpenOCD", "breakpoint", "ESP-Prog", "step through", "debug session".
Remote GDB debugging of ESP32 devices through the testbench Pi. OpenOCD runs on the Pi, GDB connects from the container over TCP.
**Architecture:**
[Container] [Pi (testbench)] [ESP32]
GDB ──── TCP :3333 ────── OpenOCD ──── USB JTAG ──────── CPU
(or)
OpenOCD ──── ESP-Prog ── JTAG pins---
| Approach | Chips | Extra Hardware | Serial During Debug | |----------|-------|:-:|:-:| | **USB JTAG** (FR-024) | C3, S3 (native USB only) | None | Yes | | **Dual-USB** (FR-025) | S3 (two USB connectors) | None | Yes + app USB | | **ESP-Prog** (FR-026) | All ESP32 variants | ESP-Prog (~$15) + cable | Yes |
---
OpenOCD starts **automatically** when a device is plugged in or at boot. No API call needed.
**How it works:** 1. Device hotplugged → serial proxy starts → auto-detect tries OpenOCD configs 2. Chip identified via JTAG TAP ID → OpenOCD starts on the assigned GDB port 3. If USB JTAG fails (e.g. classic ESP32), falls back to ESP-Prog probe if available 4. GDB port reported in `/api/devices` response
**Check debug status:**
curl $TESTBENCH_URL/api/devices # Look for: "debugging": true, "debug_chip": "esp32s3", "debug_gdb_port": 3335
**Manual override (optional -- only needed to force-stop or force-start):**
# Force stop (won't auto-restart until next hotplug)
curl -X POST $TESTBENCH_URL/api/debug/stop -d '{}'
# Force start with specific chip
curl -X POST $TESTBENCH_URL/api/debug/start \
-d '{"chip": "esp32c3"}'---
When a debug session is active, the testbench automatically uses **JTAG reset** instead of DTR/RTS serial reset. This is transparent — the same `/api/serial/reset` API is used.
**Why JTAG reset is better:**
**Via OpenOCD telnet (manual):**
# Soft reset (chip reboots normally) echo "reset run" | nc "$BENCH" 4446 # Halt CPU (stops execution immediately) echo "halt" | nc "$BENCH" 4446 # Reset and halt (for debugging from first instruction) echo "reset halt" | nc "$BENCH" 4446
**Via testbench API (automatic):**
# Uses JTAG reset when debug session is active, DTR/RTS otherwise
curl -X POST $TESTBENCH_URL/api/serial/reset \
-H "Content-Type: application/json" -d '{"slot": "SLOT1"}'**Availability:** | Scenario | JTAG reset? | |----------|:-:| | C3/S3/C6/H2 with native USB | Yes (auto-started) | | Classic ESP32 + ESP-Prog | Yes (when probe wired) | | Classic ESP32 without ESP-Prog | No — DTR/RTS fallback |
---
OpenOCD is pre-installed on the Pi:
/usr/local/bin/openocd-esp32 # binary /usr/local/share/openocd-esp32/scripts/ # config files
If missing, run `install.sh` or manually:
# On Pi (aarch64) wget https://github.com/espressif/openocd-esp32/releases/download/v0.12.0-esp32-20260304/openocd-esp32-linux-arm64-0.12.0-esp32-20260304.tar.gz tar xzf openocd-esp32-linux-arm64-*.tar.gz sudo cp openocd-esp32/bin/openocd /usr/local/bin/openocd-esp32 sudo mkdir -p /usr/local/share/openocd-esp32 sudo cp -r openocd-esp32/share/openocd/scripts /usr/local/share/openocd-esp32/scripts
---
The device must show as `303a:1001` (Espressif USB JTAG/serial debug unit). Boards with CH340/CP2102 UART bridges do NOT support USB JTAG.
# Check from Pi ssh pi@<bench-hostname> "lsusb -d 303a:1001" # → Bus 001 Device 066: ID 303a:1001 Espressif USB JTAG/serial debug unit
USB interface layout (no kernel unbind needed):
USB PID `303a:1001` is the same for C3 and S3. The JTAG TAP ID identifies the chip:
| TAP ID | Chip | Architecture | Config | |--------|------|-------------|--------| | `0x00005c25` | ESP32-C3 | RISC-V single-core | `esp32c3-builtin.cfg` | | `0x00010c25` | ESP32-H2 | RISC-V single-core | `esp32h2-builtin.cfg` | | `0x0000dc25` | ESP32-C6 | RISC-V single-core | `esp32c6-builtin.cfg` | | `0x120034e5` | ESP32-S3 | Xtensa dual-core | `esp32s3-builtin.cfg` |
# ESP32-C3 ssh pi@<bench-hostname> "openocd-esp32 -s /usr/local/share/openocd-esp32/scripts \ -f board/esp32c3-builtin.cfg \ -c 'gdb port 3333' -c 'telnet port 4444' -c 'bindto 0.0.0.0'" # ESP32-S3 ssh pi@<bench-hostname> "openocd-esp32 -s /usr/local/share/openocd-esp32/scripts \ -f board/esp32s3-builtin.cfg \ -c 'gdb port 3333' -c 'telnet port 4444' -c 'bindto 0.0.0.0'"
# C3 (RISC-V) riscv32-esp-elf-gdb build/project.elf \ -ex "target extended-remote $BENCH:3333" \ -ex "monitor reset halt" # S3 (Xtensa) xtensa-esp32s3-elf-gdb build/project.elf \ -ex "target extended-remote $BENCH:3333" \ -ex "monitor reset halt"
import socket, time
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((BENCH, 4444))
time.sleep(0.5)
banner = s.recv(4096) # telnet negotiation + "Open On-Chip Debugger"
s.sendall(b'halt\n')
time.sleep(1)
print(s.recv(4096).decode('latin-1')) # "Target halted, PC=0x..."
s.sendall(b'resume\n')
time.sleSpec to silicon, hands off. A horse is strong, fast, and willing — and useless for heavy loads until you harness it. The harness is not a part of the horse and not a part of the cart: it is the coupling that turns raw strength into pulled weight.
Phase 3 of AI Closed-Loop Programming — the Build phase, and the driver of the whole loop: locate the project on the chain, name the next act, design and…
Phase 2 of AI Closed-Loop Programming — Commissioning: prove the project's OWN never-seen-working parts (its board, its wiring, its peers/simulators), so that…
Phase 0 of AI Closed-Loop Programming — Definition: engineers the WHAT the loop converges on. Writes and evolves the FSD — atomic, falsifiable,…
Complete ESP-IDF lifecycle: project setup, build, flash, monitor, and OTA. Automatically detects whether a testbench is available or the device is connected…
PlatformIO lifecycle for ESP32 firmware: platformio.ini, environment selection, build, upload and serial monitor, on local USB or through the testbench. Covers…
Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to…