Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

CMSIS-DAP MCP

面向 CMSIS-DAP 调试探针与 Cortex-M 芯片的开源调试工具套件,提供 MCP 服务器(供 AI 助手驱动)和独立命令行工具,两者共用同一引擎,通过 SWDJTAG 工作。

新用户? 请从从零开始入手,一步步完成环境搭建 和首次连接。

两个工具

  • cmsis-dap-mcp —— MCP(模型上下文协议)服务器,让 AI 助手(Codex、 Claude Code、opencode 等)直接操控探针和目标芯片。
  • cmsis-dap-cli —— 面向人、脚本与自动化的独立命令行工具,无需 AI 客户端。

核心功能

探针与会话

工具功能
list_probes枚举所有已连接的 CMSIS-DAP 探针
get_probe_info查看探针详细信息(型号、序列号、支持的协议和速度)
connect通过 SWD 或 JTAG 连接目标芯片,支持按住复位连接
disconnect断开当前会话
get_target_info查看目标信息(内核类型、CPUID、内存映射)

内存访问

工具功能
read_memory读取内存,支持 u8/u16/u32/u64,可导出为 bin/hex 文件
write_memory写入内存
verify_memory读回并与期望值比较,报告不匹配项

内核控制

工具功能
read_core_register / write_core_register读写内核寄存器(pc、sp、lr、r0-r15 等)
list_core_registers列出目标支持的全部寄存器
get_core_status查看内核状态(运行/停机/睡眠/锁定)
halt / resume / step暂停 / 恢复 / 单步执行
reset复位目标,支持复位后继续或复位后暂停

断点与数据观察点

工具功能
set_breakpoint / clear_breakpoints / list_breakpoints硬件断点管理
set_watchpoint / clear_watchpoints / list_watchpointsDWT 数据观察点(读/写/读写触发)

DAP 原始访问

工具功能
read_dap / write_dap直接读写 DP/AP 寄存器(高级调试)

SVD 命名外设

工具功能
load_svd运行时加载任意 CMSIS-SVD 文件
list_peripherals列出所有已加载的外设
read_peripheral / write_peripheral按名称读写外设寄存器和位域(读-改-写)

Flash 烧录

工具功能
erase_flash按扇区擦除 Flash(只擦与请求范围重叠的扇区)
program_flash烧录固件,支持 elf/axf/bin/hex 格式,可选读回校验

芯片定义

工具功能
define_chip(MCP)从 Keil FLM 文件运行时注册未知芯片,无需外部工具
chip generate(CLI)从 FLM 生成 probe-rs target YAML 文件
chip list / chip search列出或搜索内置芯片库

脚本引擎

工具功能
run_script(MCP)/ script(CLI)运行 J-Link Commander / OpenOCD 风格调试脚本

非侵入调试

工具功能
dump_cpu_state(MCP)/ dump(CLI)不复位目标,采集 CPU 快照(寄存器、fault 状态、栈、内存)

远程访问

功能说明
TCP JSON-RPC 服务器--tcp PORT(MCP)或 tcp-server(CLI),按行分隔的远程协议
GDB 服务器--gdb-port PORT(MCP)或 gdb-server(CLI),GDB Remote Serial Protocol stub

运行时配置

工具功能
get_config查看当前运行时配置
update_config运行时更新配置(破坏性开关、TCP/GDB 端口),无需重启
reload_config重新加载启动时指定的配置文件

安全

三级安全策略:只读工具始终可用;写工具由 MCP 客户端审批;破坏性工具 (Flash 擦除/烧录)默认禁用,需显式启用。

CLI 实时调试(独有)

功能说明
watch按刷新间隔轮询变量(地址或 ELF 符号),带时间戳日志导出
rtt monitor读取 SEGGER RTT 上行通道日志,无需串口
evr monitor解码 CMSIS-View Event Recorder 事件,无需 trace 硬件
repl交互式 shell,保持会话持续操作

亮点特性

  • 通用 Cortex-M 支持:标准内核无需芯片适配即可调试
  • 运行时芯片定义:从 FLM 文件注册未知芯片,无需预构建 YAML
  • 零参数启动:服务器可空启动,运行时通过工具完全配置
  • 终端用户零依赖npx -y cmsis-dap-mcp 或单个原生二进制
  • 跨平台:Windows / Linux / macOS

文档导航

英文文档:https://guohj2021.github.io/CMSIS-DAP-MCP/

从零开始

本指南面向零基础用户,手把手带你从安装软件到连接硬件、读写内存, 逐步掌握 CMSIS-DAP MCP 工具的全部能力。每一步都附有具体命令和预期输出。

你将获得什么

CMSIS-DAP MCP 提供两个共用同一引擎的工具:

  • cmsis-dap-mcp —— MCP(模型上下文协议)服务器,让 AI 助手(Codex、 Claude Code 等)直接操控你的调试探针和目标芯片。
  • cmsis-dap-cli —— 独立命令行工具,无需 AI 客户端,直接在终端中 调试、烧录和监控目标。

两者都支持:

  • 枚举调试探针、通过 SWD 或 JTAG 连接 Cortex-M 芯片
  • 读写内存与内核寄存器、暂停/恢复/单步执行
  • 运行时加载 SVD 文件,按名称访问外设寄存器
  • 从固件文件(elf/axf/bin/hex)烧录 Flash
  • 运行 J-Link / OpenOCD 风格调试脚本
  • 非侵入式 CPU 快照(不复位目标)
  • TCP 远程服务器与 GDB 调试服务器

CLI 额外提供实时调试:watch(变量轮询)、rtt monitor(SEGGER RTT 日志)、 evr monitor(CMSIS-View Event Recorder)—— 全部走 SWD/JTAG,无需串口。


需要什么硬件

必需

  1. CMSIS-DAP 调试探针

    • 支持 CMSIS-DAP v1(HID)或 v2(WinUSB)协议
    • 大多数市售 CMSIS-DAP 兼容探针均可使用
    • 通过 USB 连接电脑
  2. Cortex-M 开发板

    • 任何带 SWD 调试端口的 ARM Cortex-M 开发板
    • 支持 M0、M0+、M3、M4、M7 全系列内核
    • 探针和开发板之间通过 SWD 线连接
  3. SWD 连接线

    • 至少 3 根线:SWDIOSWCLKGND
    • 将探针的 SWD 引脚连接到开发板对应的调试端口

可选

  1. nRST 复位线
    • 用于 under_reset 模式连接(锁定或无响应的目标)
    • 连接探针的 nRST 引脚到开发板的复位引脚

接线示意

探针 (CMSIS-DAP)          开发板 (Cortex-M)
┌─────────────┐           ┌─────────────┐
│  SWDIO  ──────┼───────────┤  SWDIO      │
│  SWCLK  ──────┼───────────┤  SWCLK      │
│  GND    ──────┼───────────┤  GND        │
│  nRST   ──────┼── (可选) ─┤  NRST       │
└──────┬──────┘           └─────────────┘
       │ USB
    ┌──┴──┐
    │ PC  │
    └─────┘

提示:不同的探针和开发板引脚定义不同,请参照你硬件的引脚图确认 SWDIO/SWCLK/GND 的对应位置。


需要什么文件

工具按功能层级递进,不同功能需要不同的文件:

功能需要的文件来源
基础调试(内存、寄存器、执行控制)无,开箱即用
命名外设访问SVD 文件芯片厂商 SDK 或 CMSIS-Pack
Flash 烧录Keil FLM 闪存算法文件IDE 安装目录或芯片厂商
符号级调试(watch/RTT/EVR)固件 ELF 或 AXF 文件你的编译输出

FLM 文件通常位于 Keil MDK 的 Flash/ 目录下,文件名形如 TargetChip_64.FLM

SVD 文件描述芯片外设寄存器布局,通常随芯片 SDK 或 CMSIS-Pack 提供, 文件名形如 TargetChip.svd

注意:本仓库不捆绑任何芯片专有数据。所有文件由用户在运行时提供。


环境安装

方式一:使用 npm(推荐)

npm 是 Node.js 的包管理器,本项目的两个工具都已发布为 npm 包。

Windows

# 用 winget 安装 Node.js(包含 npm)
winget install OpenJS.NodeJS.LTS

# 或用 scoop
scoop install nodejs-lts

安装完成后打开新的终端窗口,验证:

node --version    # 应显示 v18.x 或更高
npm --version     # 应显示 9.x 或更高

Linux(Debian/Ubuntu)

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash -
sudo apt install -y nodejs

Linux(Fedora/RHEL)

