Skip to main content
Glama
jpdev2022

STM32 J-Link MCP

by jpdev2022
README.md
# STM32 J-Link MCP

AI-native hardware debugging and firmware-engineering interface for **STM32H7S3** using **SEGGER J-Link**.

This project is deliberately more than a thin wrapper around `JLinkExe`. It provides a stateful semantic layer for AI agents such as Claude Code, Codex, and Hermes while keeping SEGGER's J-Link tools as the low-level hardware backend.

## Design goals

- **Stateful debug session:** J-Link and GDB ownership are coordinated instead of being independent subprocesses.
- **Semantic tools:** expose target, memory, flash, GDB, Cortex-M fault, SVD, XSPI, and workflow operations.
- **AI-friendly output:** return compact structured evidence and stable error codes instead of terminal transcripts where possible.
- **STM32H7S3 specialization:** encode verified memory-map facts and Cortex-M diagnostics without pretending that a board-specific external NOR configuration is universal.
- **Safety:** read-only mode, bounded writes, explicit confirmation for destructive operations, and raw-command escape hatch disabled by default.
- **Extensibility:** J-Link, GDB, target profiles, SVD, and diagnostics are separate layers so additional STM32 families or probe backends can be added later.

## Current hardware profile

The checked-in example configuration is tailored to the current custom target:

- **MCU:** STM32H7S3I8T6, LQFP176
- **SEGGER J-Link device name:** `STM32H7S3I8`
- **External memory:** XSPI1
- **NOR:** assumed Macronix `MX25UW51245GXDI00`, 512 Mbit / 64 MiB
- **Memory-mapped base:** `0x90000000`
- **Expected RDID:** `C2 81 3A`

This is a board profile, not a claim that the external NOR is currently initialized. See `docs/BOARD_STM32H7S3I8T6_XSPI1.md` before enabling any programming workflow.

## Architecture

```text
AI Agent (Claude / Codex / Hermes)
              |
              | MCP / stdio
              v
      +---------------------+
      | Semantic MCP tools  |
      +----------+----------+
                 |
                 v
      +---------------------+
      | DebugSessionManager |
      | state / ownership   |
      | safety / locking    |
      +----+-----------+----+
           |           |
           v           v
    +-----------+   +-----------+
    | J-Link    |   | GDB       |
    | backend   |   | session   |
    +-----+-----+   +-----+-----+
          |               |
          v               v
     JLinkExe        JLinkGDBServer
          |               |
          +-------+-------+
                  |
                J-Link
                  |
                 SWD
                  |
             STM32H7S3
          /       |        \
       Flash     SRAM      XSPI
                            |
                       External NOR
```

### Important ownership rule

Do not concurrently use `JLinkExe` and GDB to control the same target. The session manager treats GDB as an owner of the live debug connection while a GDB session is active. Low-level one-shot J-Link operations should be used before/after the GDB session, or only when the session explicitly permits them.

## STM32H7S3 memory-map facts

The STM32H7Rx/7Sx reference manual places the following windows in the Cortex-M7 address space:

- User flash: `0x08000000` upward.
- System flash: `0x1FF00000` to `0x1FF1FFFF`.
- DTCM RAM: `0x20000000` to `0x2002FFFF`.
- AXI SRAM starts at `0x24000000`.
- SRAM1/SRAM2 are in the `0x30000000` region.
- XSPI1 window: `0x90000000` to `0x9FFFFFFF`.
- XSPI2 window: `0x70000000` to `0x7FFFFFFF`.

The **address window does not prove that an external memory is fitted, initialized, or memory-mapped on your board**. The board schematic and firmware configuration must determine the actual external NOR connection.

## External NOR policy

External NOR is intentionally not treated as a generic internal-flash equivalent.

There are three different operations:

1. **Read a memory-mapped NOR** — requires the MCU's XSPI controller and pins to already be configured.
2. **Program/erase NOR** — requires a valid J-Link flash loader or a target-side programming mechanism for the exact flash/controller/board.
3. **Probe/identify NOR** — may require executing controller-specific commands or firmware; a CPU memory read alone is not sufficient.

`external_flash_program` and `external_flash_erase` are disabled unless explicitly enabled in configuration. Do not enable them merely because the CPU window is `0x70000000` or `0x90000000`.

SEGGER documents an important distinction: `VerifyBin` performs a memory read/compare and does **not** initialize an external QSPI/XSPI interface; `LoadFile` can use a flash download/loader mechanism. Therefore this project does not claim that `verifybin` can independently access an uninitialized external NOR.

## Hardware-profile sources

The checked-in STM32H7S3I8T6/XSPI1 values are based on the ST STM32H7S3I8 product/datasheet and RM0477 memory map, SEGGER's supported-device database, ST's NUCLEO-H7S3L8 documentation identifying the 256-Mbit NOR family, and Macronix documentation for the 512-Mbit density equivalent. The exact custom-board BOM and schematic remain the authoritative source for the assembled hardware.

