CMSIS-DAP MCP
面向 CMSIS-DAP 调试探针与 Cortex-M 芯片的开源调试工具套件,提供 MCP 服务器(供 AI 助手驱动)和独立命令行工具,两者共用同一引擎,通过 SWD 或 JTAG 工作。
新用户? 请从从零开始入手,一步步完成环境搭建 和首次连接。
两个工具
- 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_watchpoints | DWT 数据观察点(读/写/读写触发) |
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
文档导航
- 从零开始 —— 完整的环境搭建与首次连接教程
- 快速开始 —— MCP 服务器快速配置
- AI 客户端配置 —— Codex / Claude Code / opencode 配置
- 工具参考 —— MCP 工具完整参考
- 命令行工具 —— CLI 命令完整参考
- 脚本使用 —— J-Link / OpenOCD 风格脚本
- SWD 与 JTAG —— 协议选择
- SVD 与 Flash —— 外设访问与烧录
- 安全 —— 安全模型与配置
- 故障排查 —— 常见问题
英文文档: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,无需串口。
需要什么硬件
必需
-
CMSIS-DAP 调试探针
- 支持 CMSIS-DAP v1(HID)或 v2(WinUSB)协议
- 大多数市售 CMSIS-DAP 兼容探针均可使用
- 通过 USB 连接电脑
-
Cortex-M 开发板
- 任何带 SWD 调试端口的 ARM Cortex-M 开发板
- 支持 M0、M0+、M3、M4、M7 全系列内核
- 探针和开发板之间通过 SWD 线连接
-
SWD 连接线
- 至少 3 根线:SWDIO、SWCLK、GND
- 将探针的 SWD 引脚连接到开发板对应的调试端口
可选
- 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 驱动。
- 从 https://zadig.akeo.ie/ 下载 Zadig
- 插入探针,打开 Zadig
- 在菜单中选择
Options → List All Devices - 选择你的 CMSIS-DAP 设备
- 将驱动替换为 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_probes、connect 等工具完成操作。
进阶:Flash 烧录
准备工作
- 确认你的芯片有对应的 FLM 闪存算法文件
- 知道芯片的 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)。
下一步
- 快速开始 —— MCP 服务器快速上手
- AI 客户端配置 —— 各 AI 客户端的详细配置
- 工具参考 —— MCP 工具完整参考
- 命令行工具 —— CLI 命令完整参考
- 脚本使用 —— J-Link / OpenOCD 风格脚本
- SWD 与 JTAG —— 协议选择指南
- SVD 与 Flash —— 外设访问与烧录工作流
- 故障排查 —— 常见问题与解决方案
快速开始
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 是已发布包的标准写法;本地
二进制写法与之等价,用于本地构建。
| 方式 | 示例 | 适用场景 |
|---|---|---|
npx 包 | command = "npx", args = ["-y", "cmsis-dap-mcp"] | 已发布版本;随 npm 更新 |
| 本地二进制 | command = "/path/to/cmsis-dap-mcp" | 本地构建、离线、精确版本 |
| 远程 URL | url = "https://..." | Streamable-HTTP 服务器(本项目暂不支持) |
AI 客户端配置 页中三个客户端都同时接受 npx 与本地二进制
路径两种写法,服务器行为完全一致。
第一次会话
服务器可零参数启动——进入待配置态:所有读/写工具可用,破坏性工具保持 门控,直到按第 7 步启用。
list_probes查找探针 id。connect,参数{"protocol": "swd", "speed_khz": 1000}。read_memory/write_memory原始内存访问。halt,然后read_core_register(例如pc、sp、lr、r0)。- 完成后
resume。 load_svd加载你自己的 SVD 文件,进行命名外设访问。program_flash/erase_flash需要破坏性模式:启动时加--allow-destructive,或运行时调用update_config {"allow_destructive": true}(无需重启)。- 对 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" | 未发布或本地构建、离线、精确版本 |
| 远程 URL | url = "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 FILE | JSON 配置文件(键:allow_destructive、tcp_port、gdb_port);启动时加载,可监听变更 |
--probe-id ID | connect 的默认探针 id |
--protocol swd|jtag | 默认调试协议(默认 swd) |
--speed-khz N | 默认 SWD/JTAG 时钟速度 |
--target NAME | 默认目标芯片名 |
--svd FILE | 启动时加载的 SVD 文件 |
--target-yaml FILE | 预加载到芯片注册表的 target YAML |
--log-level LEVEL | tracing 过滤器;日志写 stderr(默认 info) |
--log-file FILE | 日志写入文件而非 stderr |
仅启动时固定(运行时不可变更):--log-level、--log-file、
--config-file 路径本身(其内容可重载)、backend 注册表种子
(--target-yaml;define_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等价。 connect、halt、resume等写工具可能受客户端审批策略约束。- 添加服务器后如果工具不出现,请重启客户端。
工具参考
安全等级:读(始终可用)、写(由客户端审批)、破坏性(需
启动时 --allow-destructive 或 运行时 update_config 设
allow_destructive: true)。
探针与会话
| 工具 | 参数 | 等级 |
|---|---|---|
list_probes | - | 读 |
get_probe_info | probe_id(可选) | 读 |
connect | probe_id、protocol(swd/jtag,默认 swd)、speed_khz、target、under_reset | 写 |
disconnect | - | 写 |
get_target_info | - | 读 |
list_probes 返回探针 id、厂商/产品、序列号、产品 id、接口、HID 标记、
支持的协议、速度与目标电压(探针支持时)。
get_target_info 返回内核类型与数量、真实 AP 数量、CPUID、DPIDR 与内存映射
摘要(RAM/NVM 区域)。
内存
| 工具 | 参数 | 等级 |
|---|---|---|
read_memory | address、width(u8/u16/u32/u64)、count(默认 1)、path、format | 读 |
write_memory | address、width、values | 写 |
verify_memory | address、width、data | 读 |
verify_memory 读回指定范围并与 data 比较,返回 verified 与 mismatches
列表。
read_memory 还可以把范围导出到文件:传 path 加 format(默认 bin 或
hex),此时 count 表示字节数。示例:
read_memory { "address": 0x08000000, "width": "u8", "count": 0x1000, "path": "firmware.bin", "format": "bin" }
内核
| 工具 | 参数 | 等级 |
|---|---|---|
read_core_register | name 或 number | 读 |
write_core_register | name 或 number、value | 写 |
list_core_registers | - | 读 |
get_core_status | - | 读 |
halt | - | 写 |
resume | - | 写 |
step | - | 写 |
reset | mode(默认 run / halt) | 写 |
寄存器名大小写不敏感。支持特殊角色(pc、sp、fp、lr/ra、
psr/xpsr、msp、psp、fpsr)与通用寄存器(r0-r15);其他名称会在
架构寄存器表中查找。list_core_registers 返回全部可用名称。
get_core_status 返回 state(running/halted/sleeping/locked_up/
unknown)、暂停时的 halt_reason 与程序计数器。
非侵入调试
| 工具 | 参数 | 等级 |
|---|---|---|
dump_cpu_state | address(可重复,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_breakpoint | address | 写 |
clear_breakpoints | - | 写 |
list_breakpoints | - | 读 |
set_watchpoint | address、access(read/write/rw) | 写 |
clear_watchpoints | - | 写 |
list_watchpoints | - | 读 |
数据观察点使用内核的 DWT 比较器,只对内核的读写访问触发,不会因调试器写入
触发。目标没有 DWT 比较器时返回 UnsupportedFeature。
DAP
| 工具 | 参数 | 等级 |
|---|---|---|
read_dap | address | 读 |
write_dap | address、value | 写 |
DAP 地址在 bit 24-31 放 APSEL 表示 AP 访问(例如 0x010000FC);否则 bit 0-7
是 DP 寄存器地址(bit 4-7 选择 DP bank)。
SVD
| 工具 | 参数 | 等级 |
|---|---|---|
load_svd | path | 写 |
list_peripherals | - | 读 |
read_peripheral | peripheral、register、field(可选) | 读 |
write_peripheral | peripheral、register、field(可选)、value | 写 |
位域写入为读-改-写。
Flash
| 工具 | 参数 | 等级 |
|---|---|---|
erase_flash | address、size | 破坏性 |
program_flash | address、data 或 path、format(可选)、verify(可选) | 破坏性 |
erase_flash 只擦除与 [address, address+size) 重叠的扇区;传入完整 Flash
范围即整片擦除。program_flash 带 verify: true 时烧写后读回校验。除了原始
data,还可以用 path 传入固件文件:
program_flash { "address": 0x08004000, "path": "/path/to/fw.hex", "format": "hex", "verify": true }
支持的格式:elf、axf(与 ELF 同容器)、bin(必须给 address)、
hex/ihex/intelhex,或 auto(默认,按扩展名
.elf/.axf/.bin/.hex/.ihx 推断)。
芯片定义
| 工具 | 参数 | 等级 |
|---|---|---|
define_chip | flm、flash_start、flash_size、sram_start、sram_size、core(可选,默认 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_config | allow_destructive(可选)、tcp_port(可选)、gdb_port(可选) | 写 |
reload_config | - | 写 |
这些工具管理服务器的运行时配置。服务器可以零参数启动(待配置态),然后 完全在运行时配置——无需重启。
get_config 返回当前配置的 JSON:allow_destructive、tcp_port、
gdb_port、config_file。
update_config 执行部分更新:省略任意字段即保持当前值。候选配置在写入前
先校验,无效值将整体拒绝(原子性,不部分生效)。更新成功后,服务器自动
收敛运行中的 TCP/GDB 任务以匹配新配置(幂等)。
allow_destructive—true开启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_script | path 或 script | 写 |
run_script 用 J-Link Commander / OpenOCD 风格命令子集执行线性调试脚本。
完整命令参考与示例见 脚本使用。
错误码
错误返回结构化 JSON,含 code 与 message:ProbeNotFound、
ConnectFailed、NotConnected、ProtocolError、Timeout、MemoryFault、
SvdNotLoaded、FileError、UnsupportedFeature、DestructiveDisabled、
InvalidArgument、InternalError。
命令行工具
简介
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 N | SWD/JTAG 时钟(kHz) |
--target NAME | 目标芯片名(内置库或 --target-yaml 中的变体) |
--under-reset | 按住复位连接(锁定/无响应目标) |
--target-yaml FILE | 加载 target YAML(芯片 + Flash 算法定义) |
--svd FILE | SVD 文件(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 ... | 按期望值校验内存 |
width 为 u8、u16、u32 或 u64。
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.ODR 或 GPIOA.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(J-Link RTT 日志)
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)并在
主机附着前完成初始化。信息头地址取自 --elf 的 EventRecorderInfo 符号或
--address。
cmsis-dap-cli --target STM32F030C8 --elf firmware.axf \
evr monitor --ctx 0,2 --count 0 --log-dir logs
监控输出、时间戳与日志导出
watch、rtt monitor、evr monitor 的每一行都带主机采集时间戳
[YYYY-MM-DD HH:MM:SS.mmm]。--json 下每个采样/事件是 stdout 上的一行
NDJSON,并带 host_ts 字段(RFC 3339,毫秒 + 时区);EVR 事件额外保留
目标侧 timestamp_ticks/timestamp_secs。
监控输出默认同时写入日志文件,位置是当前目录,文件名为自动生成
(watch-<unix秒>.log、rtt-<unix秒>.log、evr-<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_probes、connect、read_memory、write_memory、
read_core_register、halt、resume、step、reset、status、
dump_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用法错误 (未知参数、非法取值、缺参)。 - 监控命令(
watch、rtt monitor、evr 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,让halt和reg共享同一会话。 - 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" }
path 与 script 二选一。脚本顺序执行,遇到第一条失败命令即停止。返回
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-Link | OpenOCD 别名 | 说明 |
|---|---|---|---|
| 会话 | connect、si SWD|JTAG、speed <khz>、device <name>、disconnect | init、adapter speed <khz>、adapter serial <serial>、targets | 连接/配置会话 |
| 内核 | halt、go、step、reset [halt|run]、reg <name> [value]、regs | resume、reset、reg <name> [value] | 执行控制 |
| 内存 | mem8/16/32 <addr> [count]、w8/16/32 <addr> <value> | mdb/mdh/mdw、mwb/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] | 导出/烧录/校验文件 |
| Flash | erase | flash 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 是写级工具。脚本内的破坏性命令(erase、loadbin、
loadfile、flash write_image、flash 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 流程(已实测)
- 先读出当前固件并保留备份。
- 只擦除要写入的扇区。
- 以
verify: true编程。 - 读回并用
verify_memory校验结果。 - 若目标需保留原固件,则恢复备份。
安全
- 只读工具始终可用。
- 写与调试控制工具标记为写操作,由你的 MCP 客户端审批策略决定。
erase_flash与program_flash为破坏性工具,默认禁用。可通过启动参数--allow-destructive或 运行时update_config设allow_destructive: true启用;未启用时调用返回DestructiveDisabled。
Flash 擦除、Option 字节修改、读保护与调试解锁可能导致设备永久损坏或不可恢复。 只有明确要重新编程目标时才启用破坏性模式。
日志只写入 stderr(或 --log-file),绝不写入 stdout,因此不会污染 MCP
协议流。
read_memory 带 path 参数时会在主机上你指定的路径写入导出文件(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。
寄存器名错误
名称大小写不敏感且按角色解析(pc、sp、fp、lr、ra、psr、xpsr、
msp、psp、fpsr、r0-r15)。其他名称必须匹配架构寄存器表;可用
list_core_registers 查看可用项。
Flash 工具返回 DestructiveDisabled
以 --allow-destructive 启动服务器。
Flash 算法加载失败
- 目标 YAML 必须定义足够大的 RAM 区域以容纳算法、header 与栈。
load_address必须为 4 字节算法 header 留出空间,例如 RAM 从0x20000000开始时用0x20000020。- YAML 中的
pc_init、pc_uninit、pc_erase_sector、pc_program_page、pc_erase_all是相对代码起始地址的偏移。
文件格式与脚本
bin文件没有地址信息:必须显式给address(或脚本loadbin的地址)。axf是 ELF 容器:用axf或auto格式,走 ELF 解析。hex是标准 Intel HEX(type 00/04/01);校验和或记录非法时返回FileError。- 有效的 ELF/AXF 必须包含可加载节;无节的 ELF 会以
FileError(“no loadable segments”)失败。 - 脚本遇到第一条失败命令即停止;请查看返回结果中每条命令的
status与output。
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,并在repl里reset run后运行监控,确保核心 真正在执行。evr需要地址 —— 固件必须包含 CMSIS-View Event Recorder 组件 (符号EventRecorderInfo)。传入--elf或--address,并在附着前用EventRecorderInitialize完成初始化。- 一次性命令读到的是旧值 —— 每次一次性调用都会新建会话,probe-rs
附着时核心处于停机。请在
repl中connect+reset run,再执行watch run/rtt monitor/evr monitor。 - EVR 秒数看起来不对 —— 秒数由固件
ts_freq(EVENT_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 状态 |
backend | Backend trait 及 ProbeRsBackend、MockBackend 实现,含 RTT 附着/读取与 Event Recorder 附着/轮询 |
gdb | GDB Remote Serial Protocol stub(移植自 probe-rs-tools,基于 gdbstub);非侵入附着,支持寄存器/内存/运行/单步/硬件断点 |
remote | 远程 TCP JSON-RPC 服务器,复用同一会话;方法名与 MCP 工具一致(read_memory、write_memory、halt、resume、step、reset、status、dump_cpu_state 等) |
evr | CMSIS-View Event Recorder 解码(官方 16 字节记录布局),供 CLI 的 evr 命令使用 |
svd | SVD 解析与外设/寄存器/位域命名解析 |
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 Commits:
type(scope): subject,type 为feat、fix、docs、refactor、test、chore、perf之一。参考 CHANGELOG 风格示例。 - 仓库不得出现厂商专有词;推送前运行
scripts/check-no-vendor.ps1(Windows PowerShell)。CI 会强制执行此检查。
贡献指南
- 分支策略:特性分支合并到
develop,再由develop合并到main。 推送vX.Y.Ztag 会触发发布工作流。 - 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 中执行。
文档维护
每次发布前,按以下清单保持文档与代码同步:
- 对照
CHANGELOG.md与上次发布以来的实际 diff,在## [vX.Y.Z] - unreleased段补充遗漏条目。 - 审计所有 README(
README.md、npm/README.md、npm-cli/README.md), 按当前功能集更新工具表与配置示例。 - 校对
docs/src/SUMMARY.md与docs/zh/src/SUMMARY.md,确保章节列表 与用户/开发者分组反映当前状态。 - 对照
docs/src/tools.md与crates/cmsis-dap-mcp/src/mcp/的 MCP 工具 实现,补充新工具及其参数。 - 对照
docs/src/architecture.md模块表与crates/cmsis-dap-core/src/,补充新模块。 - 同步
docs/zh/src/中文镜像——结构、示例与命令输出必须与英文版一致。 - 本地构建两份书:
mdbook build docs # 英文 mdbook build docs/zh # 中文 - 运行厂商内容扫描:
powershell -File scripts/check-no-vendor.ps1
任一步骤发现差异,必须在打 tag 发布前修正。
文档
mdbook build docs # 英文
mdbook build docs/zh # 中文
发布流程
仓库遵循 GitFlow:特性分支合并到 develop,再合并 develop 到 main。
推送 vX.Y.Z tag 会触发发布工作流:构建三个平台二进制、发布 npm 元包与
平台包(cmsis-dap-mcp 与 cmsis-dap-cli 两套)、上传 GitHub Release
资产,并重建 GitHub Pages 文档。
发布前请在真实硬件上跑完整验证套件,并执行厂商内容扫描:
powershell -File scripts/check-no-vendor.ps1