sudo dnf install -y nodejs npm

macOS

brew install node

方式二:使用原生二进制(离线场景)

如果无法安装 Node.js,可以从 GitHub Releases 下载对应平台的原生二进制, 无需任何运行时依赖。

方式三:从源码构建(开发者)

需要安装 Rust 工具链:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --release --workspace

安装工具

MCP 服务器(给 AI 助手用)

# 验证可以运行(零安装,首次运行会自动下载)
npx -y cmsis-dap-mcp --help

命令行工具(给人用)

# 零安装快速试用
npx -y cmsis-dap-cli --help

# 或全局安装后直接使用命令
npm install -g cmsis-dap-cli
cmsis-dap-cli --help

如果你从 GitHub Releases 下载了原生二进制,把它放在 PATH 中或直接用 完整路径调用。


驱动安装

Windows

  • CMSIS-DAP v1(HID):通常免驱,插入即可识别。
  • CMSIS-DAP v2(WinUSB):需要安装 WinUSB 驱动。
    1. https://zadig.akeo.ie/ 下载 Zadig
    2. 插入探针,打开 Zadig
    3. 在菜单中选择 Options → List All Devices
    4. 选择你的 CMSIS-DAP 设备
    5. 将驱动替换为 WinUSB,点击 Replace Driver

Linux

需要添加 udev 规则以允许非 root 用户访问 USB 设备:

# 创建规则文件(将 xxxx/yyyy 替换为你的探针 VID/PID)
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="yyyy", MODE="0666"' \
  | sudo tee /etc/udev/rules.d/99-cmsis-dap.rules

# 重新加载规则
sudo udevadm control --reload-rules
sudo udevadm trigger

# 重新插拔探针

提示:在 Windows 上查看设备管理器中探针的 VID/PID,或在 Linux 上 用 lsusb 查看。

macOS

通常开箱即用。如果探针无法识别,检查系统设置 > 隐私与安全性中是否有 USB 设备权限提示。


第一步:连接你的硬件

1. 确认识别

插入 CMSIS-DAP 探针,打开终端:

cmsis-dap-cli list

预期输出(探针 id 和产品名会因硬件不同而不同):

CMSIS-DAP probes found:
  id        : 0123456789AB
  product   : CMSIS-DAP
  serial    : (none)
  protocols : SWD, JTAG

如果列表为空,请检查驱动安装和 USB 连接。

2. 连接目标芯片

cmsis-dap-cli connect

这会自动探测目标芯片。如果你知道芯片型号,可以指定以获得更详细的 内存映射信息:

cmsis-dap-cli --target STM32F030C8 connect

预期输出:

target: {"ap_count":1, "core_count":1, "core_type":"Armv6m", ...,
         "memory_regions":[FLASH 0x08000000-0x08010000, SRAM 0x20000000-0x20002000]}

3. 读内存验证连接

cmsis-dap-cli read --address 0x20000000 --width u32 --count 4

预期输出(值取决于目标芯片当前的内存内容):

address: 0x20000000, width: u32, count: 4
  0x20000000: 0x00000040
  0x20000004: 0x00000001
  0x20000008: 0x00000003
  0x2000000C: 0x00000000

4. 暂停、读寄存器、恢复

cmsis-dap-cli halt
cmsis-dap-cli reg get pc
cmsis-dap-cli resume

预期输出:

halted: true
pc = 0x0800122A
running: true

恭喜! 你已经成功连接到目标芯片并完成了基本的内存和寄存器操作。

提示:也可以用 repl 进入交互模式,保持一个会话持续操作:

cmsis-dap-cli repl
# 在提示符下依次输入 connect → halt → reg pc → resume

进阶:MCP 服务器配置

如果你使用 AI 助手(如 Codex、Claude Code 或 opencode),可以让它直接 操控探针。只需添加 MCP 服务器配置:

Codex

codex mcp add cmsis-dap -- npx -y cmsis-dap-mcp

Claude Code

claude mcp add --scope local cmsis-dap -- npx -y cmsis-dap-mcp

opencode

opencode mcp add cmsis-dap -- npx -y cmsis-dap-mcp

添加后重启客户端。你可以在 AI 对话中直接说:

列出已连接的调试探针,然后连接到目标芯片。

AI 会自动调用 list_probesconnect 等工具完成操作。


进阶:Flash 烧录

准备工作

  1. 确认你的芯片有对应的 FLM 闪存算法文件
  2. 知道芯片的 Flash 和 SRAM 地址范围(查看芯片数据手册)

CLI 方式

# 第一步:从 FLM 生成 target YAML(只需做一次)
cmsis-dap-cli chip generate \
  --flm /path/to/TargetChip.FLM \
  --flash-start 0x08000000 --flash-size 0x10000 \
  --sram-start 0x20000000 --sram-size 0x2000 \
  --name TargetChip --output TargetChip.yaml

# 第二步:使用生成的 YAML 连接并烧录
cmsis-dap-cli --target-yaml TargetChip.yaml connect
cmsis-dap-cli flash erase --address 0x08000000 --size 0x10000
cmsis-dap-cli flash program --address 0x08000000 --file firmware.hex --verify

MCP 方式

define_chip {
  "flm": "/path/to/TargetChip.FLM",
  "flash_start": 0x08000000, "flash_size": 0x10000,
  "sram_start": 0x20000000, "sram_size": 0x2000,
  "core": "armv6m", "name": "TargetChip"
}
connect { "target": "TargetChip", "protocol": "swd" }
program_flash { "address": 0x08000000, "path": "firmware.hex", "format": "hex", "verify": true }

开启破坏性模式

Flash 擦除和烧录是破坏性操作,默认禁用。有两种开启方式:

  • 启动时:加 --allow-destructive 参数
  • 运行时:调用 update_config {"allow_destructive": true}(无需重启)

进阶:命名外设(SVD)

SVD 文件描述芯片的外设寄存器布局,让你用名称而非地址操作外设。

# CLI 方式
cmsis-dap-cli --svd TargetChip.svd svd list
cmsis-dap-cli --svd TargetChip.svd svd read GPIOA.ODR.ODR0
cmsis-dap-cli --svd TargetChip.svd svd write GPIOA.ODR.ODR0 1
# MCP 方式
load_svd { "path": "/path/to/TargetChip.svd" }
list_peripherals {}
read_peripheral { "peripheral": "GPIOA", "register": "ODR", "field": "ODR0" }
write_peripheral { "peripheral": "GPIOA", "register": "ODR", "field": "ODR0", "value": 1 }

进阶:实时调试

CLI 独有三项实时调试能力,全部走 SWD/JTAG——无需串口:

变量轮询(watch)

cmsis-dap-cli --elf firmware.axf watch counter --interval-ms 200 --count 0

RTT 日志

cmsis-dap-cli --elf firmware.axf rtt monitor --channel 0 --count 0

Event Recorder

cmsis-dap-cli --elf firmware.axf evr monitor --count 0

注意:实时调试需要固件 ELF 文件(--elf),且目标固件需要已初始化 对应的组件(SEGGER RTT 或 CMSIS-View Event Recorder)。


下一步

快速开始

npm(推荐)

无需安装:让 MCP 客户端用 npx 启动服务器即可:

codex mcp add cmsis-dap -- npx -y cmsis-dap-mcp

cmsis-dap-mcp npm 包会在首次启动时自动下载对应平台的二进制并缓存。

固定版本:

codex mcp add cmsis-dap -- npx -y cmsis-dap-mcp@0.5.0

原生二进制

从 GitHub Releases 下载对应平台二进制,然后让客户端指向它:

codex mcp add cmsis-dap -- /path/to/cmsis-dap-mcp --log-level warn

这是运行未发布或本地构建服务器的标准方式,也适合需要离线、精确固定版本的 场景。

配置方式

MCP 客户端有三种等价的 stdio 配置写法。npx 是已发布包的标准写法;本地 二进制写法与之等价,用于本地构建。

方式示例适用场景
npxcommand = "npx", args = ["-y", "cmsis-dap-mcp"]已发布版本;随 npm 更新
本地二进制command = "/path/to/cmsis-dap-mcp"本地构建、离线、精确版本
远程 URLurl = "https://..."Streamable-HTTP 服务器(本项目暂不支持)

AI 客户端配置 页中三个客户端都同时接受 npx 与本地二进制 路径两种写法,服务器行为完全一致。

第一次会话

