OpenOCD (Open On-Chip Debugger) is an open-source tool that provides on-chip debugging, in-system programming, and boundary-scan testing for embedded targets. It acts as a bridge between a debug probe (such as J-Link, ST-Link, or CMSIS-DAP compatible adapters) and a higher-level debugger or programming tool. In the most common workflow it communicates with the host over GDB's remote serial protocol, but it also exposes telnet and TCL command interfaces that can be used independently of GDB.
In practice
OpenOCD is most commonly used in ARM Cortex-M and Cortex-A workflows, though it also includes support for MIPS, RISC-V, and several other architectures; the depth of that support varies by architecture, target device, and the adapter drivers available in a given build. A typical setup has OpenOCD connecting to a hardware debug adapter over USB, opening a GDB server on a local TCP port (default 3333), and forwarding debug traffic to the target via JTAG or SWD. GDB, or an IDE that wraps GDB (such as Eclipse CDT, VS Code with the Cortex-Debug extension, or CLion), then connects to that port. This layered approach means you can swap debug probes or target configurations without changing your GDB setup.
Flash programming is a common standalone use of OpenOCD even outside of interactive debug sessions. Scripts invoked via the `telnet` interface or the `-c` command-line flag can erase and program internal or external flash, verify the image, and reset the target. Many Makefile and CMake-based build systems include a `flash` target that calls OpenOCD directly, avoiding the need for vendor-specific programming utilities. Chip-specific configuration files (`.cfg` files) for a wide range of MCUs and boards ship with the OpenOCD distribution.
Configuration is the main friction point when first setting up OpenOCD. You must supply an interface config file (describing the probe) and a target config file (describing the MCU and debug transport). Mismatched clock speeds, incorrect transport selection (JTAG vs. SWD), or a missing `reset_config` directive are common sources of early failures. When debugging multicore parts such as STM32MP1 or i.MX RT crossover MCUs, additional care is needed to select and step between cores correctly.
OpenOCD's semihosting support allows firmware to perform host I/O operations (including writing output to the host console) via the debug connection, which is useful for targets without a UART. On Cortex-M parts, ARM semihosting calls (via `BKPT 0xAB`) are handled transparently by OpenOCD when semihosting is enabled in the target config. The "Debug, visualize and test embedded C/C++ through instrumentation" post on EmbeddedRelated covers complementary instrumentation approaches that pair well with OpenOCD-based debug sessions.
Discussed on EmbeddedRelated
Frequently asked
Which debug probes does OpenOCD support?
OpenOCD supports a wide range of adapters, including ST-Link (V2 and V3), J-Link, CMSIS-DAP / DAPLink compatible probes, FTDI-based adapters (such as the FT2232H and FT232H), Raspberry Pi
GPIO bit-bang, and many others. The exact set of supported probes depends on the interface drivers compiled into your particular OpenOCD build; pre-built binaries from xPack or distro packages typically include the most common drivers, but coverage can vary across distributions.
How does OpenOCD relate to GDB?
OpenOCD and
GDB are separate tools that, in the standard setup, communicate over a TCP socket using GDB's remote serial protocol. OpenOCD handles the low-level debug transport (
JTAG or
SWD signaling,
flash algorithms, reset sequencing) while GDB handles breakpoints, watchpoints, memory inspection, and source-level stepping. You connect GDB to OpenOCD with the command `target extended-remote localhost:3333` (or port 3333 by default).
Can OpenOCD program flash without running a full GDB session?
Yes. You can invoke OpenOCD from the command line with a sequence of `-c` commands to init, halt the target, run `program` or `
flash write_image`, verify, and reset. For example: `openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c "program firmware.
elf verify reset exit"`. This is commonly used in CI pipelines and build system flash targets.
OpenOCD fails to connect to my target. Where do I start?
Check the following in order: confirm the probe is recognized by the OS (use `lsusb` or Device Manager); verify you are using the correct interface and target `.cfg` files; lower the
JTAG/
SWD clock speed (`adapter speed 500` in kHz is a safe starting point); check that the target is powered and not held in reset by external circuitry; and confirm the correct transport (`transport select swd` for SWD-only parts like most Cortex-M0/M0+ devices). OpenOCD's verbose output (`-d3` flag) usually points directly at the failure.
What is the difference between OpenOCD and pyOCD?
Both tools serve as
GDB servers and
flash programmers for ARM targets, but they differ in scope and design. OpenOCD supports a broader set of architectures (MIPS,
RISC-V, and more) and a larger probe ecosystem built around interface driver plugins. pyOCD is a Python-based tool focused specifically on ARM Cortex-M parts, with tight integration with CMSIS-Pack flash algorithms and a simpler Python API for scripting. For Cortex-M development, either can work; pyOCD tends to be easier to install and script, while OpenOCD offers wider hardware coverage.
Differentiators vs similar concepts
OpenOCD is often compared to pyOCD and J-Link
GDB Server. pyOCD is ARM Cortex-M-only and Python-based, making it easier to script and install via pip, but it covers fewer probe types and architectures than OpenOCD. J-Link GDB Server is a closed-source tool from SEGGER that is tightly optimized for J-Link probes and generally offers faster
flash programming and more reliable multi-core support on complex SoCs, but it requires a J-Link probe (or a device with a licensed J-Link OB) and is not open source. OpenOCD's main advantages are its open-source nature, broad probe and architecture support, and zero licensing cost.