OpenOCD
Overview
In our previous post about MCU debuggers, we explored various debug interfaces and hardware probes. Now let’s dive deeper into OpenOCD (Open On-Chip Debugger), the powerful open-source tool that serves as the critical software bridge between debug hardware and development tools.
What is OpenOCD?
OpenOCD is an open-source, cross-platform debugging tool that provides programming and debugging capabilities for embedded systems. It acts as a universal translator, allowing different debug probes to communicate with various microcontrollers through standardized interfaces.
OpenOCD’s Role in the Debug Ecosystem
1
2
3
4
5
6
7
8
9
PC (OpenOCD/GDB/pyOCD)
│
│ USB + CMSIS-DAP
▼
Debug Probe (ST-Link, DAPLink...)
│
│ SWD or JTAG
▼
MCU (Cortex-M...)
Simple Flow Explanation:
- PC Layer: Development tools (OpenOCD, GDB, pyOCD) run on your computer
- Communication: USB connection using CMSIS-DAP protocol
- Debug Probe: Hardware interface (ST-Link, J-Link, DAPLink)
- Debug Protocol: SWD or JTAG signals to the microcontroller
- Target: ARM Cortex-M or other supported MCU
OpenOCD acts as the translator between:
- High-level debugging tools (GDB, IDE) ↔ Low-level hardware protocols (SWD/JTAG)
Setting Up OpenOCD
Installation
Ubuntu/Debian:
1
2
3
4
5
6
7
8
9
10
11
# Install from package manager
sudo apt update
sudo apt install openocd
# Or build from source for latest features
git clone https://git.code.sf.net/p/openocd/code openocd
cd openocd
./bootstrap
./configure --enable-cmsis-dap --enable-stlink --enable-jlink
make -j$(nproc)
sudo make install
Basic Configuration
Create a configuration file for your setup:
stm32f4_discovery.cfg:
1
2
3
4
5
6
7
8
9
10
11
# Debug probe configuration
source [find interface/stlink.cfg]
# Transport selection
transport select hla_swd
# Target configuration
source [find target/stm32f4x.cfg]
# Reset configuration
reset_config srst_only
Practical OpenOCD Usage
Basic Commands
Start OpenOCD Server:
1
2
3
4
5
# Using configuration file
openocd -f board/stm32f4discovery.cfg
# Custom configuration
openocd -f interface/cmsis-dap.cfg -f target/stm32f4x.cfg
Telnet Interface:
1
2
3
4
5
6
7
8
9
# Connect to OpenOCD telnet interface
telnet localhost 4444
# Basic commands in OpenOCD telnet
> halt # Stop CPU execution
> reset halt # Reset and halt
> flash write_image erase unlock firmware.elf
> resume # Continue execution
> shutdown # Close OpenOCD
Programming Flash Memory
1
2
3
4
# Complete programming sequence
openocd -f interface/stlink.cfg \
-f target/stm32f4x.cfg \
-c "program firmware.elf verify reset exit"
Real-World Example: LED Blink Debug Session
Let’s debug a simple LED blink program:
main.c:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include "stm32f4xx.h"
volatile uint32_t delay_counter = 0;
void delay_ms(uint32_t ms) {
for (uint32_t i = 0; i < ms * 1000; i++) {
__asm__("nop");
}
}
int main(void) {
// Enable GPIOA clock
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
// Configure PA5 as output (LED on STM32F4 Discovery)
GPIOA->MODER |= (1 << 10); // PA5 as output
GPIOA->OTYPER &= ~(1 << 5); // Push-pull
GPIOA->OSPEEDR |= (2 << 10); // High speed
while(1) {
// Toggle LED
GPIOA->ODR ^= (1 << 5);
// Delay
delay_counter++;
delay_ms(500);
}
return 0;
}
Debug Session:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. Start OpenOCD
openocd -f board/stm32f4discovery.cfg
# 2. In another terminal, connect GDB
arm-none-eabi-gdb firmware.elf
# 3. GDB commands
(gdb) target extended-remote localhost:3333
(gdb) monitor reset halt
(gdb) load
(gdb) break main
(gdb) continue
(gdb) info registers
(gdb) print delay_counter
(gdb) step
Troubleshooting Common Issues
Connection Problems
Issue: Target not found
1
2
3
4
5
6
# Check connections and power
openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -d3
# Debug output will show:
# Debug: xx xx stlink_usb.c:xxxx stlink_usb_get_version()
# Debug: xx xx stlink_usb.c:xxxx stlink_usb_check_voltage()
Issue: Flash programming failures
1
2
3
4
5
6
# Add to configuration
reset_config srst_only srst_push_pull
adapter speed 1000 # Reduce speed for stability
# Manual unlock for protected flash
stm32f2x unlock 0
Performance Optimization
Faster Programming:
1
2
3
4
5
6
# Optimize for speed
adapter speed 4000 # Increase SWD speed
set WORKAREASIZE 0x8000 # Larger work area
$_TARGETNAME configure -work-area-phys 0x20000000 \
-work-area-size $WORKAREASIZE \
-work-area-backup 0
Integration with Development Tools
VS Code Integration
launch.json:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug with OpenOCD",
"type": "cortex-debug",
"request": "launch",
"executable": "build/firmware.elf",
"servertype": "openocd",
"configFiles": [
"interface/stlink.cfg",
"target/stm32f4x.cfg"
],
"preLaunchTask": "build"
}
]
}
Best Practices
Configuration Management
- Use version-controlled configuration files
- Document custom memory maps and special requirements
- Create board-specific configuration templates
Debugging Workflow
- Always verify target connection before programming
- Use appropriate reset strategies for your hardware
- Monitor adapter speed vs. reliability trade-offs
Performance Considerations
- Optimize work area size for faster programming
- Use appropriate adapter speeds for cable length
- Consider real-time constraints when debugging
Conclusion
OpenOCD serves as the universal bridge in embedded debugging, providing flexibility and extensibility that commercial tools often lack. While it requires more initial setup and learning, its open-source nature, extensive target support, and powerful scripting capabilities make it invaluable for professional embedded development.