Skip to content

Quick Start

This page contains complete, runnable examples for the most common tasks. Each example assumes OpenOCD is already running on localhost:6666. Both async and sync versions are provided.

The simplest possible script: connect, read the target state, and print it.

import asyncio
from openocd import Session
async def main():
async with Session.connect() as ocd:
state = await ocd.target.state()
print(f"Target: {state.name}")
print(f"State: {state.state}")
if state.current_pc is not None:
print(f"PC: 0x{state.current_pc:08X}")
asyncio.run(main())

Output when the target is halted:

Target: stm32f1x.cpu
State: halted
PC: 0x08001234

Control the target execution state.

import asyncio
from openocd import Session
async def main():
async with Session.connect() as ocd:
# Halt the target
state = await ocd.target.halt()
print(f"Halted at PC=0x{state.current_pc:08X}")
# Single-step one instruction
state = await ocd.target.step()
print(f"Stepped to PC=0x{state.current_pc:08X}")
# Resume execution
await ocd.target.resume()
print("Target resumed")
asyncio.run(main())

Read memory at various widths and display a hexdump.

import asyncio
from openocd import Session
async def main():
async with Session.connect() as ocd:
# Read 4 words (32-bit) from the vector table
words = await ocd.memory.read_u32(0x08000000, count=4)
for i, w in enumerate(words):
print(f" [0x{0x08000000 + i*4:08X}] = 0x{w:08X}")
# Read raw bytes
data = await ocd.memory.read_bytes(0x08000000, 32)
print(f"\nFirst 32 bytes: {data.hex()}")
# Pretty hexdump
dump = await ocd.memory.hexdump(0x08000000, 64)
print(f"\n{dump}")
asyncio.run(main())

Access CPU registers by name, with convenience methods for common ARM Cortex-M registers.

import asyncio
from openocd import Session
async def main():
async with Session.connect() as ocd:
await ocd.target.halt()
# Read individual registers
pc = await ocd.registers.pc()
sp = await ocd.registers.sp()
lr = await ocd.registers.lr()
print(f"PC=0x{pc:08X} SP=0x{sp:08X} LR=0x{lr:08X}")
# Read several at once
values = await ocd.registers.read_many(["r0", "r1", "r2", "r3"])
for name, val in values.items():
print(f" {name} = 0x{val:08X}")
# Read all registers
all_regs = await ocd.registers.read_all()
print(f"\n{len(all_regs)} registers available")
# Write a register
await ocd.registers.write("r0", 0x42)
await ocd.target.resume()
asyncio.run(main())

Write a firmware image to flash memory with automatic erase and verification.

import asyncio
from pathlib import Path
from openocd import Session
async def main():
async with Session.connect() as ocd:
firmware = Path("build/firmware.bin")
# Program flash (erases affected sectors, writes, then verifies)
await ocd.flash.write_image(firmware, erase=True, verify=True)
print("Flash programming complete")
# Reset and run the new firmware
await ocd.target.reset(mode="run")
asyncio.run(main())

Load an SVD file to decode peripheral registers into named bitfields. This is especially useful for reading GPIO, timer, and peripheral configuration registers.

import asyncio
from pathlib import Path
from openocd import Session
async def main():
async with Session.connect() as ocd:
await ocd.target.halt()
# Load the SVD file for your chip
await ocd.svd.load(Path("STM32F103xx.svd"))
# List available peripherals
peripherals = ocd.svd.list_peripherals()
print(f"Peripherals: {', '.join(peripherals[:5])}...")
# Read and decode a specific register
odr = await ocd.svd.read_register("GPIOA", "ODR")
print(odr)
# GPIOA.ODR @ 0x4001080C = 0x00000010
# [ 0] ODR0 = 0x0
# [ 1] ODR1 = 0x0
# ...
# [ 4] ODR4 = 0x1
# ...
# Decode a value without reading hardware
decoded = ocd.svd.decode("GPIOA", "CRL", 0x44444444)
print(decoded)
await ocd.target.resume()
asyncio.run(main())

Discover all TAPs (Test Access Ports) on the JTAG chain.

import asyncio
from openocd import Session
async def main():
async with Session.connect() as ocd:
taps = await ocd.jtag.scan_chain()
for tap in taps:
print(
f" {tap.name:<25s} IDCODE=0x{tap.idcode:08X} "
f"IR={tap.ir_length} enabled={tap.enabled}"
)
asyncio.run(main())

Catch specific exceptions for different failure modes.

from openocd import (
Session,
ConnectionError,
TargetError,
TargetNotHaltedError,
TimeoutError,
)
with Session.connect_sync() as ocd:
try:
ocd.target.halt()
pc = ocd.registers.pc()
print(f"PC = 0x{pc:08X}")
except TargetNotHaltedError:
print("Target must be halted to read registers")
except TimeoutError:
print("Operation timed out")
except TargetError as e:
print(f"Target error: {e}")

See the Error Handling guide for the full exception hierarchy.

Instead of starting OpenOCD manually, let the library manage it:

import asyncio
from openocd import Session
async def main():
config = "-f interface/cmsis-dap.cfg -f target/stm32f1x.cfg"
async with Session.start(config, timeout=15.0) as ocd:
state = await ocd.target.state()
print(f"Target: {state.name}, State: {state.state}")
# OpenOCD process stops when the context manager exits
asyncio.run(main())