SVD Register Decoding
Without SVD, reading a peripheral register gives you a raw hex value — say, 0x44310000
from GPIOA’s CRL register. With SVD loaded, mcjtag decodes that into named fields:
MODE0=0b01 (10 MHz output), CNF0=0b01 (open-drain), MODE1=0b11 (50 MHz output), and
so on. No datasheet lookup required.
What is SVD?
Section titled “What is SVD?”CMSIS System View Description (SVD) is an XML format defined by ARM that describes every memory-mapped peripheral on a microcontroller. Each SVD file contains:
- Peripherals — named blocks like GPIOA, USART1, RCC, TIM1
- Registers — named registers within each peripheral, with their addresses
- Bitfields — individual fields within each register, with widths, offsets, and descriptions
Chip vendors provide SVD files for their devices, usually alongside their SDK or IDE packages.
Getting SVD files
Section titled “Getting SVD files”STMicroelectronics — The community-maintained cmsis-svd-data
repository has SVD files for most STM32 families. Look in the data/STMicro directory.
# Example: download the STM32F103 SVDcurl -LO https://raw.githubusercontent.com/cmsis-svd/cmsis-svd-data/main/data/STMicro/STM32F103xx.svdNordic Semiconductor — SVD files are bundled with the nRF5 SDK and nRF Connect SDK.
Also available in the cmsis-svd-data repository under data/Nordic.
Other vendors — Check your chip vendor’s SDK download page. SVD files are typically
found alongside CMSIS packs, IDE project templates, or device support packages. The file
extension is .svd.
Loading an SVD file
Section titled “Loading an SVD file”Option 1: Environment variable (auto-loaded on startup)
Section titled “Option 1: Environment variable (auto-loaded on startup)”export OPENOCD_SVD=/path/to/STM32F103xx.svdWhen mcjtag starts and connects to OpenOCD, it automatically loads the SVD file.
This is the simplest approach — set it in your .env or MCP client config and
forget about it.
claude mcp add mcjtag -- env OPENOCD_SVD=/path/to/STM32F103xx.svd OPENOCD_CONFIG=/path/to/config.cfg uvx mcjtagOption 2: Load at runtime via tool call
Section titled “Option 2: Load at runtime via tool call”svd_inspect(svd_path="/path/to/STM32F103xx.svd")When called with svd_path, the tool loads the file and then returns the list of
available peripherals. Subsequent calls can omit svd_path — the file stays loaded
for the session.
Listing peripherals
Section titled “Listing peripherals”After loading, call with no arguments to see what is available:
svd_inspect()Returns a list of all peripherals defined in the SVD file — typically GPIOA through GPIOG, USART1-3, TIM1-4, RCC, FLASH, DMA1, ADC1, SPI1, I2C1, and the system peripherals (SCB, NVIC, SysTick, etc.). Each peripheral name is a string you pass to subsequent calls.
Decoding all registers of a peripheral
Section titled “Decoding all registers of a peripheral”svd_inspect(peripheral="GPIOA")This reads every register in the peripheral from the live target and decodes all bitfields. The response contains:
- peripheral — the name you requested
- registers — a dictionary of register name to decoded result
Each register entry includes:
- name — e.g., “CRL”
- address — the memory-mapped address, e.g., “0x40010800”
- raw_value — the 32-bit hex value read from hardware, e.g., “0x44310000”
- fields — a list of decoded bitfields, each with:
- name — field name from the SVD, e.g., “MODE0”
- value — the extracted value (integer)
- width — field width in bits
- offset — bit offset within the register
- description — text description from the SVD
Progress is reported as each register is read and decoded, which is helpful for peripherals with many registers (some timer peripherals have 20+).
Decoding a single register
Section titled “Decoding a single register”If you only care about one register, specify both the peripheral and register name:
svd_inspect(peripheral="RCC", register="CR")This reads and decodes only that register, which is faster than decoding the entire peripheral.
Workflow: “Why isn’t my UART working?”
Section titled “Workflow: “Why isn’t my UART working?””A common debugging scenario: you set up USART1 in firmware, but nothing comes out on the TX pin. Here is how to diagnose it with SVD decoding.
1. Check the clock
Section titled “1. Check the clock”The peripheral clock must be enabled before the peripheral will respond. On STM32, USART1 is on the APB2 bus.
svd_inspect(peripheral="RCC", register="APB2ENR")Look for the USART1EN bitfield. If its value is 0, the clock is disabled and
the peripheral is dead. Your firmware forgot to enable it (or the init function
never ran).
2. Check the GPIO configuration
Section titled “2. Check the GPIO configuration”USART1 TX is typically PA9, RX is PA10 (check your chip’s datasheet for the actual pin mapping).
svd_inspect(peripheral="GPIOA")For STM32F1 (which uses a different GPIO model than F4), check:
- CRH register — controls pins PA8-PA15
- PA9 (MODE9 + CNF9) should be configured as alternate function push-pull output
- PA10 (MODE10 + CNF10) should be configured as input (floating or pull-up)
For STM32F4 and newer (which use the AFR model):
- MODER — PA9 should be “alternate function” mode (0b10)
- AFRH — PA9’s alternate function should be set to AF7 (USART1)
3. Check the USART configuration
Section titled “3. Check the USART configuration”svd_inspect(peripheral="USART1")Key fields to check:
| Register | Field | What to look for |
|---|---|---|
| CR1 | UE | USART enable — must be 1 |
| CR1 | TE | Transmitter enable — must be 1 |
| CR1 | RE | Receiver enable — must be 1 (if you need RX) |
| BRR | DIV_Mantissa, DIV_Fraction | Baud rate divisor — calculate from APB clock |
| SR | TXE | TX data register empty — 1 means ready to send |
| SR | TC | Transmission complete — 1 means last byte fully shifted out |
If UE=0, the peripheral is not enabled at all. If TE=0, the transmitter is off. If BRR is 0 or a wildly wrong value, the baud rate is misconfigured.
This same pattern — clock, pins, peripheral config — applies to debugging any peripheral. SPI not working? Check SPI clock enable, GPIO AF settings, then the SPI CR1/CR2 registers.
SVD as a resource
Section titled “SVD as a resource”mcjtag also exposes SVD data as MCP resources, which the LLM can poll without making explicit tool calls:
jtag://svd/peripherals— list all loaded peripheralsjtag://svd/{peripheral}— decoded register values for a specific peripheral
Resources are read-only snapshots. Use the svd_inspect tool when you need to
load an SVD file or want progress reporting during decode.