SVD Inspection
This example demonstrates using SVD metadata to inspect hardware registers on a live target. Instead of manually masking and shifting bits from raw hex values, the SVD subsystem decodes register contents into named fields with descriptions.
Async version
Section titled “Async version”import asyncioimport loggingfrom pathlib import Path
from openocd import Session, SVDError, ConnectionError
logging.basicConfig(level=logging.INFO, format="%(message)s")log = logging.getLogger("svd-inspect")
async def main(): svd_path = Path("STM32F103.svd") if not svd_path.exists(): log.error("SVD file not found: %s", svd_path) log.error("Download from your vendor's CMSIS pack or cmsis-svd-data on GitHub") return
try: session = await Session.connect(timeout=5.0) except ConnectionError as e: log.error("Cannot connect to OpenOCD: %s", e) return
async with session: # --- Load SVD --- log.info("Loading SVD file: %s", svd_path) await session.svd.load(svd_path)
# --- Browse peripherals --- peripherals = session.svd.list_peripherals() log.info("Found %d peripherals", len(peripherals)) log.info("First 10: %s", ", ".join(peripherals[:10]))
# --- Browse registers in GPIOA --- gpio_regs = session.svd.list_registers("GPIOA") log.info("\nGPIOA registers: %s", ", ".join(gpio_regs))
# --- Halt and read live registers --- await session.target.halt()
# Read and decode GPIOA.ODR (Output Data Register) log.info("\n--- GPIOA Output Data Register ---") odr = await session.svd.read_register("GPIOA", "ODR") log.info("%s", odr)
# Read and decode GPIOA.IDR (Input Data Register) log.info("\n--- GPIOA Input Data Register ---") idr = await session.svd.read_register("GPIOA", "IDR") log.info("%s", idr)
# --- Inspect clock configuration --- log.info("\n--- RCC Clock Control Register ---") rcc_cr = await session.svd.read_register("RCC", "CR") log.info("%s", rcc_cr)
# Check specific fields for field in rcc_cr.fields: if field.name in ("HSEON", "HSERDY", "PLLON", "PLLRDY"): status = "ON" if field.value else "OFF" log.info(" %s: %s - %s", field.name, status, field.description)
# --- Read an entire peripheral --- log.info("\n--- All USART1 registers ---") try: usart_regs = await session.svd.read_peripheral("USART1") for name, decoded in usart_regs.items(): log.info("%s", decoded) log.info("") # blank line between registers except SVDError as e: log.warning("Could not read USART1: %s", e)
# --- Decode without hardware read --- log.info("\n--- Offline decode example ---") # Suppose we captured this value from a log file captured_value = 0x0300_0083 decoded = session.svd.decode("RCC", "CR", captured_value) log.info("Decoding RCC.CR = 0x%08X:", captured_value) log.info("%s", decoded)
# --- Access individual field values programmatically --- log.info("\n--- Programmatic field access ---") odr = await session.svd.read_register("GPIOA", "ODR") pin_states = [] for field in odr.fields: if field.value: pin_states.append(field.name) if pin_states: log.info("GPIOA pins driven high: %s", ", ".join(pin_states)) else: log.info("No GPIOA pins driven high")
# Resume the target await session.target.resume()
asyncio.run(main())Sync version
Section titled “Sync version”import loggingfrom pathlib import Path
from openocd import Session, SVDError, ConnectionError
logging.basicConfig(level=logging.INFO, format="%(message)s")log = logging.getLogger("svd-inspect")
def main(): svd_path = Path("STM32F103.svd") if not svd_path.exists(): log.error("SVD file not found: %s", svd_path) return
try: session = Session.connect_sync(timeout=5.0) except ConnectionError as e: log.error("Cannot connect to OpenOCD: %s", e) return
with session: # Load SVD log.info("Loading SVD file: %s", svd_path) session.svd.load(svd_path)
# Browse peripherals = session.svd.list_peripherals() log.info("Found %d peripherals", len(peripherals))
gpio_regs = session.svd.list_registers("GPIOA") log.info("GPIOA registers: %s", ", ".join(gpio_regs))
# Halt and read session.target.halt()
log.info("\n--- GPIOA Output Data Register ---") odr = session.svd.read_register("GPIOA", "ODR") log.info("%s", odr)
log.info("\n--- RCC Clock Control Register ---") rcc_cr = session.svd.read_register("RCC", "CR") log.info("%s", rcc_cr)
for field in rcc_cr.fields: if field.name in ("HSEON", "HSERDY", "PLLON", "PLLRDY"): status = "ON" if field.value else "OFF" log.info(" %s: %s", field.name, status)
# Decode a captured value without reading hardware decoded = session.svd.decode("RCC", "CR", 0x0300_0083) log.info("\nOffline decode of RCC.CR = 0x03000083:") log.info("%s", decoded)
session.target.resume()
main()Expected output
Section titled “Expected output”Loading SVD file: STM32F103.svdFound 51 peripheralsFirst 10: ADC1, ADC2, AFIO, BKP, CAN, CRC, DAC, DMA1, DMA2, EXTI
GPIOA registers: BRR, BSRR, CRH, CRL, IDR, LCKR, ODR
--- GPIOA Output Data Register ---GPIOA.ODR @ 0x4001080C = 0x00000001 [ 0:0] ODR0 = 0x1 Port output data bit 0 [ 1:1] ODR1 = 0x0 Port output data bit 1 [ 2:2] ODR2 = 0x0 Port output data bit 2 [ 3:3] ODR3 = 0x0 Port output data bit 3 ...
--- GPIOA Input Data Register ---GPIOA.IDR @ 0x40010808 = 0x0000FFFD [ 0:0] IDR0 = 0x1 Port input data bit 0 [ 1:1] IDR1 = 0x0 Port input data bit 1 ...
--- RCC Clock Control Register ---RCC.CR @ 0x40021000 = 0x03000083 [ 0:0] HSION = 0x1 Internal high-speed clock enable [ 1:1] HSIRDY = 0x1 Internal high-speed clock ready flag [ 16:16] HSEON = 0x1 HSE clock enable [ 17:17] HSERDY = 0x1 External high-speed clock ready flag [ 24:24] PLLON = 0x1 PLL enable [ 25:25] PLLRDY = 0x1 PLL clock ready flag HSEON: ON - HSE clock enable HSERDY: ON - External high-speed clock ready flag PLLON: ON - PLL enable PLLRDY: ON - PLL clock ready flag
--- Offline decode example ---Decoding RCC.CR = 0x03000083:RCC.CR @ 0x40021000 = 0x03000083 [ 0:0] HSION = 0x1 Internal high-speed clock enable ...Key points
Section titled “Key points”load()is required first. All other SVD methods raiseSVDErrorif no SVD file has been loaded.list_peripherals()andlist_registers()are synchronous — they operate on in-memory data after the initial parse. Noawaitneeded in async mode.read_register()reads from live hardware. It computes the register’s memory-mapped address from the SVD, reads 32 bits via the memory subsystem, and decodes the result. The target should be halted for consistent reads.decode()works offline. Pass a raw integer value and it returns the sameDecodedRegisterstructure without touching hardware. Useful for analyzing values from log files or crash dumps.read_peripheral()is fault-tolerant. It silently skips write-only or otherwise unreadable registers and logs warnings. The returned dict contains only registers that were successfully read.DecodedRegister.__str__produces formatted output. Each field shows its bit range, name, value, and description — no manual bit manipulation needed.