docs(测试说明): 按用途分六个子目录并同步全库引用

分层:流程与规范/ 单元测试/ 板级测试/ 专项验证/ 测试工具/ 测试数据/,
顶层只留新增的目录导航 README.md(归层判据 + 硬约束 + 本次处置记录)。

- 搬迁 28 个路径:测试数据三个目录 58 个文件为纯改名(R100,内容逐字节不变)
- 全库引用同步 124 个文件:AGENTS / docs 索引 / skills / 门禁注释 / scripts
- 门禁面:scripts/check_test_traceability.py 的 glob 改 rglob
  (分层后不递归扫描=追溯门禁直接瞎掉)
- scripts/rename_ref.py:收尾的 ℹ 提示在 GBK 代码页抛 UnicodeEncodeError,
  让进程以退出码 1 收场而改写其实已落盘(RC 与真实结果相反);改为把
  stdout/stderr reconfigure 成 UTF-8,与 check_doc_links.py 等同法
- docs/文档规范.md §1.1 补「子目录文件过多时再分一层」;§3.6 补 rename_ref
  搬整目录的两个实测坑:① 会改写目录内部文件的内容 ② 内部文件的 ../ 出链
  不补层级(本次 23 个被误改的证据文件已按 HEAD 原始字节逐字节还原)
- docs/README.md §6 改为与六个子目录一一对应,并补登原先漏登记的
  「启动日志原子性复验流程」一行
- .cubemx_survival_baseline.json:App/util/task_watchdog.c 的注释路径也随分层更新,
  该文件是存活审计的 watchdog-module 漂移锚点,按脚本自己的提示跑 --write 重建基线
  (实测重建后仅 watchdog-module 一条哈希变化)
- 铁律 4 例外(本次在任务树里改了单写者文件):AGENTS.md 与
  .pre-commit-config.yaml 只被 rename_ref 改写路径字面量(后者全在注释行),
  任务表块与钩子声明一字未动