服务器可零参数启动——进入待配置态:所有读/写工具可用,破坏性工具保持 门控,直到按第 7 步启用。

  1. list_probes 查找探针 id。
  2. connect,参数 {"protocol": "swd", "speed_khz": 1000}
  3. read_memory / write_memory 原始内存访问。
  4. halt,然后 read_core_register(例如 pcsplrr0)。
  5. 完成后 resume
  6. load_svd 加载你自己的 SVD 文件,进行命名外设访问。
  7. program_flash / erase_flash 需要破坏性模式:启动时加 --allow-destructive运行时调用 update_config {"allow_destructive": true}(无需重启)。
  8. 对 probe-rs 未内置的芯片,先调用 define_chip 传入 Keil FLM 文件 再 connect(见工具参考)。

示例(CMSIS-DAP 探针 + Cortex-M0+ 开发板实测输出):

list_probes -> {"probes": [{"id": "0123456789AB", "product": "CMSIS-DAP", ...}]}
connect {protocol: swd, speed_khz: 1000}
  -> {"target": {"core_type": "Armv6m", "core_count": 1, "ap_count": 1, "cpu_id": ..., "dp_id": ...}}
read_memory {address: 0x20000000, width: u32, count: 4}
  -> {"values": [64000000, 1, 3, 0]}
halt -> {"halted": true}
read_core_register {name: pc} -> {"value": 134228884}
resume -> {"running": true}

日志只写入 stderr;MCP 协议运行在 stdout 上。

CLI 快速上手

独立命令行工具 cmsis-dap-cli 与服务器共用同一引擎,会自动使用全局连接 参数(--probe-id--target--target-yaml 等):

cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 connect
cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 read --address 0x20000000 --width u32 --count 4
cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 --elf fw.axf watch counter --interval-ms 200 --count 0
cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 --elf fw.axf rtt monitor --count 0
cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 --elf fw.axf evr monitor --count 0

repl 保持单一会话(halt/读/恢复跨行执行,或在 reset run 后运行 watch/RTT/Event Recorder 监控)。完整命令参考见命令行工具

AI 客户端配置

服务器通过 stdio 使用 MCP 协议。标准配置方式是 npx 形式(运行已发布的 npm 包);要运行本地构建的二进制,把 npx -y cmsis-dap-mcp 换成二进制路径即可, 服务器行为完全一致。

配置方式

把 MCP 客户端指向服务器有三种写法:

方式示例适用场景
npx 包(标准)command = "npx", args = ["-y", "cmsis-dap-mcp"]已发布版本;首次启动下载并缓存
本地二进制command = "/path/to/cmsis-dap-mcp"未发布或本地构建、离线、精确版本
远程 URLurl = "https://..."Streamable-HTTP MCP 服务器(本项目暂不支持)

npx 固定版本:npx -y cmsis-dap-mcp@0.5.0。开发本仓库时,把客户端 指向 target/release/cmsis-dap-mcp,即可使用刚构建的二进制而无需发布。

服务器命令行参数

所有参数均可选——服务器零参数启动即可,进入待配置态。下表中除日志外的 一切都可以在运行时通过 update_config / reload_config / get_config MCP 工具变更,无需重启。

参数说明
--allow-destructive启动即开启 erase_flash / program_flash 及破坏性脚本命令
--tcp PORT同时在 127.0.0.1:PORT 提供远程 JSON-RPC TCP 服务
--gdb-port PORT同时在 127.0.0.1:PORT 启动 GDB 服务器
--config-file FILEJSON 配置文件(键:allow_destructivetcp_portgdb_port);启动时加载,可监听变更
--probe-id IDconnect 的默认探针 id
--protocol swd|jtag默认调试协议(默认 swd
--speed-khz N默认 SWD/JTAG 时钟速度
--target NAME默认目标芯片名
--svd FILE启动时加载的 SVD 文件
--target-yaml FILE预加载到芯片注册表的 target YAML
--log-level LEVELtracing 过滤器;日志写 stderr(默认 info
--log-file FILE日志写入文件而非 stderr

仅启动时固定(运行时不可变更):--log-level--log-file--config-file 路径本身(其内容可重载)、backend 注册表种子 (--target-yamldefine_chip 在运行时往里追加)。GDB 服务器端口一旦 启动即不可变更。

优先级:CLI 参数 > 配置文件 > 默认值;运行时 update_config 覆盖两者。

Codex

codex mcp add cmsis-dap -- npx -y cmsis-dap-mcp

或写入 ~/.codex/config.toml

[mcp_servers.cmsis-dap]
command = "npx"
args = ["-y", "cmsis-dap-mcp"]

本地构建时用 command = "/path/to/cmsis-dap-mcp"。用 codex mcp list 确认;Codex 桌面端在新会话启动时加载该服务器。

Claude Code

claude mcp add --scope local cmsis-dap -- npx -y cmsis-dap-mcp

本地构建时把 npx -y cmsis-dap-mcp 换成二进制路径。用 claude mcp list 确认(显示 √ Connected)。

opencode

opencode mcp add cmsis-dap -- npx -y cmsis-dap-mcp

或写入 ~/.config/opencode/opencode.jsonc

"cmsis-dap": {
  "type": "local",
  "command": ["npx", "-y", "cmsis-dap-mcp"],
  "enabled": true
}

本地构建时把 command 数组换成 ["/path/to/cmsis-dap-mcp", "--log-level", "warn"]。用 opencode mcp list 确认。

其他 MCP 客户端

{
  "mcpServers": {
    "cmsis-dap": {
      "command": "npx",
      "args": ["-y", "cmsis-dap-mcp"]
    }
  }
}

端到端示例(已实测)

以下任务已由 Claude Code 和 opencode 在真实 CMSIS-DAP 探针上成功执行:

1. list_probes
2. connect {protocol: swd, speed_khz: 1000}
3. read_memory {address: 0x20000000, width: u32, count: 4}
4. halt
5. read_core_register {name: pc}
6. resume

实测结果:

探针 id : 0123456789AB(CMSIS-DAP,vendor 0x0416)
内存    : [64000000, 1, 3, 0]
pc      : 134228884(0x08002B94)

说明:

  • 模型传参时请使用十进制整数或字符串;部分客户端会拒绝 JSON 参数里的十六进制 字面量(如 0x20000000)。十进制 536870912 等价。
  • connecthaltresume 等写工具可能受客户端审批策略约束。
  • 添加服务器后如果工具不出现,请重启客户端。

工具参考

安全等级:(始终可用)、(由客户端审批)、破坏性(需 启动时 --allow-destructive 运行时 update_configallow_destructive: true)。

探针与会话

工具参数等级
list_probes-
get_probe_infoprobe_id(可选)
connectprobe_idprotocolswd/jtag,默认 swd)、speed_khztargetunder_reset
disconnect-
get_target_info-

list_probes 返回探针 id、厂商/产品、序列号、产品 id、接口、HID 标记、 支持的协议、速度与目标电压(探针支持时)。

get_target_info 返回内核类型与数量、真实 AP 数量、CPUID、DPIDR 与内存映射 摘要(RAM/NVM 区域)。

内存

工具参数等级
read_memoryaddresswidthu8/u16/u32/u64)、count(默认 1)、pathformat
write_memoryaddresswidthvalues
verify_memoryaddresswidthdata

verify_memory 读回指定范围并与 data 比较,返回 verifiedmismatches 列表。

read_memory 还可以把范围导出到文件:传 pathformat(默认 binhex),此时 count 表示字节数。示例:

read_memory { "address": 0x08000000, "width": "u8", "count": 0x1000, "path": "firmware.bin", "format": "bin" }

内核

工具参数等级
read_core_registername number
write_core_registername numbervalue
list_core_registers-
get_core_status-
halt-
resume-
step-
resetmode(默认 run / halt

寄存器名大小写不敏感。支持特殊角色(pcspfplr/rapsr/xpsrmsppspfpsr)与通用寄存器(r0-r15);其他名称会在 架构寄存器表中查找。list_core_registers 返回全部可用名称。

get_core_status 返回 staterunning/halted/sleeping/locked_up/ unknown)、暂停时的 halt_reason 与程序计数器。

非侵入调试

工具参数等级
dump_cpu_stateaddress(可重复,0xADDR 或 ELF 符号)、stack_words(可选)、no_restore(可选)

dump_cpu_state永不复位目标的前提下采集 CPU 快照:内核寄存器(在短暂停机时读取)、Cortex-M fault 状态寄存器(CFSR/HFSR/DFSR/MMFAR/BFAR,不停机读取)、MSP/PSP 栈顶字与按给定地址的可选内存采样。默认读取后恢复原运行状态;传入 no_restore: true 则保持核心停机。地址接受 0xADDR 或 ELF 符号名(当服务器以 --elf 文件启动时)。

