| name | openocd-jtag |
| description | OpenOCD skill for embedded hardware debugging. Use when configuring OpenOCD for JTAG or SWD targets, flashing firmware, connecting GDB to bare-metal targets, setting hardware watchpoints, or using J-Link with OpenOCD. Activates on queries about OpenOCD, JTAG, SWD, GDB remote target, flash programming, hardware breakpoints, J-Link, or connecting GDB to an MCU. |
OpenOCD / JTAG Debugging
Purpose
Guide agents through configuring OpenOCD for JTAG and SWD targets, flashing firmware to microcontrollers, attaching GDB for bare-metal debugging, setting hardware watchpoints, and configuring J-Link and CMSIS-DAP adapters.
Triggers
- "How do I connect GDB to my MCU with OpenOCD?"
- "How do I flash firmware using OpenOCD?"
- "How do I set up J-Link with OpenOCD?"
- "What's the difference between JTAG and SWD?"
- "How do I set a hardware watchpoint in GDB?"
- "OpenOCD says 'Error: unable to find JTAG device' — how do I fix it?"
Workflow
1. JTAG vs SWD
| Feature | JTAG | SWD (Serial Wire Debug) |
|---|
| Pins | 4+ (TCK, TMS, TDI, TDO, TRST) | 2 (SWCLK, SWDIO) |
| Multi-target | Yes (daisy chain) | No (one target) |
| Speed | Up to 30 MHz | Up to 10 MHz |
| Availability | Full JTAG: Cortex-A/R, RISC-V | SWD: Cortex-M only |
| Cable cost | More complex | Simpler 2-wire |
Most Cortex-M microcontrollers support both. Use SWD when pin count is limited.
2. OpenOCD configuration
# openocd.cfg — CMSIS-DAP (ST-Link v2, DAPLink)
source [find interface/cmsis-dap.cfg]
source [find target/stm32f4x.cfg]
adapter speed 4000 # kHz
# For SWD explicitly
transport select swd
# J-Link adapter
source [find interface/jlink.cfg]
jlink serial 123456789 # optional: select by serial
source [find target/nrf52.cfg]
adapter speed 8000
openocd -f openocd.cfg
ls $(openocd --help 2>&1 | grep "scripts" | head -1)/interface/
ls $(openocd --help 2>&1 | grep "scripts" | head -1)/target/
3. Connecting GDB
openocd -f openocd.cfg
arm-none-eabi-gdb firmware.elf
(gdb) target extended-remote :3333
(gdb) monitor reset halt
(gdb) load
(gdb) monitor reset init
(gdb) break main
(gdb) continue
arm-none-eabi-gdb -ex "target extended-remote :3333" \
-ex "monitor reset halt" \
-ex "load" \
-ex "break main" \
-ex "continue" \
firmware.elf
4. Flashing firmware
telnet localhost 4444
> reset halt
> program firmware.elf verify reset
> exit
(gdb) monitor flash write_image erase firmware.bin 0x08000000
(gdb) monitor reset run
openocd -f openocd.cfg \
-c "program firmware.elf verify reset exit"
openocd -f openocd.cfg \
-c "program firmware.bin 0x08000000 verify reset exit"
5. Hardware breakpoints and watchpoints
Software breakpoints (break) patch instruction memory with trap instructions — they don't work in flash-execute-in-place without debug registers. Use hardware breakpoints instead:
(gdb) hbreak function_name
(gdb) hbreak *0x08001234
(gdb) watch global_variable
(gdb) rwatch some_buffer
(gdb) awatch sensor_value
(gdb) info breakpoints
6. OpenOCD commands reference
monitor reset halt
monitor reset init
monitor reset run
monitor halt
monitor resume
monitor mdw 0x20000000
monitor mww 0x40021000 0x1
monitor reg r0
monitor arm disassemble 0x08000000 16
monitor flash list
monitor flash erase_sector 0 0 0
monitor flash write_bank 0 firmware.bin 0
7. Common errors
| Error | Cause | Fix |
|---|
unable to find JTAG device | Wrong interface, cable, or power | Check USB connection; power target; verify interface config |
JTAG scan chain interrogation failed | Wrong target config or bad SWD mode | Match config to exact MCU; try transport select swd |
flash 'stm32f4x' is not supported | Wrong target | Check MCU part number; use correct .cfg |
Error: timed out while waiting for target halted | Target running, not halted | monitor halt; check BOOT pins |
Cannot access memory at address | MMU, memory protection, or wrong address | Check MPU config; use correct flash/RAM address |
Warn: target not examined yet | OpenOCD not connected to target | Check power and connections |
8. J-Link configuration
# openocd.cfg for J-Link
source [find interface/jlink.cfg]
jlink usb 0 # use first J-Link found
transport select swd # or jtag
adapter speed 4000
source [find target/stm32l4x.cfg]
J-Link GDB Server (alternative to OpenOCD):
JLinkGDBServer -if SWD -device STM32L476RG -port 3333 &
arm-none-eabi-gdb -ex "target remote :3333" firmware.elf
Related skills
- Use
skills/embedded/freertos for FreeRTOS-aware debugging with OpenOCD
- Use
skills/embedded/zephyr for Zephyr's west debug integration
- Use
skills/debuggers/gdb for GDB session management
- Use
skills/embedded/linker-scripts for understanding memory map for flash addresses