---
title: SVD Register Decoding
description: Use CMSIS SVD files to decode peripheral registers into named bitfields
sidebar:
  order: 2
---

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?

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

**STMicroelectronics** — The community-maintained [cmsis-svd-data](https://github.com/cmsis-svd/cmsis-svd-data)
repository has SVD files for most STM32 families. Look in the `data/STMicro` directory.

```bash
# Example: download the STM32F103 SVD
curl -LO https://raw.githubusercontent.com/cmsis-svd/cmsis-svd-data/main/data/STMicro/STM32F103xx.svd
```

**Nordic 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

### Option 1: Environment variable (auto-loaded on startup)

```bash
export OPENOCD_SVD=/path/to/STM32F103xx.svd
```

When 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.

```bash
claude mcp add mcjtag -- env OPENOCD_SVD=/path/to/STM32F103xx.svd OPENOCD_CONFIG=/path/to/config.cfg uvx mcjtag
```

### 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

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

```
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

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?"

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

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

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

```
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

mcjtag also exposes SVD data as MCP resources, which the LLM can poll without
making explicit tool calls:

- `jtag://svd/peripherals` — list all loaded peripherals
- `jtag://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.