断点与数据观察点

工具参数等级
set_breakpointaddress
clear_breakpoints-
list_breakpoints-
set_watchpointaddressaccessread/write/rw
clear_watchpoints-
list_watchpoints-

数据观察点使用内核的 DWT 比较器,只对内核的读写访问触发,不会因调试器写入 触发。目标没有 DWT 比较器时返回 UnsupportedFeature

DAP

工具参数等级
read_dapaddress
write_dapaddressvalue

DAP 地址在 bit 24-31 放 APSEL 表示 AP 访问(例如 0x010000FC);否则 bit 0-7 是 DP 寄存器地址(bit 4-7 选择 DP bank)。

SVD

工具参数等级
load_svdpath
list_peripherals-
read_peripheralperipheralregisterfield(可选)
write_peripheralperipheralregisterfield(可选)、value

位域写入为读-改-写。

Flash

工具参数等级
erase_flashaddresssize破坏性
program_flashaddressdata pathformat(可选)、verify(可选)破坏性

erase_flash 只擦除与 [address, address+size) 重叠的扇区;传入完整 Flash 范围即整片擦除。program_flashverify: true 时烧写后读回校验。除了原始 data,还可以用 path 传入固件文件:

program_flash { "address": 0x08004000, "path": "/path/to/fw.hex", "format": "hex", "verify": true }

支持的格式:elfaxf(与 ELF 同容器)、bin(必须给 address)、 hex/ihex/intelhex,或 auto(默认,按扩展名 .elf/.axf/.bin/.hex/.ihx 推断)。

芯片定义

工具参数等级
define_chipflmflash_startflash_sizesram_startsram_sizecore(可选,默认 armv6m)、name(可选,默认 FLM 文件名)

define_chip 在运行时从 Keil FLM 闪存算法文件注册自定义/未知芯片—— 无需独立 probe-rs CLI 或预构建 target YAML。FLM 被解析以提取闪存算法 (代码、入口点、页大小、扇区布局、擦除值、超时),生成 probe-rs target YAML 并注册到运行中服务器的 backend registry。注册后,调用 connect 并将 target 设为芯片名(仅定义一个变体时可省略)即可连接。

参数:

  • flm — Keil FLM 文件路径(ARM ELF,含厂商闪存算法与 FlashDevice 描述符)。
  • flash_start / flash_size — Flash 内存地址范围(如 0x08000000 / 0x10000 表示 64 KB)。FLM 描述符自身的值不可靠,必须显式提供。
  • sram_start / sram_size — SRAM 地址范围(如 0x20000000 / 0x2000 表示 8 KB)。FLM 不包含此信息。
  • core — ARM 架构 profile:armv6m(Cortex-M0/M0+,默认)、armv7m (Cortex-M3)、armv7em(Cortex-M4/M7)。
  • name — 用于 connect 的芯片/变体名。默认取 FLM 文件名(去掉扩展名)。

示例:

define_chip {
  "flm": "C:/SDK/Libraries/Flash/MyChip_64.FLM",
  "flash_start": 0x08000000, "flash_size": 0x10000,
  "sram_start": 0x20000000, "sram_size": 0x2000,
  "core": "armv6m", "name": "MyChip"
}
connect { "target": "MyChip", "protocol": "swd" }
load_svd { "path": "C:/SDK/SVD/MyChip.svd" }
erase_flash { "address": 0x0800FC00, "size": 0x400 }
program_flash { "address": 0x0800FC00, "data": [0xDE, 0xAD, 0xBE, 0xEF], "verify": true }

运行时配置

工具参数等级
get_config-
update_configallow_destructive(可选)、tcp_port(可选)、gdb_port(可选)
reload_config-

这些工具管理服务器的运行时配置。服务器可以零参数启动(待配置态),然后 完全在运行时配置——无需重启。

get_config 返回当前配置的 JSON:allow_destructivetcp_portgdb_portconfig_file

update_config 执行部分更新:省略任意字段即保持当前值。候选配置在写入前 先校验,无效值将整体拒绝(原子性,不部分生效)。更新成功后,服务器自动 收敛运行中的 TCP/GDB 任务以匹配新配置(幂等)。

  • allow_destructivetrue 开启 erase_flash / program_flash 及 破坏性脚本命令;false 关闭。
  • tcp_port — 设为端口号(1–65535)启动或迁移 127.0.0.1 上的远程 JSON-RPC TCP 服务器;设为 null 停止。
  • gdb_port — 设为端口号启动 GDB 服务器。已运行的 GDB 服务器无法 运行时迁移端口;需重启服务器才能改端口。

reload_config 重新读取启动时通过 --config-file 指定的配置文件并应用。 未提供文件、文件缺失或内容无效时返回明确错误。

示例:

get_config
  -> {"allow_destructive": false, "tcp_port": null, "gdb_port": null, "config_file": null}

update_config { "allow_destructive": true, "tcp_port": 4000 }
  -> {"allow_destructive": true, "tcp_port": 4000, "gdb_port": null, "config_file": null}

脚本

工具参数等级
run_scriptpath script

run_script 用 J-Link Commander / OpenOCD 风格命令子集执行线性调试脚本。 完整命令参考与示例见 脚本使用

错误码

错误返回结构化 JSON,含 codemessageProbeNotFoundConnectFailedNotConnectedProtocolErrorTimeoutMemoryFaultSvdNotLoadedFileErrorUnsupportedFeatureDestructiveDisabledInvalidArgumentInternalError

命令行工具

简介

cmsis-dap-cli 是面向人、脚本与自动化的独立命令行工具。它与 MCP 服务器共用 同一套 cmsis-dap-core 引擎(探针枚举、内存、内核控制、SVD、Flash 与脚本), 但直接面向终端用户,不经过 MCP。

仓库是包含三个 crate 的 Cargo workspace:

  • cmsis-dap-core —— 共享引擎(后端、会话、SVD、脚本引擎);
  • cmsis-dap-mcp —— MCP 服务器二进制;
  • cmsis-dap-cli —— 本 CLI,只依赖 cmsis-dap-core

安装

npm 包已发布;可用 npx 零安装直接运行,或全局安装后直接使用 cmsis-dap-cli 命令:

# 零安装(推荐快速试用与脚本调用)
npx -y cmsis-dap-cli --help

# 或全局安装
npm install -g cmsis-dap-cli
cmsis-dap-cli --help

离线环境下,从 GitHub Releases 下载 Windows / Linux / macOS 原生二进制,或本地构建:

cargo build --release --workspace
./target/release/cmsis-dap-cli --help        # Windows 为 target\release\cmsis-dap-cli.exe

想直接敲 cmsis-dap-cli,把所在目录加入 PATH 即可。

快速上手

cmsis-dap-cli list                                   # 枚举探针
cmsis-dap-cli --probe-id 0123456789AB connect        # 连接(自动选择芯片)
cmsis-dap-cli read --address 0x20000000 --width u32 --count 4
cmsis-dap-cli halt
cmsis-dap-cli reg get pc
cmsis-dap-cli resume

需要目标的命令会自动使用全局连接参数连接,典型的一次性会话:

$ cmsis-dap-cli --target STM32F030C8 connect
target: {"ap_count":1,"core_count":1,"core_type":"Armv6m",...,
         "memory_regions":[FLASH 0x08000000-0x08010000, SRAM 0x20000000-0x20002000]}

全局参数

所有参数都是全局的,可以放在子命令前后。

