Getting Started with OpenOCD: A Beginner’s Guide for Embedded Developers
A beginner-friendly guide to installing, configuring, and using OpenOCD for flashing and debugging microcontrollers.

If you're anything like me, you probably have a set of go-to tools you love, and you genuinely appreciate the freedom of choosing them. That's why being locked into vendor-specific tools can feel like a real violation of that freedom.
Debuggers are often one such offender! Their quality can vary quite a bit, and jumping from one vendor's chip to another often forces you to learn an entirely new set of tools.
Well, I have something for you that can really unify your setup! It is called OpenOCD, or Open On-Chip Debugger. It is a powerful open-source and cross-platform tool. It lets you flash firmware and debug using GDB, and it supports a wide range of microcontrollers (such asSTM32, RP2040, ESP32) and debug probes (including ST-Link, CMSIS-DAP, J-Link).
Curious how it works? I’ll walk you through the basics, show you how to install it and get started!
How does OpenOCD Actually work?
OpenOCD acts as a bridge between your debugger software and your physical embedded device (the microcontroller). It connects to your board over a debug interface like SWD or JTAG, using a debug probe.

Once the hardware connections are done, running OpenOCD will start several servers, most notably a GDB server . The debugger (e.g. arm-none-eabi-gdb
) connects to OpenOCD GDB server which provides high level interface to issue commands. OpenOCD translates these commands into low-level commands that are specific to the chosen debug probe and target controller.
In essence it abstracts away complex low-level hardware communication, providing a standardized interface for various debug probes and embedded targets.
Installing OpenOCD (Linux/Debian)
On a Debian-based machine (Ubuntu/Mint/Pi OS), installing OpenOCD is straightforward:
sudo apt update
sudo apt install openocd
Verify that openocd
is installed:
$ openocd --version
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Installing OpenOCD (Windows and MacOS)
For Windows and macOS, the easiest way to acquire OpenOCD is by using the xPack project binaries, available for download from GitHub.
After downloading and extracting the files, you will need to add the xPack OpenOCD /bin
and /openocd/scripts
directories to the system path. The scripts
directory is needed for OpenOCD to locate the /target
and /interface
scripts.
Once system path is updated, open a terminal and verify the installation:
$ openocd --version
xPack Open On-Chip Debugger 0.12.0+dev-01312-g18281b0c4-dirty (2023-09-04-22:32)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Flashing and Debugging a NUCLEO Board
For this example I will be using an STMicroelectronics NUCLEO board. So let's walk through flashing the microcontroller using the onboard ST-Link debug probe.
OpenOCD typically just needs two configuration files, one for the interface and one for the target. When you are using any of the NUCELO boards the interface file should be interface/stlink.cfg
.
For the target you need to choose the correct controller for your specific board. In my case, since I have the stm32f103RB chip, I'll use the target/stm32f1x.cfg
file.
Step 1: Connect Hardware and Run OpenOCD
$ openocd -f interface/stlink.cfg -f target/stm32f1x.cfg
Open On-Chip Debugger 0.12.0
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : clock speed 1000 kHz
Info : STLINK V2J33M25 (API v2) VID:PID 0483:374B
Info : Target voltage: 3.255680
Info : [stm32f1x.cpu] Cortex-M3 r1p1 processor detected
Info : [stm32f1x.cpu] target has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f1x.cpu on 3333
Info : Listening on port 3333 for gdb connections
Step 2: Connect GDB
Open a new terminal window and run the arm-none-eabi-gdb
with the desired binary:
arm-none-eabi-gdb blinky.elf
Once inside the GDB prompt, execute the following commands:
target remote localhost:3333
monitor reset halt
load
continue
These commands will perform the following actions. First, GDB will connect to the OpenOCD server running on your machine (localhost
) on port 3333
. Then OpenOCD will reset the target and halt its execution. The load
command will then flash the binary provided to GDB (blinky.elf
) onto the target. Finally, continue
will instruct the target to resume its execution.
Congratulations — you’re now debugging a microcontroller using OpenOCD! You are now FREE from the Vendors grip.

Debugging with VS Code
While debugging in a terminal can certainly make you feel like a real "hackerman", integrating OpenOCD with an IDE offers many quality-of-life improvements, as we would not want to fall short of vendor-provided IDEs, would we!
OpenOCD integrates with many popular IDEs and text editors, including Clion, Eclipse and VS Code. I'll show you how to set up debugging in VS Code, which is my go-to editor.
First we need to install a community extension, called "Cortex-Debug" by marus25 (Found under VS Codes Extensions Marketplace).
Once we have it installed, we need to create a launch.json
file in the .vscode
directory. This file will define how the debugging is setup.
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug with OpenOCD",
"type": "cortex-debug",
"request": "launch",
"executable": "${workspaceFolder/out/blinky.elf",
"servertype": "openocd",
"toolchainPrefix": "arm-none-eabi",
"device": "STM32F103",
"interface": "swd",
"svdFile": ".svd/STM32F103.svd",
"configFiles": [
"interface/stlink.cfg",
"target/stm32f1x.cfg"
],
"postRestartCommands": [
"break main",
"continue"
],
"showDevDebugOutput": "none"
}
]
}
Let's go over some of the fields:
request
Defines the type of debug session,launch
will start a new debug session (typically flashing and running the program), whileattach
connects to an already running program.executable
this will be the program we want to flash and debugservertype
which type of GDB server we are communicating with (other options would bejlink
andpyocd
)svdFile
points to the System View Description (.svd) file that describes target peripheral which can give us a human-readable view of peripheral registers and their values during debuggingconfigFiles
are the same files we provided on the command linepostRestartCommands
these are GDB commands that will be executed after the target is reset, when first flashed or when reset during a debug session. In this example we set a break point atmain
to stop program execution.
Now, when we click the Debug tab in VS Code and start our debugging session, we'll be able to step through our code directly, inspect variable and register values, and even monitor peripheral values.


What’s Next?
While debugging on your local machine is incredibly useful, the true power of OpenOCD extends far beyond. Have you ever wished you could have a dedicated, low-power debugging station, perhaps accessible from anywhere in your home or office?
In the next post, we'll explore using a dev
server for remote development!

Including External Libraries in CMake Projects
Learn how to use CMake’s FetchContent module to automatically download and integrate libraries like CMSIS into your embedded projects, eliminating the hassle of manual copying and updates.

How to Find the Memory Address of a Symbol in an ELF File
A quick and useful tip for locating symbol memory addresses in ELF files using arm-none-eabi-nm combined with grep—perfect for embedded debugging scenarios like setting up SEGGER RTT or inspecting linker placements and runtime symbols.

Remote Debugging with OpenOCD on Raspberry Pi
Learn how to turn a Raspberry Pi into a remote debugging server for the RP2040 using OpenOCD, a complete with step-by-step setup and instructions for building OpenOCD from source to resolve hardware compatibility issues.
Whether you're building something new, fixing stability issues, or automating what slows your team down — we can help.