N-19 FTP 鉴权:
- lftpd_auth(USER/PASS 状态机 + 连续5次失败锁60s)+ SHA-256
(user||pwd) 口令哈希;config.ini [ftp] 段 user/pwd_hash/write,
出厂 admin/admin 在用有启动告警;lftpd_log.c 删除并入 lftpd_auth
- ftp_cfg 配置读写;台架 ftp_auth_bench.py 13/13
N-30 / Trap 25(CH395F_Trap_Records.md 四次定案全记录):
- 修复1 closed-with-data accept:客户端发完正常 FIN 后芯片按
FUN_PARA(0x09) §5.52② 保留 Socket+RX 缓冲,旧代码把 CLOSED 一律
relisten 自毁缓冲 → STOR 必挂 425;改为接受"已关但可读"连接排空
- 修复2 丢 CONNECT 中断探针 net_lost_connect_probe + last_peer_port
幽灵甄别(拆链窗口握手完成但中断丢失,双信源去抖补 accept)
- 修复3 send_list/send_nlst 批量单发:背靠背 ~60B 小段毒化芯片 TX
(芯片报 SEND_OK 但对端全丢),整份目录一次性写入
- 证伪存档:固定沉降/Socket 轮换冷却/listen 门控(台架 v7 矩阵)
- 台架工具 test/board/ch395f_reuse_bench.{c,h} + host 脚本存档
(不注册编译;实验分支 n30-chip-bench 保留)
N-20:Error_Handler 死循环降级(记录+复位路径)
N-23:scripts/check_registration.py 双端注册反向校验(pre-commit)
N-26:GD5F NAND 直 DMA 调用方缓冲窗口断言
验证:BUILD_OK 0/0;ftp_regression 连跑 4 轮 11/11(修复前
LIST#4/#7 100% 挂、STOR#2 曾 100% 425);ftp_auth_bench 13/13;
@test 启动标记 PASS;ci_local L0+L0.5 全过;doc-links 通过。
登记簿 N-30 已销项。
18 KiB
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,SN0B250D12A218303030303032;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. 六个核心复位用法
① 复位并运行(重启板子,最常用)✅ 本机可用
ST-LINK_CLI -c SWD -Rst -Run
时序:连接(默认连接即停核)→ 系统复位 → 运行 → 板子从 Flash 引导重新跑固件。 这就是"命令控制板子重启",本机 3 线接线完全够用。
② 复位并停核(调试/检查用)✅ 本机可用
ⓞ 实测更正:v3.5.0.0 CLI 下 -Rst 之后核是运行状态(-SCore 回读 "Core is Running."),并不停核。要停核必须显式加 -Halt:
ST-LINK_CLI -c SWD -Rst -Halt
实测:停核成功,SP=0x2001E8B8(与向量表首字一致),PC=0x08004664——复位后核先运行了一段启动代码再被停住(软件系统复位不保持调试 halt,停点由 -Halt 下发时刻决定,不保证是复位向量)。
ⓞ 本机无 nRST 线 + CLI 不支持 RM=,"精确停在复位向量"在本机不可实现;停核读取命令必须与复位写在同一命令行:
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 未接线)
:: 仅备查:需 nRST 接线 + 支持 RM= 的 CLI/GUI/J-Link
ST-LINK_CLI -c SWD RM=Hrst -HardRst PULSE=100
PULSE=100 意为 nRST 拉低 100ms 再释放(整片冷启动,等价于按复位键/重新上电)。
本机不可用的原因(双重障碍):
- nRST 线未接(3 线接线)——探针没有可驱动目标复位脚的信号;
- ⓞ 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 未接线)
:: 仅备查:按住复位→释放,用于复位电路验证/上电过程观察
ST-LINK_CLI -c SWD RM=Hrst -HardRst LOW -HardRst HIGH
(-HardRst LOW 按住、-HardRst HIGH 释放;需 nRST 接线 + 支持 RM= 的工具。)
⑤ 烧写 + 复位 + 运行(完整固件更新)✅ 本机可用
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-flashskill 承载。 - ⓞ 静默失败模式(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,运行中板子的只读检查)✅ 本机可用
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)
& '.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 的"采集先于烧录"原则一致)。
ⓞ 实测补充三条:
- 改过
.serialtest/config.json端口后必须重启 daemon:daemon 在启动时缓存配置,改端口后close+ 杀旧进程再open,否则一直按旧端口报port not found; - (已修,2026-10-10)旧版
wait-idle在复位突发期会报daemon unresponsive after auto-start: timed out:CLI 把超时误判成"daemon 不可达",顺手拉起一个绑不上 HTTP 口的实例再把命令撞一次超时(数据其实已落盘)。现 CLI 超时按--max-ms自动推导、超时只快速失败不再误拉起实例; - 日志校验:
.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 线接线的可行子集:
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=<串号> 指定 |