参数含义
--probe-id ID多探针时按 id/序列号选择
--protocol swd|jtag调试协议(默认 swd
--speed-khz NSWD/JTAG 时钟(kHz)
--target NAME目标芯片名(内置库或 --target-yaml 中的变体)
--under-reset按住复位连接(锁定/无响应目标)
--target-yaml FILE加载 target YAML(芯片 + Flash 算法定义)
--svd FILESVD 文件(svd 子命令用)
--elf FILE固件 ELF(symbols/watch/rtt/evr 符号解析用)
--json输出机器可读 JSON 而非人类文本
--log-level LEVEL日志过滤级别;日志只写 stderr(默认 warn
--log-file FILE日志写入文件而非 stderr

数字(地址、大小、数值)支持十进制与十六进制(0x...)。

命令参考

探针与会话

命令用途
list枚举已连接探针
info查看探针信息(id、厂商、产品、序列号、能力)
connect连接目标并显示目标信息
disconnect断开会话
target显示目标信息(自动连接)

内存

命令用途
read --address A --width W --count N [--output FILE --format bin|hex]读内存;带 --output 时导出范围到文件(此时 count 为字节数)
write --address A --width W --values V1,V2,...写内存
verify --address A --width W --values ...按期望值校验内存

widthu8u16u32u64

cmsis-dap-cli read --address 0x20000000 --width u32 --count 4
cmsis-dap-cli read --address 0x08000000 --width u8 --count 0x1000 --output fw.bin --format bin
cmsis-dap-cli write --address 0x20000000 --width u32 --values 0xDEADBEEF,1,2

内核

命令用途
regs列出内核寄存器名
reg get NAME|NUM读寄存器(名字或编号)
reg set NAME|NUM VALUE写寄存器
status显示内核状态、停机原因与 PC
halt / resume / step暂停 / 恢复 / 单步
reset [--mode run|halt]复位后继续,或复位后暂停

核心在运行时读寄存器会失败——先 halt(一次性命令每次是新会话,请在 script/repl 里 halt 后再读):

cmsis-dap-cli script --text "connect\nhalt\nreg pc\nresume"

断点与数据观察点

bp set ADDR | bp list | bp clear
wp set ADDR --access read|write|rw | wp list | wp clear

DAP

dap read ADDR
dap write ADDR VALUE

原始 DP/AP 寄存器访问(ADDR 的 bit24..31 选择 AP,低位是寄存器)。

SVD(命名外设访问)

svd list
svd read PERIPH.REG[.FIELD]
svd write PERIPH.REG[.FIELD] VALUE

需要 --svd FILE。目标写法:GPIOA.ODRGPIOA.ODR.ODR0;位域写是 读-改-写。

cmsis-dap-cli --svd target.svd svd list
cmsis-dap-cli --svd target.svd svd read GPIOA.ODR.ODR0
cmsis-dap-cli --svd target.svd svd write GPIOA.ODR.ODR0 1

Flash

flash erase --address A --size N
flash program --address A --file FILE [--format elf|axf|bin|hex] [--verify]

擦除/烧录直接执行(无确认)。目标必须定义了 Flash,否则命令明确报错而不是 静默无效果。--format 默认按文件扩展名推断;--verify 会读回校验。

cmsis-dap-cli flash erase --address 0x08000000 --size 0x1000
cmsis-dap-cli flash program --address 0x08000000 --file fw.hex --verify

脚本

script --file FILE
script --text TEXT

执行 J-Link Commander / OpenOCD 风格脚本(见脚本使用)。 script 命令会继承全局连接参数,脚本里的 connect 直接使用它们。

芯片工具

chip generate --flm FILE --flash-start A --flash-size N --sram-start A --sram-size N [--name NAME] [--output FILE]
chip list
chip search KEYWORD

chip generate 从 Keil FLM 生成 probe-rs target YAML(见下文)。chip list/ chip search 列出或搜索内置芯片库(也可包含 --target-yaml 自定义芯片); 结果带 Flash/RAM 范围,一眼能看出能不能烧录。

符号

symbols list [PATTERN]
symbols resolve NAME

查看 --elf 固件的符号表。list 列出全部符号(可按大小写不敏感的子串 过滤)及虚拟地址;resolve 查询单个名字。watch/rtt/evr 正是用同一套 符号去定位变量和控制块。

cmsis-dap-cli --elf firmware.axf symbols resolve counter
cmsis-dap-cli --elf firmware.axf symbols list counter

变量实时观察(Live watch)

watch [--interval-ms N] [--count N] [--width u8|u16|u32|u64]
      [--log-dir DIR | --log-file FILE] TARGET...

按刷新间隔轮询一个或多个变量并打印带时间戳的采样行。TARGET 可以是符号名 (经 --elf 解析)或 0xADDR 地址。默认 --interval-ms 500--count 1 (采样一次)、--width u32--count 0 一直运行到 Ctrl-C;干净停止后退出码 为 0,并在 stderr 打印 stopped (Ctrl-C)

cmsis-dap-cli --target STM32F030C8 --elf firmware.axf \
  watch counter 0x20000004 --interval-ms 200 --count 0

示例输出(CMSIS-DAP 探针 + Cortex-M0+ 目标实测):

[2026-08-16 19:16:13.302] watch_var = 0x00001007
[2026-08-16 19:16:13.520] watch_var = 0x0000100E
[2026-08-16 19:16:13.736] watch_var = 0x00001015
rtt info
rtt monitor --channel 0,1 [--interval-ms N] [--count N]
            [--address A] [--log-dir DIR | --log-file FILE]

rtt info 附着目标 RTT 控制块并列出上行通道。rtt monitor 轮询所选上行 通道(逗号列表,默认 0),每收到一段数据就打印带主机时间戳和通道前缀的 一行([RTT0 "Channel 0"] ...)。控制块地址依次取自 --elf_SEGGER_RTT 符号、--address,或扫描目标 RAM(扫描需要芯片目标定义了 RAM:内置芯片或 --target-yaml)。默认 --interval-ms 200--count 0 (直到 Ctrl-C)、每通道每轮 --max-bytes 1024

固件需要运行 SEGGER RTT(例如 rtt_target 或 SEGGER RTT 实现),并且主机 附着前控制块已初始化。

cmsis-dap-cli --target STM32F030C8 --elf firmware.axf \
  rtt monitor --channel 0 --count 0 --log-dir logs

Event Recorder(CMSIS-View)

evr info
evr monitor [--interval-ms N] [--count N]
            [--ctx 0..7] [--address A]
            [--log-dir DIR | --log-file FILE]

evr info 附着片上 Event Recorder 并报告协议版本、记录数、时间戳频率与 计数器。evr monitor 通过纯 SWD/JTAG 内存读(无需 trace 硬件、无需串口) 轮询环形缓冲,并按官方 16 字节记录布局解码每个新事件:主机时间戳、目标侧 tick 数与秒数(按 ts_freq 换算)、事件上下文(记录 info 的 bit16..18, 取值 0..7)、组件与消息编号、序号以及 两个 32 位数值。--ctx 可按上下文过滤(可重复或逗号列表)。注意片上记录 只存 16 位事件 id(组件 + 消息);API 层的 level 用于固件内过滤,不写入记录。

固件需要包含 CMSIS-View Event Recorder 组件(符号 EventRecorderInfo)并在 主机附着前完成初始化。信息头地址取自 --elfEventRecorderInfo 符号或 --address

cmsis-dap-cli --target STM32F030C8 --elf firmware.axf \
  evr monitor --ctx 0,2 --count 0 --log-dir logs

监控输出、时间戳与日志导出

watchrtt monitorevr monitor 的每一行都带主机采集时间戳 [YYYY-MM-DD HH:MM:SS.mmm]--json 下每个采样/事件是 stdout 上的一行 NDJSON,并带 host_ts 字段(RFC 3339,毫秒 + 时区);EVR 事件额外保留 目标侧 timestamp_ticks/timestamp_secs

监控输出默认同时写入日志文件,位置是当前目录,文件名为自动生成 (watch-<unix秒>.logrtt-<unix秒>.logevr-<unix秒>.log); --log-dir DIR 指定其他目录(不存在会自动创建),--log-file FILE 则追加 写入确切文件。文件内容与 stdout 完全一致(每采样/事件一行),每行立即 flush; 监控启动时在 stderr 打印 logging to <路径>

交互式 shell

repl

非侵入调试

dump [--address A]... [--stack-words N] [--no-restore]

不复位目标的前提下采集 CPU 快照:寄存器、Cortex-M fault 状态寄存器 (CFSR/HFSR/DFSR/MMFAR/BFAR,不经停机直接读)、MSP/PSP 栈顶若干字与可选 内存采样。读核心寄存器需要短暂停机,默认读取后恢复原运行状态 (--no-restore 则保持停机)。--address 支持 0xADDR 或 ELF 符号名 (经 --elf)。

cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 dump \
  --address 0x20000000 --stack-words 16
cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 --elf fw.axf dump \
  --address counter --no-restore --json

远程 TCP 服务器

tcp-server [--port 4000]

127.0.0.1 上提供按行分隔的 JSON-RPC over TCP 协议,方法名与 MCP 工具 对齐(list_probesconnectread_memorywrite_memoryread_core_registerhaltresumestepresetstatusdump_cpu_state 等),每行一个请求,响应为 {"id":N,"result":...}{"id":N,"error":{...}}。后续请求复用同一会话, 无需重连。cmsis-dap-mcp --tcp PORT 可在 MCP stdio 之外同时提供该协议。

cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 tcp-server --port 4000
echo '{"id":1,"method":"read_memory","params":{"address":536870912,"width":"u32","count":4}}' \
  | nc 127.0.0.1 4000

GDB 服务器

gdb-server [--port 1337] [--reset-halt]

提供 GDB Remote Serial Protocol stub(移植自 probe-rs-tools,基于 gdbstub,MIT OR Apache-2.0): 任意 GDB(target remote :1337)可读写寄存器与内存、运行/单步/停机并使用 硬件断点。附着为非侵入(不复位;--reset-halt 可选)。 cmsis-dap-mcp --gdb-port 1337 可在 MCP 进程内启动同一服务器。

cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 gdb-server --port 1337
arm-none-eabi-gdb fw.elf -ex 'target remote :1337' -ex 'info registers'

参考资料:GDB Remote Serial Protocol 与 MCP 规范 (modelcontextprotocol.io);Cortex-M fault 状态寄存器属于 ARM System Control Block(见 ARMv6-M Architecture Reference Manual); Event Recorder 详见 CMSIS-View 文档

从 FLM 生成 target YAML

对于 probe-rs 内置库没有的芯片,烧录需要一份描述芯片并内嵌厂商 Flash 算法 的 target YAML。不用手写——chip generate 读取 Keil FLM,你只需要提供 Flash 与 SRAM 地址范围:

cmsis-dap-cli chip generate \
  --flm MyChip_64.FLM \
  --flash-start 0x08000000 --flash-size 0x10000 \
  --sram-start 0x20000000 --sram-size 0x2000 \
  --name MYCHIP --output MYCHIP.yaml

其余信息全部从 FLM 自动提取:算法指令、入口偏移(Init/ProgramPage/ EraseSector/EraseChip)、静态数据基址、FlashDevice 描述符(页大小、 擦除值、扇区大小、超时)与设备名。--name 默认取 FLM 文件名;用 --output - 把 YAML 打印到 stdout。

然后连接:

cmsis-dap-cli --target-yaml MYCHIP.yaml connect

当 target YAML 只定义一颗芯片变体时,--target 可以省略,CLI 会自动选择; 若定义了多颗,则必须给 --target NAME(命令会提示可用的名字)。

生成的 YAML 会把算法放在 SRAM 起始 + 0x20;请确保 SRAM 范围足够大 (放不下时命令会拒绝生成)。

查看与搜索芯片

cmsis-dap-cli chip list
cmsis-dap-cli chip search STM32F103
cmsis-dap-cli chip search stm32f103c8
cmsis-dap-cli --target-yaml MYCHIP.yaml chip search MYCHIP

搜索不区分大小写、按子串匹配。加 --json 会输出完整信息(所属系列、内核、 Flash 与 RAM 范围),方便脚本处理。

示例

一次完整调试会话

cmsis-dap-cli list
cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 connect
cmsis-dap-cli --target STM32F030C8 read --address 0x20000000 --width u32 --count 4
cmsis-dap-cli --target STM32F030C8 halt
cmsis-dap-cli --target STM32F030C8 reg get pc
cmsis-dap-cli --target STM32F030C8 step
cmsis-dap-cli --target STM32F030C8 resume

烧录固件并校验

cmsis-dap-cli --target STM32F030C8 flash erase --address 0x08000000 --size 0x10000
cmsis-dap-cli --target STM32F030C8 flash program --address 0x08000000 --file fw.hex --verify
cmsis-dap-cli --target STM32F030C8 read --address 0x08000000 --width u8 --count 0x100 --output dump.bin --format bin

脚本文件

flash.jlink

connect
halt
reg pc
savebin C:/dump.bin 0x20000000 0x100
resume
q
cmsis-dap-cli --target STM32F030C8 script --file flash.jlink

机器可读输出

cmsis-dap-cli --json connect
cmsis-dap-cli --json read --address 0x20000000 --width u32 --count 2
{"target":{"core_type":"Armv6m","core_count":1,"ap_count":1, ...}}
{"address":536870912,"width":"u32","values":[64000000,1]}

输出与退出码

  • 默认输出人类可读;--json 输出与 MCP 工具一致的 structured payload。 日志始终写 stderr。
  • 退出码:0 成功,1 运行时错误(探针/连接/烧录失败),2 用法错误 (未知参数、非法取值、缺参)。
  • 监控命令(watchrtt monitorevr monitor)每采样/事件输出一行 (--json 为 NDJSON),Ctrl-C 干净停止后退出 0--count N 限定轮数, 便于脚本与 CI。

REPL

repl 启动交互式 shell,一个会话保持打开,halt/读/恢复可以跨行执行:

$ cmsis-dap-cli --probe-id 0123456789AB --target STM32F030C8 repl
cmsis-dap-cli> connect
target: {"ap_count":1,"core_count":1,"core_type":"Armv6m", ...}
cmsis-dap-cli> halt
halted: true
cmsis-dap-cli> reg pc
pc = 0x800122A
cmsis-dap-cli> resume
running: true
cmsis-dap-cli> q

?/help 显示支持的命令;q/exit 退出。REPL 继承全局连接参数,connect 直接使用它们(不用重敲 --target)。REPL 里 Flash 擦除/烧录同样直接执行。

REPL 还提供带持久观察状态的实时调试命令:

watch add <name|0xADDR> [--width u8|u16|u32|u64] [--label TEXT]
watch list | watch remove <idx|name> | watch clear
watch interval <ms>
watch run [--count N] [--log-dir DIR | --log-file FILE]
rtt [info] [--channel 0,1] [--count N] [--interval-ms N] [--log-dir DIR | --log-file FILE]
evr [info] [--ctx 0..7] [--count N] [--log-dir DIR | --log-file FILE]

监控命令运行到 Ctrl-C(或 --count N)后回到提示符。

脚本命令

脚本引擎(script 与 REPL 共用)支持:

connect | disconnect | init        会话管理
si swd|jtag                        接口
speed <khz>                        时钟
device <name>                      目标芯片
adapter serial <id>                选择探针
halt | go | step                   执行控制
reset [run|halt]                   复位
reg <name> [<value>] | regs        内核寄存器
mem8/16/32 <addr> [<n>] | mdb/mdh/mdw   读内存
w8/16/32 <addr> <value> | mwb/mwh/mww   写内存
savebin <file> <addr> <size>       导出内存到二进制文件
dump_image <file> <addr> <size>    savebin 别名
loadbin <file> <addr>              烧录二进制文件
loadfile <file> [<addr>]           烧录 axf/elf/bin/hex
flash write_image <file> [<addr>]  loadfile 别名
flash erase_sector <addr> <size>   擦除一段 Flash
erase                              全片擦除
verifybin <file> [<addr>]          用文件校验内存
verify_image <file> [<addr>]       verifybin 别名
sleep <ms> | echo <text>           辅助命令
targets                            显示已连接目标
? | help | q | exit                帮助与退出

常见问题与提示

  • 选择芯片:内置芯片(chip search NAME)直接 --target NAME 即可; 其他芯片先用 chip generate 生成一次 target YAML,再用 --target-yaml 加载(单变体自动选择;多变体需 --target)。
  • Flash 需要芯片定义:没有定义时擦除/烧录会明确报错,而不是静默无效果。
  • 读寄存器需要先暂停内核:一次性模式下用 script/repl,让 haltreg 共享同一会话。
  • Flash 不能用 write:直接写 Flash 地址会被拒绝;用 flash program
  • 数字格式:十进制或十六进制(0x...)均可。

脚本使用

run_script 用 J-Link Commander / OpenOCD 风格命令子集执行线性调试脚本, 适合把“连接→读内存→烧录文件→复位“等重复流程固化成脚本,不必逐条调用工具。

运行脚本

传脚本文件路径,或内联文本:

run_script { "path": "/path/to/demo.jlink" }
run_script { "script": "halt\nreg pc\nresume" }

pathscript 二选一。脚本顺序执行,遇到第一条失败命令即停止。返回 ok、命令数量与每条命令的结果:

{
  "ok": true,
  "commands": 3,
  "results": [
    { "command": "halt", "status": "ok", "output": { "halted": true } },
    { "command": "reg pc", "status": "ok", "output": { "register": "pc", "value": 134228884 } },
    { "command": "resume", "status": "ok", "output": { "running": true } }
  ]
}

语法

  • 每行一条命令;; 也可作分隔符(OpenOCD 风格)。
  • 注释以 //# 开头。
  • 参数可用 "..."'...' 引起来(路径含空格时)。
  • 数字支持十进制或 0x 十六进制。
  • sleep <ms> 延时;echo <text> 输出;q / exit 结束脚本。

命令参考

以 J-Link Commander 命令名为主,OpenOCD 别名映射到同一批操作。

分类J-LinkOpenOCD 别名说明
会话connectsi SWD|JTAGspeed <khz>device <name>disconnectinitadapter speed <khz>adapter serial <serial>targets连接/配置会话
内核haltgostepreset [halt|run]reg <name> [value]regsresumeresetreg <name> [value]执行控制
内存mem8/16/32 <addr> [count]w8/16/32 <addr> <value>mdb/mdh/mdwmwb/mwh/mww读写内存
文件savebin <path> <addr> <size>loadbin <path> <addr>loadfile <path> [addr]verifybin <path> <addr>dump_image <path> <addr> <size>flash write_image <path> [offset]verify_image <path> [offset]导出/烧录/校验文件
Flasheraseflash erase_sector <addr> <size>擦除 Flash
其他sleep <ms>echo <text>q / exit-工具命令

savebin / dump_image 导出原始二进制;loadbin 按给定地址烧录原始二进制; loadfile / flash write_image 烧录文件(按扩展名推断 elf/axf/bin/hex); verifybin / verify_image 把文件与目标内存比较。

示例

保存 Flash 前 16KB,然后烧录并校验新固件:

connect
savebin C:/dump/fw.bin 0x08000000 0x4000
loadbin C:/fw/new.bin 0x08000000
verifybin C:/fw/new.bin 0x08000000
reset halt
go
q

OpenOCD 风格内联脚本:

halt; mdw 0x20000000 4; reg pc; resume

烧录 HEX 文件:

connect
flash write_image C:/fw/out.hex
reset

安全

run_script 是写级工具。脚本内的破坏性命令(eraseloadbinloadfileflash write_imageflash erase_sector)仍要求服务器以 --allow-destructive 启动,否则返回 DestructiveDisabled

SWD 与 JTAG

两种协议都支持。在 connect 时选择,或用服务器启动参数 --protocol 设置 默认值。

connect { "protocol": "swd" }    # 默认
connect { "protocol": "jtag" }

list_probes 会报告已连接探针支持的协议。大多数 CMSIS-DAP 探针两种都支持。

如何选择

  • SWD 是默认值,任何带调试端口的 Cortex-M 都可用,只需两根线(SWDIO、 SWCLK)加复位。
  • JTAG 需要目标引出 JTAG TAP 与四/五根 JTAG 引脚。很多小型 Cortex-M0/M0+ 器件没有引出 JTAG。

服务器已在硬件上通过 SWD 验证。如果目标不支持 JTAG,connect 会返回 ConnectFailed 协议错误;对支持 JTAG 的目标,工具集完整支持 JTAG。

速度

connect 中传 speed_khz,或在启动时设置 --speed-khz。探针会选择不 高于请求的最高可用速度。

复位下连接

对于锁定或无响应的目标,可在连接期间保持复位线:

connect { "protocol": "swd", "under_reset": true }

这要求探针的复位引脚已连接到目标的复位。

SVD 与 Flash

SVD 文件

SVD 文件描述芯片的外设与寄存器。运行时提供你自己的文件:

load_svd { "path": "/path/to/your-chip.svd" }
list_peripherals {}
read_peripheral { "peripheral": "GPIOA", "register": "ODR" }
write_peripheral { "peripheral": "GPIOA", "register": "ODR", "field": "ODR0", "value": 1 }

位域写入为读-改-写。本仓库绝不捆绑芯片专有数据。

Flash 编程

Flash 工具需要带烧写算法的目标描述。从芯片的 CMSIS-Pack 生成 probe-rs 目标 YAML(或手写),并以此启动服务器:

cmsis-dap-mcp --target-yaml /path/to/your-target.yaml --allow-destructive

用 YAML 中定义的目标名连接,然后擦除与编程:

connect { "protocol": "swd", "target": "YourChip" }
erase_flash { "address": 0x08000000, "size": 0x1000 }
program_flash { "address": 0x08000000, "data": [0x00, 0x11, ...], "verify": true }

verify: true 会在烧写后读回校验。erase_flash 只擦除与请求范围重叠的扇区; 传入完整 Flash 范围即整片擦除。

推荐的 Flash 流程(已实测)

  1. 先读出当前固件并保留备份。
  2. 只擦除要写入的扇区。
  3. verify: true 编程。
  4. 读回并用 verify_memory 校验结果。
  5. 若目标需保留原固件,则恢复备份。

安全

  • 只读工具始终可用。
  • 写与调试控制工具标记为写操作,由你的 MCP 客户端审批策略决定。
  • erase_flashprogram_flash 为破坏性工具,默认禁用。可通过启动参数 --allow-destructive 运行时 update_configallow_destructive: true 启用;未启用时调用返回 DestructiveDisabled

Flash 擦除、Option 字节修改、读保护与调试解锁可能导致设备永久损坏或不可恢复。 只有明确要重新编程目标时才启用破坏性模式。

日志只写入 stderr(或 --log-file),绝不写入 stdout,因此不会污染 MCP 协议流。

read_memorypath 参数时会在主机上你指定的路径写入导出文件(bin/hex); run_script 也可能读写主机文件。这与 load_svd 相同的信任模型:路径由用户 提供,并在运行服务器的机器上执行。

故障排查

探针未列出

  • Windows:CMSIS-DAP v2 探针需要 WinUSB 驱动。如果探针不出现,请用 Zadig 把驱动替换为 WinUSB。CMSIS-DAP v1(HID) 探针通常无需驱动。
  • Linux:安装授予 USB 设备访问权限的 udev 规则(见 README),然后重新 插拔探针。
  • macOS:通常开箱即用;若探针被拦截,检查系统设置 > 隐私与安全性。

连接失败

  • 检查接线:SWDIO/SWCLK(使用 under_reset 时还需 nRST)。
  • 降低速度:connect { "speed_khz": 100 }
  • 锁定目标可尝试 under_reset: true
  • 目标未引出 JTAG TAP 时,JTAG 会返回 ConnectFailed,请改用 SWD。

寄存器名错误

名称大小写不敏感且按角色解析(pcspfplrrapsrxpsrmsppspfpsrr0-r15)。其他名称必须匹配架构寄存器表;可用 list_core_registers 查看可用项。

Flash 工具返回 DestructiveDisabled

--allow-destructive 启动服务器。

Flash 算法加载失败

  • 目标 YAML 必须定义足够大的 RAM 区域以容纳算法、header 与栈。
  • load_address 必须为 4 字节算法 header 留出空间,例如 RAM 从 0x20000000 开始时用 0x20000020
  • YAML 中的 pc_initpc_uninitpc_erase_sectorpc_program_pagepc_erase_all相对代码起始地址的偏移

文件格式与脚本

  • bin 文件没有地址信息:必须显式给 address(或脚本 loadbin 的地址)。
  • axf 是 ELF 容器:用 axfauto 格式,走 ELF 解析。
  • hex 是标准 Intel HEX(type 00/04/01);校验和或记录非法时返回 FileError
  • 有效的 ELF/AXF 必须包含可加载节;无节的 ELF 会以 FileError (“no loadable segments”)失败。
  • 脚本遇到第一条失败命令即停止;请查看返回结果中每条命令的 statusoutput

AI 客户端不显示工具

  • 添加服务器后重启客户端。
  • Codex:codex mcp list 必须显示服务器已启用;桌面端在新会话启动时加载。
  • 检查客户端配置中的二进制路径是否正确且可执行。

RTT / Event Recorder

  • RTT attach failed: control block not found —— 固件必须初始化 SEGGER RTT(SEGGER_RTT_Init()),且主机要在初始化之后、核心进入 main 运行后再附着(不能在停机时附着)。传入 --elf_SEGGER_RTT 符号)或 --address,并在 replreset run 后运行监控,确保核心 真正在执行。
  • evr 需要地址 —— 固件必须包含 CMSIS-View Event Recorder 组件 (符号 EventRecorderInfo)。传入 --elf--address,并在附着前用 EventRecorderInitialize 完成初始化。
  • 一次性命令读到的是旧值 —— 每次一次性调用都会新建会话,probe-rs 附着时核心处于停机。请在 replconnect + reset run,再执行 watch run / rtt monitor / evr monitor
  • EVR 秒数看起来不对 —— 秒数由固件 ts_freqEVENT_TIMESTAMP_FREQ)换算;请把它设为实际时间戳时钟(例如 SystemCoreClock)。tick 本身始终单调递增。

