fix(bench): ST-LINK_CLI 子进程加 stdin=DEVNULL,闭环不再挂死

- stlink_flash.py::run_cli 与 run_boot_test.py::_run_cmd 调 subprocess.run
  时未给 stdin=DEVNULL:ST-LINK_CLI 编程完成后停在 "run application to
  exit" 等 stdin,stdin 是未关闭管道即永久挂起(编程其实已成功、板子已
  复位运行)→ 闭环误判 flash rc=-1(180s 超时)
- 归档 ADC 1kHz 台架证据 boot_log_data/20261010_prod_adc_tim6_boot_log.txt
  并在 README 清单登记
- 同步 ADC采样节拍设计说明(状态→通过台架验收、新增 §7.1 实测)
  与 继电保护功能复现规划 L1-1
This commit is contained in:
2026-10-10 15:46:21 +08:00
parent 970e574433
commit b80f59cc5d
6 changed files with 112 additions and 7 deletions
@@ -1,7 +1,9 @@
# ADC 采样节拍设计说明(1 kHz 硬件定时器触发)
> **状态**:**已实现(2026-10-10)**——TIM6 更新中断(1 kHz)触发已落地(`Src/main.c` 回调 +
> `app_main.c` 启动 + `adc_task.c` 退化为纯消费者),`@build` 0 错 0 警;**台架 `@test` 验收(§7)待做**。
> **状态**:**已实现并通过台架验收(2026-10-10)**——TIM6 更新中断(1 kHz)触发已落地
> (`Src/main.c` 回调 + `app_main.c` 启动 + `adc_task.c` 退化为纯消费者),`@build` 0 错 0 警;
> 台架 `@test` **PASS**(`frame_seq` 每 10 s 精确 +10000 = 1000.0 Hz、`frst_err=0`、回读一致;
> 实测见 §7.1)。
> **上位需求**:`docs/算法/继电保护功能复现规划.md` §3.2 L1-1(周期 CONVST 重触发 1000 Hz,
> 与保护节拍同源)。**驱动契约**:`Drivers/BSP/TPAFE5160/README.md`。
> **背景**:B1(2026-10-10)已把 `adc_task` 由空桩改为真实消费者,但采样节拍是
@@ -181,6 +183,26 @@ t=1000 µs 下一个 TIM6 更新事件
| 6 | 开机日志时间戳正常(TIM7 时基未坏) | 串口日志 |
| 7 | 无 HardFault / `[ERR]` / 看门狗复位 | `@test` Forbidden 判定 |
### 7.1 台架实测结果(2026-10-10,`@test` PASS)
证据:`docs/测试说明/boot_log_data/20261010_prod_adc_tim6_boot_log.txt`(`fw build: Oct 10 2026 15:21:20`)。
| # | 判据 | 实测 |
|---|---|---|
| 1 | `@build` 0 错 0 警 + 镜像时效 | ✅ 0 错 0 警;无源文件新于 hex |
| 2 | CONVST 1.000 kHz | ✅ 以 `frame_seq` 速率替代(无示波器):`seq` 10005→20005→30005,**每 10 s 精确 +10000 = 1000.0 Hz** |
| 3 | BUSY 每周期一脉冲 | ✅ 以 `frst_err=0` 替代:全程无"FRSTDATA 无跳变"帧(BUSY EXTI 每周期都在读帧) |
| 4 | `frame_seq` 严格递增 | ✅ 见 #2,严格单调 |
| 5 | `frst_err=0`、`idle` 基本为 0 | ✅ `frst_err=0`;⚠ `idle` 每 10 s +5(≈0.05%,见下) |
| 6 | 开机时间戳正常 | ✅ 日志带墙钟时间戳,`net init: OK` 在 +530 ms |
| 7 | 无 HardFault / `[ERR]` / 看门狗复位 | ✅ 零 `[ERR]`/HardFault;`reset cause:` 仅 1 次(调试器软复位) |
**关于 `idle`(不是缺陷,是轮询消费的固有抖动)**:生产端(TIM6)与消费端(`adcTask` 1 ms 轮询)
同为 1000 Hz(TIM6 与 FreeRTOS tick 源 TIM7 参数一致,均 84 MHz/84/1000),但二者无显式同步 →
偶发 ±1 帧的相位抖动:每 10 s 约 5 次"两次轮询落在同一生产间隔"(`idle` +5)配 5 次"一次轮询跨两个
生产间隔"(`frames` 少 5,即 9995/10000 ≈ 99.95% 取数)。要彻底消除需把消费端改为**帧就绪事件驱动**
(在 BUSY EXTI 读帧完成时通知 `adcTask`)——与 §8 等周波调频的消费端改造是同一件事,留待该阶段一并做。
---
## 8. 后续:等周波调频(不在本项范围)
@@ -201,3 +223,4 @@ t=1000 µs 下一个 TIM6 更新事件
|---|---|---|
| 2026-10-10 | 建立本文档 | B1(ADC 采集链路)遗留项"精确 1 kHz 硬件定时器触发"的规划:方案选型(A/B)、CubeMX 配置规格、代码改造清单、时序与优先级分析、风险与验收判据、等周波调频预留 |
| 2026-10-10 | **实现(方案 A)** | CubeMX 加 TIM6(PSC=83 / ARR=999 / ARR 预装载 / NVIC 抢占优先级 6);`Src/main.c` 回调加 TIM6 分支触发 CONVST;`app_main.c` 用 `HAL_TIM_Base_Start_IT(&htim6)` 启动节拍;`adc_task.c` 退化为纯消费者。`@build` 0 错 0 警;台架 `@test` 验收待做 |
| 2026-10-10 | **台架 `@test` 验收 PASS** | 真机闭环:`seq` 10005→20005→30005(每 10 s +10000 = 1000.0 Hz)、`frst_err=0`、`idle` 每 10 s +5(0.05%,轮询抖动)、回读 `No difference found`、零 `[ERR]`/HardFault、`reset cause` 仅 1 次。证据 `boot_log_data/20261010_prod_adc_tim6_boot_log.txt` |
@@ -0,0 +1,72 @@
[+0ms] [----/--/-- --:--:--][APP] boot: syslog init OK
[+0ms] [----/--/-- --:--:--][APP] fw build: Oct 10 2026 15:21:20
[+10ms] [----/--/-- --:--:--][APP] reset cause: software (NVIC_SystemReset) (CSR=0x14000000)
[+20ms] PREVRUN seg=2 seq=1910016719 t=9345
[+20ms] TICKRUN uw=9385 n=9385 duw=40
[+31ms] [----/--/-- --:--:--][RTC] sd2506_init: OK
[+31ms] [----/--/-- --:--:--][APP] SD2506 init: OK (ret=0)
[+31ms] [2026-10-10 07:44:17][CLK] sys_clock_init: RTC initial time 2026-10-10 07:44:17
[+42ms] [2026-10-10 07:44:17][CLK] sys_clock_init: wall clock base = unix 1791618257, base_tick=136
[+52ms] [2026-10-10 07:44:17][APP] RS485 init: OK (UART4, DE=PA15)
[+73ms] [2026-10-10 07:44:17][NAND] Resetting NAND...
[+83ms] [2026-10-10 07:44:17][NAND] Reading NAND ID...
[+83ms] [2026-10-10 07:44:17][NAND] NAND ID: MID=0xC8, DID=0x52
[+96ms] [2026-10-10 07:44:17][NAND] Scanning bad blocks...
[+225ms] [2026-10-10 07:44:17][NAND] BBT scan: 0 bad blocks found
[+225ms] [2026-10-10 07:44:17][NAND] Enabling ECC...
[+235ms] [2026-10-10 07:44:17][NAND] Unlocking block protection...
[+246ms] [2026-10-10 07:44:17][NAND] Locating BBT pool...
[+246ms] [2026-10-10 07:44:17][NAND] Loading persisted BBT...
[+258ms] [2026-10-10 07:44:17][NAND] NAND init OK
[+258ms] [2026-10-10 07:44:17][APP] NAND init: OK
[+258ms] [2026-10-10 07:44:17][ADC] Init OK
[+258ms] [2026-10-10 07:44:17][APP] ADC init: OK
[+269ms] [2026-10-10 07:44:17][APP] SD2506 ID: 2512153425482405
[+279ms] [2026-10-10 07:44:17][APP] SD2506 time: 2026-10-10 07:44:17 (week 2)
[+279ms] [2026-10-10 07:44:17][APP] SD2506 temp: 29 C
[+279ms] [2026-10-10 07:44:17][APP] SD2506 battery: 3.12 V
[+290ms] [2026-10-10 07:44:17][APP] App init OK
[+300ms] [2026-10-10 07:44:17][NAND_FTL] Initializing NAND FTL...
[+321ms] [2026-10-10 07:44:17][NAND_FTL] Map resumed: 14094/97504 sectors used
[+332ms] [2026-10-10 07:44:17][NAND_FTL] Map head=108784 tail=86214 epoch=1
[+332ms] [2026-10-10 07:44:17][NAND_FTL] NAND FTL ready (capacity: 97504 pages = 190 MB)
[+415ms] [2026-10-10 07:44:17] [FS] FATFS mounted
[+457ms] [2026-10-10 07:44:17][SYSLOG] runlog boot entry: reboot
[+467ms] [2026-10-10 07:44:17][CFG] register: section 'network' (4 keys)
[+478ms] [2026-10-10 07:44:17][CFG] load: OK (523B, heap free 15240B)
[+478ms] [2026-10-10 07:44:17][NET_CFG] load: OK ip=192.168.1.100
[+509ms] [2026-10-10 07:44:17][NET_TASK] === Network Init ===
[+520ms] [2026-10-10 07:44:17][ADC_TASK] first frame: UA=11428 UN=11454 IA=11451
[+530ms] [2026-10-10 07:44:17][NET_TASK] net init: OK
[+530ms] [2026-10-10 07:44:17][NET_TASK] MAC: 3C:AB:72:53:2B:12
[+541ms] [2026-10-10 07:44:17][NET_TASK] IP_INF: IP=192.168.1.100 GW=192.168.1.1 MASK=255.255.255.0
[+551ms] MISS start snap=0x00000067 req=0x00000077 t=649
[+551ms] [2026-10-10 07:44:17][WD] [WD] armed: timeout ~2498ms (worst ~1701ms), miss_tol=800ms
[+562ms] [2026-10-10 07:44:17][UI_TASK] UI task: started, wait net ready
[+2533ms] [2026-10-10 07:44:19][NET_TASK] PHY: 100M FULL
[+2544ms] [2026-10-10 07:44:19][NET_TASK] netTask: started (single-socket mode)
[+2576ms] [2026-10-10 07:44:19] [FTP] waiting for connection...
[+2617ms] [2026-10-10 07:44:19][TIME_SYNC] time_sync: TCP listen on :8888 (sock=1)
[+2627ms] [2026-10-10 07:44:19][UI_TASK] UI task: net ready, init port
[+2627ms] [2026-10-10 07:44:19][UI_TASK] UI task: ui_port_init enter
[+2638ms] [2026-10-10 07:44:19][UI_PORT] theme: mono dark_bg=true applied
[+2638ms] [2026-10-10 07:44:19][UI_TASK] UI port init: OK
[+2648ms] [2026-10-10 07:44:19][UI_TASK] UI task: ui_menu_init enter
[+2648ms] [2026-10-10 07:44:19][UI_MENU] menu build start: total=39408 free=36572 big=36572
[+2659ms] [2026-10-10 07:44:19][UI_MENU_VIEW] view init: root frame w=66 h=107
[+2669ms] [2026-10-10 07:44:19][UI_MENU] menu build done: total=39292 free=35708 big=35696 used=3584
[+2679ms] [2026-10-10 07:44:19][UI_TASK] UI menu init: OK
[+2679ms] [2026-10-10 07:44:19][UI_STANDBY] standby: ready (idle=60000ms)
[+2690ms] MISS start snap=0x00000067 req=0x00000077 t=2789
[+2690ms] [2026-10-10 07:44:19][UI_TASK] UI standby: ready (idle=60s)
[+2742ms] [2026-10-10 07:44:19][UI_TASK] UI net sink: started (port 7003)
[+5294ms] [2026-10-10 07:44:22] [STACK] default peak_used=2164/4096 free_min=1932 (47%)
[+5305ms] [2026-10-10 07:44:22] [STACK] net peak_used=920/3840 free_min=2920 (76%)
[+5305ms] [2026-10-10 07:44:22] [STACK] ftp peak_used=740/4096 free_min=3356 (81%)
[+5315ms] [2026-10-10 07:44:22] [STACK] ui peak_used=4016/16384 free_min=12368 (75%)
[+5326ms] [2026-10-10 07:44:22] [STACK] timesync peak_used=616/2048 free_min=1432 (69%)
[+5326ms] [2026-10-10 07:44:22] [STACK] adc peak_used=528/2048 free_min=1520 (74%)
[+5336ms] [2026-10-10 07:44:22] [STACK] heap free=15088 min_ever=7152
[+10297ms] [2026-10-10 07:44:27][ADC_TASK] frames=9961 idle=40 seq=10005 frst_err=0
[+20294ms] [2026-10-10 07:44:37][ADC_TASK] frames=19956 idle=45 seq=20005 frst_err=0
[+30292ms] [2026-10-10 07:44:47][ADC_TASK] frames=29951 idle=50 seq=30005 frst_err=0
+1 -1
View File
@@ -25,7 +25,7 @@
| 日期 | 构建 / 负载 | 关键 `[STACK]` 水位 | 文件 |
|---|---|---|---|
| — | — | — | (待台架窗口补齐) |
| 2026-10-10 | `prod_adc_tim6` / 开机 + 30 s 空载 | `adc` 528/2048(74%);`default` 2164/4096(47%);heap free=15088 min_ever=7152 | `20261010_prod_adc_tim6_boot_log.txt` |
## 4. 关联
@@ -238,7 +238,7 @@
| # | 功能点 | 关键参数 | 完成判据 | 状态 |
| --- | --- | --- | --- | --- |
| L1-1 | 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | ✅ 2026-10-10:**TIM6 更新中断(1 kHz)硬件触发**(ISR 内 `tpafe5160_start_conv_irq()`;方案 A,零引脚/零驱动改动);B1 阶段已台架确认 `frame_seq` 严格 1000 Hz 递增 |
| L1-1 | 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | ✅ 2026-10-10:**TIM6 更新中断(1 kHz)硬件触发**(ISR 内 `tpafe5160_start_conv_irq()`;方案 A,零引脚/零驱动改动);台架 `@test` PASS——`seq` 每 10 s 精确 +10000 = 1000.0 Hz、`frst_err=0`(证据 `boot_log_data/20261010_prod_adc_tim6_boot_log.txt`) |
| L1-2 | TPAFE 快照消费 | 8 通道 / 帧 | `adc_task` 每拍调 `tpafe5160_snapshot()`,返回 1/0/-1 有处理 | ✅ B1 已实现并 `@test` 闭环(`adc_task.c`;台架 `idle=0`、`frst_err=0`) |
| L1-3 | STM32 ADC1 启动与扫描 | 9 通道、144 cycles、软件触发 | 全库出现 `HAL_ADC_Start`;9 通道码值随注入变化 | ⬜ |
| L1-4 | 通道语义映射 | 见 `docs/硬件平台/ADC通道映射说明.md`(**按语义取数,不写死下标**) | `UA→buf[6]`、`UN→buf[5]`、`IA→buf[2]`;STM32 侧 `UB→ADC_CHANNEL_14` | ⬜ |