Skip to content

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.

import asyncio
import logging
from 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())
import logging
from 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()
Loading SVD file: STM32F103.svd
Found 51 peripherals
First 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
...
  • load() is required first. All other SVD methods raise SVDError if no SVD file has been loaded.
  • list_peripherals() and list_registers() are synchronous — they operate on in-memory data after the initial parse. No await needed 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 same DecodedRegister structure 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.