架构说明

cmsis-dap-mcp 是单个 Rust 进程,通过 stdio 使用 MCP 协议。它是纯服务器: 由 MCP 客户端(Codex、Claude Code、opencode 或任意兼容 MCP 的主机)驱动, 自身不提供界面。

仓库是包含三个 crate 的 Cargo workspace:cmsis-dap-core(两个工具共用的 MCP 无关引擎)、cmsis-dap-mcp(本服务器)与 cmsis-dap-cli(基于同一 引擎的独立命令行工具)。下图展示的是该 workspace 中服务器一侧的构成。

系统总览

MCP 客户端(Codex / Claude Code / opencode / 任意 MCP 主机)
    |
    |  MCP stdio:JSON-RPC 2.0,换行分隔,运行在 stdout
    v
+--------------------------------------------------------------+
|  cmsis-dap-mcp(单个 Rust 进程,日志只写 stderr)              |
|                                                              |
|  +--------------------------------------------------------+  |
|  | MCP 工具层(rmcp)                                       |  |
|  |  probe | memory | core | dap | svd | flash | file | script | |
|  +--------------------------------------------------------+  |
|  | 安全策略:只读 / 写 / 破坏性                              |  |
|  +--------------------------------------------------------+  |
|  | 会话管理:探针选择、会话与 SVD 状态                       |  |
|  +--------------------------------------------------------+  |
|  | 后端接口(Backend trait)                                |  |
|  |  ProbeRsBackend(真实)         MockBackend(测试)      |  |
|  +--------------------------------------------------------+  |
|  | probe-rs 库(SWD/JTAG、Flash、ELF/HEX/BIN 解析)          |  |
|  +--------------------------------------------------------+  |
+--------------------------------------------------------------+
    |
    |  USB(HID / WinUSB)
    v