验证:check_doc_links.py --sections-strict 覆盖全部 88 个改动 .md 全绿;
check_test_traceability.py 输出与主树逐行一致;196 个文本文件无 BOM、无新增
CR、无 U+FFFD、无行尾空白;陈旧引用面由主树 25 处降到 6 处(无新增断链)。
This commit is contained in:
2026-10-30 07:06:38 +08:00
parent fea4cc7502
commit f754d59218
209 changed files with 644 additions and 528 deletions
@@ -0,0 +1,231 @@
# ST-LINK_CLI 复位使用说明(v3.5.0.0 本机实测版)
> 依据:本机 ST-LINK Utility 4.5.0.0 自带 `ST-LINK_CLI.exe`(CLI 版本 v3.5.0.0,`-h` 全文已实测核对)+ ST 官方文档语义。
> 探针路径:经 `DTU_STLINK_CLI` 环境变量解析(本机设为标准安装位 `C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe`;未设时回退 PATH,`stlink_flash.py` 均可用)
> 2026-09-19 已上板实测(ST-LINK/V2,FW V2J37S7,SN `0B250D12A218303030303032`;STM32F407ZGTx 目标,SWD)。
> 2026-09-20 复测(V0.1 板):烧写静默失败根因闭环(见 §2 ⑤ 与 §7)、完整启动闭环(见 §5)。
> ⚠️ **本机接线:3 根线(SWDIO / SWCLK / GND),nRST 未接** → 能力边界见 §0,实测记录见 §5。
> 文中标注 ⓞ 的为"官方帮助/文档说法"与"本机实测"不一致处的更正。
---
## 0. 本机接线与能力边界(先读)
当前板(V0.1;09/19 上板实测时为 V2 板,接线相同)↔ ST-LINK/V2 只接了 **3 根线**:
| 线 | 目标端 | 探针端 | 状态 |
|---|---|---|---|
| SWDIO | SWD 数据 | SWDIO | ✅ 已接 |
| SWCLK | SWD 时钟 | SWCLK | ✅ 已接 |
| GND | 地 | GND | ✅ 已接 |
| **nRST** | 芯片复位脚 | **RESET** | ❌ **未接** |
由此得到本机能力矩阵:
| 能力 | 本机(3 线) | 说明 |
|---|---|---|
| 软件系统复位(`-Rst`,SYSRESETREQ) | ✅ | **本机"重启板子"的唯一方式** |
| 停核/运行/单步/断点(`-Halt`/`-Run`/`-Step`/`-SetBP`) | ✅ | 调试用 |
| 内存/Flash 读写、擦除、校验(`-r*`/`-w*`/`-P`/`-V`/`-ME`/`-SE`/`-CmpFile`) | ✅ | |
| 不扰连接 / 低功耗唤醒 / 读电压 / 枚举探针(`HOTPLUG`/`LPM`/`-TVolt`/`-List`) | ✅ | |
| nRST 引脚操作(`-HardRst`、`RM=Hrst`) | ❌ | **双重障碍**:① nRST 未接线(无信号可驱动)② v3.5.0.0 CLI 拒识 `RM=`(ⓞ,见 §2③) |
| 复位态连接(`UR`) | ❌ | 需要 nRST 接线才能"按住复位连接" |
要点:
- **日常"命令重启板子" = `-c SWD -Rst -Run`(软件系统复位)**。对 STM32F4,SYSRESETREQ 会复位内核 + 几乎所有外设,与 nRST 硬复位的固件级效果等价(差别仅在 nRST 引脚本身不动、调试域保留)——3 线接线场景下这就是复位能力的上限,完全够用。
- **需要 nRST 引脚级操作时**(复位电路/上电时序验证、跑飞后的复位态连接救援)必须补第 4 根线:目标 nRST → 探针 RESET 脚。补线之后注意:本机 v3.5.0.0 CLI 仍不认 `RM=`(ⓞ),届时要走 ST-LINK Utility GUI、升级 ST-LINK Utility(新版 CLI)、或换 J-Link。
- `stlink_flash.py hard` 已内置回退:本机永远回退到软件复位(exit 仍为 0),**不会把脚本跑断**;将来补线 + 升级 CLI 后自动升级为真 nRST 脉冲,无需改脚本。
## 1. 三种"复位"(核心概念)
| 种类 | 触发源 | 复位范围 | CLI 表达 | 本机可用 |
|---|---|---|---|---|
| **硬件复位(nRST)** | 探针驱动目标 nRST 引脚 | 整片冷启动,最接近"重新上电" | `-HardRst [LOW/HIGH/PULSE=<ms>]`(配 `RM=Hrst`) | ❌ nRST 未接线(且 CLI 不支持 `RM=`) |
| **软件系统复位(SYSRESETREQ)** | 调试器写系统复位寄存器 | 内核 + 绝大多数外设(调试域保留) | `-Rst`(默认模式即可) | ✅ **本机唯一复位方式** |
| **内核复位(AirCore/VC)** | 内核复位信号 | 仅内核;**外设保持运行** | `-c ... RM=Crst`(连接时选择) | ⓞ v3.5.0.0 CLI 拒识 `RM=`,本机不可用 |
## 2. 六个核心复位用法
### ① 复位并运行(重启板子,最常用)✅ 本机可用
```bat
ST-LINK_CLI -c SWD -Rst -Run
```
时序:连接(默认连接即停核)→ 系统复位 → 运行 → 板子从 Flash 引导重新跑固件。
这就是"命令控制板子重启",本机 3 线接线完全够用。
### ② 复位并停核(调试/检查用)✅ 本机可用
ⓞ **实测更正**:v3.5.0.0 CLI 下 `-Rst` 之后核是**运行**状态(`-SCore` 回读 "Core is Running."),并不停核。要停核必须显式加 `-Halt`:
```bat
ST-LINK_CLI -c SWD -Rst -Halt
```
实测:停核成功,SP=0x2001E8B8(与向量表首字一致),**PC=0x08004664**——复位后核先运行了一段启动代码再被停住(软件系统复位不保持调试 halt,停点由 `-Halt` 下发时刻决定,不保证是复位向量)。
ⓞ 本机无 nRST 线 + CLI 不支持 `RM=`,**"精确停在复位向量"在本机不可实现**;停核读取命令必须与复位写在**同一命令行**:
```bat
ST-LINK_CLI -c SWD -Rst -Halt -SCore -CoreReg :: 复位停核后读核状态 + 寄存器
ST-LINK_CLI -c SWD -Rst -Halt -R32 0x08000000 4 :: 停核后读向量表前 4 个字
```
ⓞ **一次性连接语义(实测)**:ST-LINK_CLI 是"连接→执行→断开"的一次式进程,**会话结束(断开)时核自动恢复运行**。因此 `stlink_flash.py halt` 单独调用只适合"复位后读状态"场景,断开后板子会继续运行;需要**持续性 halt**(GDB 调试/长时间断点)请走 GDBServer/IDE 路径。
### ③ 硬件复位:nRST 脉冲 ❌ 本机不可用(nRST 未接线)
```bat
:: 仅备查:需 nRST 接线 + 支持 RM= 的 CLI/GUI/J-Link
ST-LINK_CLI -c SWD RM=Hrst -HardRst PULSE=100
```
`PULSE=100` 意为 nRST 拉低 100ms 再释放(整片冷启动,等价于按复位键/重新上电)。
本机不可用的原因(双重障碍):
1. **nRST 线未接**(3 线接线)——探针没有可驱动目标复位脚的信号;
2. ⓞ v3.5.0.0 CLI 拒识 `RM=`:`RM=Hrst/Srst/Crst` 在 4 种语法排列下全部报错
`[RM=Hrst]: Unknown debug protocol or option!`(exit=1)——帮助文本与实现不符。
将来若补 nRST 线:ST-LINK GUI 可先做引脚级操作;要 CLI 化则升级 ST-LINK Utility 或换 J-Link。
### ④ nRST 电平保持序列 ❌ 本机不可用(nRST 未接线)
```bat
:: 仅备查:按住复位→释放,用于复位电路验证/上电过程观察
ST-LINK_CLI -c SWD RM=Hrst -HardRst LOW -HardRst HIGH
```
(`-HardRst LOW` 按住、`-HardRst HIGH` 释放;需 nRST 接线 + 支持 `RM=` 的工具。)
### ⑤ 烧写 + 复位 + 运行(完整固件更新)✅ 本机可用
```bat
ST-LINK_CLI -c SWD -P "MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex" -Rst -Run
```
- ⓞ **`.hex` 直接支持已实测**:1MB Intel HEX 编程耗时 **6.5s**,`Programming Complete`(远快于 UV4/CMSIS-DAP 路径);`.bin` 同理(`fromelf --bin` 可转,ARMCC 自带 `C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe`);`.axf` 直读未测,无需。
- 加 `-V` 编程后校验、`-Q` 静默。
- 与 `stlink_flash.py flash` 同源(都走 ST-LINK_CLI)。原 `download.bat`(`UV4 -f` 走 CMSIS-DAP)与 `reset.bat` **均已删除**(2026-10-10),烧录/复位/回读统一由 `stlink-flash` skill 承载。
- ⓞ **静默失败模式(2026-09-20 实测,代价最大的坑)**:省略结尾 `-Rst -Run` 的裸 `-c SWD -P <文件>` 仍报 `Memory programmed in 1s 906ms / Programming Complete`,但芯片 flash **不变**(回读向量表 = 旧镜像)——目标核处于死循环/异常状态时,"Normal 连接、不复位"的会话写入不落地;同文件改用完整 `-P <文件> -Rst -Run` 即正常落地(6.5s / 1MB)。**铁律:任何编程命令必须以 `-Rst -Run` 收尾;任何烧录之后必须 `-CmpFile` 全片回读校验**(详见 §7)。
### ⑥ 不扰目标连接(HOTPLUG,运行中板子的只读检查)✅ 本机可用
```bat
ST-LINK_CLI -c SWD HOTPLUG -SCore :: 核状态(Running/Halted、PC)
ST-LINK_CLI -c SWD HOTPLUG -R32 0x08000000 4 :: 读运行中芯片的 Flash
ST-LINK_CLI -c SWD HOTPLUG -TVolt :: 读 VDD
ST-LINK_CLI -c SWD HOTPLUG -Dump 20000000 1000000 dump.bin :: 转储 SRAM
```
`HOTPLUG` = 连接时**不 halt、不 reset**——对正在跑的板子做无副作用检查。
## 3. `-c` 连接参数全表
```
-c [ID=<id>/SN=<sn>] [JTAG/SWD [SWCLK=<f>]] [UR/HOTPLUG] [LPM] [RM=Hrst/Srst/Crst]
```
| 参数 | 含义 | 本机状态 |
|---|---|---|
| `SWD` / `JTAG` | 调试接口(本工程用 SWD;SWD 只需 2 根信号线,JTAG 需 4 根) | ✅ 默认选 SWD |
| `SWCLK=<f>` | SWD 时钟。⚠️ 帮助文字标"KHz"但官方示例写 `SWCLK=5`(若按 KHz 则慢到不可用),两处自相矛盾 | ⓞ 先不传,用探针默认(本机实测自动协商到 4000K);连接慢/失败再小步试验 |
| `UR` | 在复位状态下连接(nRST 拉低期间完成连接) | ❌ 需 nRST 接线(本机未接) |
| `HOTPLUG` | 连接时不 halt、不 reset | ✅ |
| `LPM` | 低功耗模式下进入调试(先唤醒目标) | ✅ |
| `RM=Hrst/Srst/Crst` | 本次会话的复位机制:nRST 引脚 / 软件系统复位 / 仅内核 | ⓞ v3.5.0.0 全部拒识,勿用 |
| `ID=<0..9>` / `SN=<串号>` | 多探针选择(默认 ID=0) | ✅ 一机多板时用于指定 |
示例(多板场景):`-c SN=0B250D12A218303030303032 SWD LPM`
## 4. 核状态 / 内存 / Flash 辅助命令(复位前后验证链)
| 命令 | 作用 |
|---|---|
| `-SCore` | 核状态:Running/Halted + 程序计数器(复位后核对"停在哪") |
| `-CoreReg` | 读核心寄存器组(SP/PC/xPSR 等) |
| `-Halt` / `-Run [addr]` | 停核 / 运行(可从指定地址开始) |
| `-Step` | 单步 |
| `-SetBP <address>` / `-ClrBP` | 设/清断点 |
| `-r8/-r16/-r32 <地址> <数量>` | 读内存(地址、数量均为**十六进制**) |
| `-w8/-w32/-w64 <地址> <数据>` | 写内存 |
| `-Dump <地址> <大小> <文件>` | 内存转储到文件 |
| `-CmpFile <文件> [地址]` | 全片 Flash 与文件逐字节比对(2026-09-20 实测:`No difference found` = 真写入;v3.5.0.0 无 `-Cksum` 命令)。⚠ **连接即复位目标**(2026-10-10 实测:比对瞬间板子重打一遍开机日志)→ 自动化里必须排在日志采集之后 |
| `-P <文件> [地址] [ske] [skpv]` | 编程(ske=跳擦除 skpv=跳校验) |
| `-V [after_programming]` | 校验 |
| `-ME` / `-SE <扇区>` | 全片擦除 / 扇区擦除(⚠️ RDP≠0 时 `-ME` 会被拒) |
| `-TVolt` | 目标 VDD 电压(⚠️ 需 VDD 感应脚接至目标;本机台架 3 线连接(SWDIO/SWCLK/GND)此脚未接,读数无效,供电判据以万用表实测为准) |
| `-Q` / `-Log` / `-NoPrompt` | 静默 / 生成跟踪日志 / 免交互确认 |
| `-List` | 枚举所有已连接探针(固件版本 + 串号) |
退出码:`0`=成功;`2`=未检测到探针(本机实测);其他非零=失败。
## 5. 本工程实战组合
**A. 只重启不烧录**(固件没变,重新验证启动/串口行为;配合 serial_tool)
```powershell
& '.venv\Scripts\python.exe' .dsh/skills/serial-assistant/scripts/serial_tool.py open
& '.venv\Scripts\python.exe' .dsh/skills/serial-assistant/scripts/serial_tool.py clear
& '.venv\Scripts\python.exe' .dsh\skills\stlink-flash\scripts\stlink_flash.py reset # = ST-LINK_CLI -c SWD -Rst -Run -Q
# 等待开机完成后直接读日志文件校验标记:
Get-Content .dsh\skills\serial-assistant\scripts\state\serial.log -Tail 100
```
顺序关键:**先开串口清日志,再复位**,否则错过开机头几行(与 `run_boot_test.py` 的"采集先于烧录"原则一致)。
ⓞ 实测补充三条:
1. **改过 `.serialtest/config.json` 端口后必须重启 daemon**:daemon 在启动时缓存配置,改端口后 `close` + 杀旧进程再 `open`,否则一直按旧端口报 `port not found`;
2. **(已修,2026-10-10)旧版 `wait-idle` 在复位突发期会报 `daemon unresponsive after auto-start: timed out`**:CLI 把**超时**误判成"daemon 不可达",顺手拉起一个绑不上 HTTP 口的实例再把命令撞一次超时(数据其实已落盘)。现 CLI 超时按 `--max-ms` 自动推导、超时只快速失败不再误拉起实例;
3. **日志校验**:`.dsh/skills/serial-assistant/scripts/state/serial.log` 用 Read/Grep 直接查最直观;`serial_tool.py log --grep <标记>` 现已可作判定依据(2026-10-10 修:旧实现先 `--tail`(默认 50)后 grep,开机标记必然查不到——这就是当年"实测 0 命中、语义存疑"的真根因)。
**B. 完整烧写 + 运行**:`stlink-flash` skill 的 `stlink_flash.py flash [xxx.hex]`(= `-c SWD -P <hex> -Rst -Run`;09/19 实测 1MB ≈ 6.5s,09/20 复测 6.47s + 全片 `-CmpFile` 逐字节一致)。**2026-10-10 起 CLI 路径即唯一烧录路径**——原 `download.bat` 的 `UV4 -f` 与 `reset.bat` 均已删除。
**B2. 回读校验**:`stlink_flash.py cmp [xxx.hex]`(= `-c SWD -CmpFile <hex> 0x08000000`,2026-10-10 加;默认对最新构建 hex)。判定看输出行首的 `No difference found`(`This file is already downloaded` 是同义提示)。⚠ **连接即复位目标**:实测比对瞬间板子重打一遍开机日志 → 在自动化闭环里回读必须排在**日志采集之后**(`run_boot_test.py` 已按此顺序内置)。
**C. 救援**(板子起不来 / 疑似 Flash 问题)——本机 3 线接线的可行子集:
```bat
ST-LINK_CLI -c SWD LPM :: 若目标休眠/连不上,先试低功耗唤醒
ST-LINK_CLI -c SWD -ME :: 全片擦除(前提 RDP=0;RDP≠0 需先 -rOB 确认,RDP 解锁是专门流程)
ST-LINK_CLI -c SWD -P "MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex" -Rst -Run
```
ⓞ 注意:`UR`(复位态连接)在本机不可用(nRST 未接线)——跑飞救援能力受限,能做的只有"正常连接 + LPM + 全擦重烧";若板子连 SWD 都握不上手,需先补 nRST 线。
**D. 运行中检查**:`-c SWD HOTPLUG -SCore` / `-R32` / `-TVolt`(⚠️ 本机 3 线连接下读数无效,见命令表注记)/ `-Dump`。
## 6. `stlink-flash` skill 的复位/烧录子命令(2026-09-19 上板验证;原 `MDK-ARM\reset.bat` 已于 2026-10-10 删除并全并入本 skill)
用法(全部分支 exit=0 实测通过):
| 调用 | 行为 | 本机实际效果 |
|---|---|---|
| `stlink_flash.py reset` | `-c SWD -Rst -Run` | ✅ 软件系统复位 + 运行(重启板子) |
| `stlink_flash.py hard` | `-c SWD RM=Hrst -HardRst PULSE=100`,被拒则回退 | ⓞ 本机 `RM=` 被拒 → **自动回退软件复位**(打印 RESET_NOTE,exit=0);补 nRST 线 + 升级 CLI 后自动升级为真 nRST 脉冲 |
| `stlink_flash.py halt` | `-c SWD -Rst -Halt` | ✅ 复位停核(一次性会话,读状态须同命令行附加;断开后核自动恢复运行) |
| `stlink_flash.py run` | `-c SWD -Run` | ✅ 恢复被停核的目标 |
| `stlink_flash.py list` | `-List` | ✅ 枚举探针 |
| `stlink_flash.py flash [F]` | `-c SWD -P F -Rst -Run`(F 缺省 = 档案 `hex` = `MDK-ARM\STM32F407-Demo\STM32F407-Demo.hex`) | ✅ 烧写 + 复位 + 运行(1MB ≈ 6.5s;2026-09-20 复测验证,见 §2 ⑤) |
| `stlink_flash.py cmp [F]` | `-c SWD -CmpFile F 0x08000000` | ✅ 全片回读比对(`No difference found` = 真写入) |
退出码:`0`=OK;`1`=探针/目标错误;`2`=CLI 未找到/无效;`3`=用法错误。
注意:档案(`.serialtest/config.json`)解析、`DTU_STLINK_CLI` 工具路径解析(未设回退 PATH;显式设了但无效 = 硬报错)、镜像缺省值均内置于脚本;`stlink_flash.py` 为纯标准库 Python,无原 bat 的引号/CRLF 行尾坑。
## 7. 故障排查速查
| 现象 | 排查 |
|---|---|
| `No ST-LINK detected!`(exit=2) | 探针没插/USB 未枚举/驱动问题。本机已装 STLinkWinUSB 驱动;`stlink_flash.py list` 复核;换 USB 口(避免前端_hub) |
| `[RM=xxx]: Unknown debug protocol or option!`(exit=1) | ⓞ v3.5.0.0 CLI 不支持 `RM=`(帮助与实现不符);**且本机 nRST 未接线**——直接用软件复位 `-Rst`(`stlink_flash.py reset`) |
| 连接失败 | 目标供电;SWDIO/SWCLK 接线(本机 3 线,勿依赖 nRST 辅助);芯片休眠 → 加 `LPM`;看门狗反复复位 → 提高连接速度(本机无 `UR` 可用);RDP 被锁 → 只能读有限信息 |
| 复位后程序没跑 | 读复位向量确认 Flash 有效:`-R32 0x08000000 1`(应指向 0x08xxxxxx,`0xFFFFFFFF`=空片);查 BOOT0 状态;看串口是否有输出 |
| 复位后卡死(串口日志中断在半路) | ⓞ 2026-09-19 实测案例:`-c SWD HOTPLUG -SCore -CoreReg` 读 PC/寄存器定位卡点(案例:V2 引脚固件卡在 0x08000FA0 启动循环,见 §5)——**先定位再下结论**,勿直接怀疑探针 |
| 烧录报成功但芯片行为不变 | ⓞ **先怀疑静默写入失败**(2026-09-20 实测):命令缺 `-Rst -Run`(裸 `-P` 在目标核死循环/异常时不落地)或选项字节异常(RDP 字节非法,见 §3 与 §7)。处置:`-CmpFile` 全片比对/回读向量表首字 → 用 `stlink_flash.py flash` 重烧 → 再 `-CmpFile` 复核;勿直接怀疑探针/接线 |
| `daemon unresponsive after auto-start`(serial_tool) | ⓞ 复位后几秒内 daemon 忙于排空日志突发;稍等后直接读 `state/serial.log` 文件验证,勿反复重试 |
| `port not found: COMx (available: COMy)`(serial_tool) | ⓞ 端口重新枚举(板子重插常见):改 `.serialtest/config.json` → **kill 旧 daemon 进程** → 重新 `open`(daemon 启动时缓存配置,不重启不生效) |
| `log --grep` 查不到明明存在的标记 | ⓞ 该子命令实测不可靠(0 命中);改用直接读/`Select-String` 查 `state/serial.log` |
| SWD 通信不稳 | 不传 `SWCLK` 用默认时钟(本机实测 4MHz);检查长线/夹子接触 |
| 误改 option bytes | `-rOB` 读回现状;`-OB RDP=0` 等回写后需再复位生效;**RDP=2 会锁死调试+全片擦除,操作前务必确认** |
| 多板混淆 | `stlink_flash.py list` 拿串号,`-c SN=<串号>` 指定 |