## Requirements

- Python 3.10+
- SEGGER J-Link Software and Documentation Pack
- J-Link probe
- ARM GDB (`arm-none-eabi-gdb` or `gdb-multiarch`)
- Optional firmware ELF with debug information
- Optional CMSIS-SVD file for peripheral/register semantics

SEGGER supports J-Link Commander and J-Link GDB Server on Linux and macOS.

## Install

```bash
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
pip install -e ".[dev]"
cp config.example.yaml config.yaml
```

Edit `config.yaml`, then:

```bash
stm32-jlink-mcp
```

Configuration path can be overridden with:

```bash
export STM32_JLINK_MCP_CONFIG=/absolute/path/config.yaml
```

## Direct hardware smoke test

Before involving MCP, validate J-Link itself:

```text
JLinkExe
Device STM32H7S3I8
SI SWD
Speed 4000
Connect
Halt
Regs
Mem8 0x08000000, 0x40
```

SEGGER recommends specifying the target device explicitly because device-specific handling may be required during connect/reset.

## MCP tool groups

### Probe / target

- `probe_list`
- `jlink_connect`
- `jlink_disconnect`
- `jlink_status`
- `target_identify`
- `target_status`
- `target_reset`
- `target_halt`
- `target_run`
- `target_step`

### Memory / registers

- `memory_read`
- `memory_write`
- `registers_read`
- `register_read`
- `register_write`

### Internal flash

- `flash_program`
- `flash_verify`
- `flash_erase`

### GDB / source debugging

- `debug_start`
- `debug_stop`
- `debug_continue`
- `debug_pause`
- `debug_step`
- `debug_breakpoint_set`
- `debug_breakpoint_clear`
- `debug_watchpoint_set`
- `debug_watchpoint_clear`
- `debug_stop_reason`
- `debug_backtrace`
- `read_variable`

### ELF / SVD

- `load_symbols`
- `resolve_address`
- `resolve_symbol`
- `svd_info`
- `peripheral_info`
- `register_info`
- `register_read`

### STM32 diagnostics

- `stm32_fault_info`
- `stm32_snapshot`
- `stm32_reset_reason`
- `boot_diagnose`

### XSPI / external memory

- `external_flash_info`
- `external_flash_read`
- `external_flash_test`
- `external_flash_program`
- `external_flash_erase`

### Workflows / expert escape hatches

- `flash_and_verify`
- `diagnose_crash`
- `jlink_command` (disabled by default)

## Safety model

Configuration supports:

```yaml
safety:
  mode: read_only
```

In read-only mode, target inspection and diagnostics remain available while writes/program/erase are denied.

Destructive or target-modifying operations can require exact confirmation tokens. The MCP server does not interpret a natural-language phrase such as "yes" as authorization.

## Testing

Fast tests do not require J-Link hardware:

```bash
pytest
ruff check .
```

Hardware tests are marked separately:

```bash
pytest -m hardware
```

They are intentionally not part of normal CI unless a self-hosted runner with the required hardware is configured.

## Project status

This is an engineering-focused v0.2 foundation. The core architecture is intended to be production-oriented, but board-specific external NOR programming still requires validation against the actual schematic, NOR part number, XSPI instance/configuration, and programming method.

Do not use this repository as a substitute for SEGGER documentation, the STM32 reference manual/datasheet, or your board's schematic.

## RTT and deployment sequence

J-Link RTT is supported as a first-class diagnostic transport. The preferred board workflow is:

```text
erase -> program -> verify -> RTT connect -> NRST pulse -> capture boot logs
```

Available MCP tools:

- `rtt_connect`
- `rtt_read`
- `rtt_write`
- `rtt_disconnect`
- `nrst_assert`
- `nrst_release`
- `nrst_pulse`
- `program_verify_rtt_nrst`

RTT uses SEGGER's local RTT TELNET transport and channel 0. When no GDB session is already active, the MCP starts a persistent J-Link GDB Server solely to maintain the J-Link connection required by RTT. If GDB is already active, RTT attaches to its configured RTT TELNET port.

See `docs/RTT_AND_PROGRAMMING_SEQUENCE.md` for ownership, reset, and RTT control-block guidance.

## Option bytes

STM32H7S3 option-byte inspection is exposed separately from ordinary memory/register access.

Planned/guarded operations:

- `option_bytes_read`
- `option_bytes_write`
- `option_bytes_mass_erase`

Option-byte writes and mass erase are disabled by default in configuration because
they are persistent device configuration changes. The implementation must use the
STM32H7S3-specific FLASH option-byte sequence; it must not guess a generic
`J-Link Commander` command or treat option bytes as ordinary RAM/register writes.

See `docs/OPTION_BYTES.md`.