CMSIS-DAP 探针 ---- SWD / JTAG ----> Cortex-M 目标

模块职责

模块职责
cli解析启动参数、配置日志、启动 stdio 服务器
mcp用 rmcp 注册工具、MCP 注解、server instructions
mcp/tools_*各领域参数与处理器(probe、memory、core、dap、svd、flash、script)
script线性 J-Link Commander / OpenOCD 风格脚本解析与执行
hex内存导出用的 Intel HEX 编码器
security三级策略;破坏性工具需要 --allow-destructive
session单个活动会话;持有探针/会话与 SVD 状态
backendBackend trait 及 ProbeRsBackendMockBackend 实现,含 RTT 附着/读取与 Event Recorder 附着/轮询
gdbGDB Remote Serial Protocol stub(移植自 probe-rs-tools,基于 gdbstub);非侵入附着,支持寄存器/内存/运行/单步/硬件断点
remote远程 TCP JSON-RPC 服务器,复用同一会话;方法名与 MCP 工具一致(read_memorywrite_memoryhaltresumestepresetstatusdump_cpu_state 等)
evrCMSIS-View Event Recorder 解码(官方 16 字节记录布局),供 CLI 的 evr 命令使用
svdSVD 解析与外设/寄存器/位域命名解析
error错误码与结构化 McpError

