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-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...)均可。