armhub.dev
Tools · 10 pages
Tools

OpenOCD & probes

ST-Link, J-Link, CMSIS-DAP, Black Magic — the debug probes you'll meet, what OpenOCD does, and the alternatives (pyOCD, probe-rs).

3 min read · 617 wordsupdated · May 12, 2026

A debug probe is a USB-to-SWD/JTAG bridge that lets your host computer talk to the chip's Debug Access Port. OpenOCD is the open-source server that drives the probe. There are several probes worth knowing and a few alternatives to OpenOCD.

The probes

ProbeCostStrengthsCaveats
ST-Link V2/V3$5–$25Bundled on every ST dev board, fastST chips only (in OpenOCD)
J-Link EDU$60Best-in-class speed, RTT, flash driversEducational-only license
J-Link Base/Plus/Pro$400–$1500Commercial, full speed, all featuresExpensive
CMSIS-DAP (DAPLink)$5–$30ARM-blessed, USB MSC drag-drop flashSlower than J-Link
Black Magic Probe$70Built-in GDB server, no OpenOCD neededSlower for big flashes
PicoProbe$5Raspberry Pi Pico programmed as a probeWorks for most Cortex-M
Tag-Connect probesvariesSpring-loaded contact for no-header debugAwkward without a stand

For new development, the practical defaults are:

  • ST-Link V3 if you're on STM32 (bundled with Nucleo/Discovery, $25 standalone).
  • CMSIS-DAP for everything else, especially if your team needs cross-platform support.
  • J-Link Base when you need its speed (high-rate RTT logging, large flashes).

OpenOCD architecture

    GDB ───┬─── gdb-server :3333    ┬
    Telnet ┴─── command port :4444 ─┤   openocd
                                    │
                                    ├── probe driver (hla, jlink, cmsis-dap, ...)
                                    │
                                    └── target driver (cortex_m, stm32f4x, ...)

OpenOCD's two big knobs:

  1. Interface config — which probe. -f interface/stlink.cfg, -f interface/cmsis-dap.cfg, -f interface/jlink.cfg.
  2. Target config — which chip. -f target/stm32f4x.cfg, -f target/nrf52.cfg, -f target/rp2040.cfg.

Combined:

openocd -f interface/stlink.cfg -f target/stm32f4x.cfg

The two files configure the SWD pins/protocol and the chip's flash size, RAM size, debug ports respectively. OpenOCD ships hundreds of board-specific configs in share/openocd/scripts/ — board/st_nucleo_f4.cfg, board/raspberrypi-pico.cfg, etc.

Probe to target memory bus path
corememoryradioperiph
USBSWD/JTAGmem r/whalt / stepHostGDB / OpenOCDProbeST-Link / J-Link / DAPLinkSWJ-DPSWD or JTAG entryDAPDebug Access PortAHB-APMemory access portBusAHBCoreCortex-M
OpenOCD never touches the core directly — every memory read, breakpoint write, and halt request travels host to probe to SWD to DAP to AP and only then onto the target's AHB bus.

OpenOCD telnet console

While OpenOCD is running, connect to its command port:

telnet localhost 4444
> reset halt
> mdw 0x40023830 4        # memory display word — 4 words at RCC->AHB1ENR
> mww 0x40023830 0x1      # memory write word
> flash write_image erase firmware.bin 0x08000000
> flash verify_image firmware.bin 0x08000000
> reset run

Same commands work from GDB via monitor <command>. The telnet console is handy for one-off poking without firing up GDB.

OpenOCD adapter speed

> adapter speed 4000      # 4 MHz SWD clock

Higher speed = faster flashing and faster step. Most modern probes do 4–8 MHz cleanly; some chips are sensitive to long traces or 1.8 V signalling and need to back off. Start at 1 MHz, scale up until it gets unreliable, then back off 20%.

J-Link comes with JLinkGDBServer, which serves the same GDB RSP as OpenOCD but is implemented by SEGGER, often faster, with built-in support for all chips J-Link knows about.

JLinkGDBServer -device STM32F407VG -if SWD -speed 4000 -port 2331
arm-none-eabi-gdb -ex "target extended-remote :2331" firmware.elf

J-Link's "Unlimited Breakpoints" feature can install software breakpoints in flash by intercepting flash reads — useful when you've exhausted the FPB's 6–8 hardware slots.

pyOCD

Python-implemented debug server, particularly strong for CMSIS-DAP probes. Bundled with the PyOCD project. Used by ARM's mbed and increasingly elsewhere.

pyocd gdbserver --target=stm32f407vg
pyocd flash --target=stm32f407vg firmware.bin
pyocd erase --target=stm32f407vg --chip

For Cortex-M development on macOS or in Python-friendly environments, pyOCD is a smooth alternative to OpenOCD.

probe-rs — the Rust ecosystem's tool

probe-rs is a one-tool replacement for OpenOCD + GDB + RTT in a single Rust binary. Despite the Rust origin, it works for C/C++ projects too.

probe-rs run --chip STM32F407VGTx firmware.elf    # flash and run
probe-rs gdb --chip STM32F407VGTx                  # GDB server
probe-rs attach --chip STM32F407VGTx --rtt-port 1  # RTT viewer

It supports ST-Link, J-Link, CMSIS-DAP, FTDI-based probes, and a growing list of native USB protocols. For modern projects (especially Rust embedded) it's often the smoothest experience.

Black Magic Probe — the no-GDB-server option

Black Magic Probe runs its own GDB server on the probe itself. You connect GDB directly to the probe over USB-serial:

arm-none-eabi-gdb firmware.elf
(gdb) target extended-remote /dev/cu.usbmodem*1
(gdb) monitor swdp_scan
(gdb) attach 1
(gdb) load
(gdb) run

No OpenOCD or other server process. Less moving parts, very nice for portable setups (BMP fits in your pocket).

Common probe problems

  • "Error: connect failed" — wrong target voltage, missing SWCLK/SWDIO connection, NRST stuck low.
  • "Error: failed to read DSCSR" — debug port locked (RDP level 2 on STM32, or fuse-locked on others). Sometimes recoverable with monitor reset_config srst_only srst_pulls_trst, sometimes the chip is bricked.
  • Random disconnects on long flashes — USB hub or cable issue. Try a direct port and a short cable.
  • Probe shows up but target doesn't — target reset issue. Try reset_config srst_only or reset_config srst_push_pull.

See also