工具调用流程

MCP 客户端          服务器                  后端                目标
   |  tools/call      |                        |                      |
   |----------------->|  安全检查               |                      |
   |                  |  锁定会话               |                      |
   |                  |  backend.read_memory() |-- SWD/JTAG 读取 ---->|
   |                  |<-----------------------|                      |
   |<-----------------|  结构化 JSON            |                      |

每次工具调用都走同一条路径:解析并校验参数 → 检查安全等级 → 获取会话 → 在后端执行操作 → 返回结构化 JSON(或分类错误)。

文件与脚本路径

program_flash {data: [...]}  ->  backend.program_flash  ->  FlashLoader(原始数据)
program_flash {path, format} ->  backend.program_file   ->  BIN:读取 + add_data
                                                             ELF/AXF/HEX:probe-rs build_loader
read_memory {path, format}   ->  backend.export_memory  ->  BIN:原始字节
                                                             HEX:hex::encode_ihex
run_script {path | script}   ->  script::run           ->  逐命令分派到后端
                                                             (破坏性命令由策略门禁)

构建与发布流程

特性分支 -> develop -> main -> tag vX.Y.Z
                                  |
                                  v
             CI:三平台 fmt / clippy / test / build
                                  |
             +--------------------+--------------------+
             |                                         |
             v                                         v
 GitHub Release 二进制                        npm 平台包
 (win32/linux/darwin × x64/arm64)           (元包 cmsis-dap-mcp + 平台包)
             |
             v
 GitHub Pages 文档(英文 /,中文 /zh/)

开发与发布

构建与测试

cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo build --release --workspace

这会构建两个二进制:target/release/cmsis-dap-mcp(MCP 服务器)与 target/release/cmsis-dap-cli(命令行工具)。

代码规范

  • cargo fmt --check 必须通过;提交前用 cargo fmt 格式化。
  • cargo clippy --workspace --all-targets -- -D warnings 必须通过且无警告。
  • 提交信息遵循 Conventional Commitstype(scope): subject,type 为 featfixdocsrefactortestchoreperf 之一。参考 CHANGELOG 风格示例。
  • 仓库不得出现厂商专有词;推送前运行 scripts/check-no-vendor.ps1 (Windows PowerShell)。CI 会强制执行此检查。

贡献指南

  • 分支策略:特性分支合并到 develop,再由 develop 合并到 main。 推送 vX.Y.Z tag 会触发发布工作流。
  • PR 必须通过完整 CI 套件(Windows、Linux、macOS 三平台的 fmt / clippy / test / build)与厂商内容扫描。
  • 涉及探针或目标行为的变更建议在真实硬件上验证:在真实 CMSIS-DAP 探针 + Cortex-M 板子上跑通后再开 PR。
  • 中英文文档必须同步:docs/src/ 的任何用户可见变更都要镜像到 docs/zh/src/

测试策略

  • 单元测试:各 crate 的 crates/*/tests/ 覆盖后端(mock 与 probe-rs)、 SVD 解析、hex 编码、寄存器提示、安全策略、会话管理与脚本。
  • 集成测试crates/cmsis-dap-cli/tests/ 端到端测试 CLI(参数、命令、 实时监控、非侵入 dump);crates/cmsis-dap-mcp/tests/ 覆盖 MCP 处理器 与功能开关。
  • 硬件验证:每次发布前,在真实 CMSIS-DAP 探针 + Cortex-M 目标上跑 完整端到端会话(枚举探针、连接、读写内存、halt/resume、寄存器访问、 带校验的 Flash 烧录、实时 watch / RTT / Event Recorder 监控、非侵入 dump)。此步骤为手工验证,不在 CI 中执行。

文档维护

每次发布前,按以下清单保持文档与代码同步:

  1. 对照 CHANGELOG.md 与上次发布以来的实际 diff,在 ## [vX.Y.Z] - unreleased 段补充遗漏条目。
  2. 审计所有 README(README.mdnpm/README.mdnpm-cli/README.md), 按当前功能集更新工具表与配置示例。
  3. 校对 docs/src/SUMMARY.mddocs/zh/src/SUMMARY.md,确保章节列表 与用户/开发者分组反映当前状态。
  4. 对照 docs/src/tools.mdcrates/cmsis-dap-mcp/src/mcp/ 的 MCP 工具 实现,补充新工具及其参数。
  5. 对照 docs/src/architecture.md 模块表与 crates/cmsis-dap-core/src/,补充新模块。
  6. 同步 docs/zh/src/ 中文镜像——结构、示例与命令输出必须与英文版一致。
  7. 本地构建两份书:
    mdbook build docs        # 英文
    mdbook build docs/zh     # 中文
    
  8. 运行厂商内容扫描:
    powershell -File scripts/check-no-vendor.ps1
    

任一步骤发现差异,必须在打 tag 发布前修正。

文档

mdbook build docs     # 英文
mdbook build docs/zh  # 中文

发布流程

仓库遵循 GitFlow:特性分支合并到 develop,再合并 developmain。 推送 vX.Y.Z tag 会触发发布工作流:构建三个平台二进制、发布 npm 元包与 平台包(cmsis-dap-mcpcmsis-dap-cli 两套)、上传 GitHub Release 资产,并重建 GitHub Pages 文档。

发布前请在真实硬件上跑完整验证套件,并执行厂商内容扫描:

powershell -File scripts/check-no-vendor.ps1