L1-6 采样有效性校验:adc_health 判定层 + 告警编排 + 31 用例单测 + 台架闭环

新增 App/algo/adc_health.c/h(纯逻辑判定层,零平台依赖免桩单测):
- 静默:两侧帧序号连续 >=100ms 无前进(电平位可自愈,flags() 为 L5-4 闭锁预留)
- 丢帧:TPAFE 序号一次前进 >1 计 tgap(与 STM32 侧 adc1_gap 对称,边沿事件)
- 单调性:序号倒退锁存位;tick/计数差值法 (int32_t)(a-b) 回绕安全
- 错误增量:FRSTDATA / HAL 错误 / STM32 停摆计数增量,事件位与锁存位编号对齐,
  消费者按位图做"每类每次开机留痕一次"编排

adc_task.c v2.9 告警编排(判定与编排分离):严重事件/电平上升沿 DBG_ERROR +
SYSLOG_SELFTEST(每类每次开机一次防刷屏),下降沿 DBG_INFO 恢复;gap 不告警
(消费者超拍是已知现象,告警会淹没真故障);心跳行增 tgap 观测字段。

主机单测 test/host/adc_health/ 31 用例全绿(100ms 门限两侧 / 边沿语义 /
倒退锁存 / tick 回绕 / NULL 守卫 / init 幂等),登记 adc-health-unit-test 钩子。

台架 @test PASS:零 [ERR](健康不误报)、tgap=1->2 与 adc1_gap 同步可见、
frames 1000.0 Hz;证据 boot_log_data/20261011_prod_adc_health_boot_log.txt。

抬栈:adc_health_report->syslog_post 控制台回显尾使 adcTask 静态最坏链
832->1080 B(512 words 余 968 B < 1024 B ISR 底线)-> 512->640 words,
复测余 1480 B / 57%,堆 min_ever 7152->6640 B(-512 B 符合预算)。
AGENTS/README 任务表、RAM 方案 §2.3、规划文档 §3.1 L1-6 已同步置完成。
This commit is contained in:
2026-10-11 01:28:20 +08:00
parent 6c8f82ec54
commit 13a4e61c27
15 changed files with 1035 additions and 27 deletions
@@ -36,10 +36,10 @@
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
| 区域 | 用量 | 容量 | 占比 |
|---|---|---|---|
| ER_IROM1 | 273,860 B (267.44 KB) | 1,048,576 B (1024 KB) | 26.1% |
| RW_IRAM1 | 91,488 B (89.34 KB) | 131,072 B (128 KB) | 69.8% |
| ER_IROM1 | 274,728 B (268.29 KB) | 1,048,576 B (1024 KB) | 26.2% |
| RW_IRAM1 | 91,544 B (89.40 KB) | 131,072 B (128 KB) | 69.8% |
| RW_CCM | 49,184 B (48.03 KB) | 65,280 B (64 KB) | 75.3% |
| **Flash (ROM 合计)** | **274,684 B (268.2 KB)** | 1,048,576 B (1024 KB) | **26.2%** |
| **Flash (ROM 合计)** | **275,608 B (269.1 KB)** | 1,048,576 B (1024 KB) | **26.3%** |
<!-- MEM_SNAPSHOT:END -->
各区的容量与常量来源:
@@ -95,6 +95,9 @@
> 同日**增列 `adcTask`**(B1:ADC 采集消费者,512 words,静态最坏链 504 B / 余 75%)。
> **2026-10-11 L2 相量层接入后复测**:adcTask 静态 **832 B** / 台架实测峰值 **928 B / 2048(余 54%)**,
> 增量为压环 + `phasor_run()`(`win[20]` 80 B)+ `log_phasors` 日志链;仍高于 1024 B 底线,7 任务全 PASS。
> **同日 L1-6 有效性校验后抬栈 512→640 words**:`adc_health_report`→`syslog_post` 控制台回显尾把静态
> 最坏链推到 **1080 B**(512 words 时余 968 B < 1024 B ISR 底线)→ 抬至 2.5 KB,余 **1480 B / 57%**;
> 堆 `min_ever` 7152 → **6640 B**(-512 B,符合预算)。
> 此前 2026-10-04 的 V5 30 min 重采曾把 defaultTask 推到 **3664B/4096(余量 432B ≈ 10%,登记 S-1)**;
> 2026-10-10 的栈整改(**未抬栈**,见 §4 阶段 0 的"2026-10-10 复测")把它压回 **2152B/4096**,S-1 已销项。
@@ -106,7 +109,7 @@
| testTask | `2048*4` | 8KB | 测试套件(产品构建不创建;存储套件深链需要) | 未创建 / 静态 496 B |
| defaultTask | `1024*4` | 4KB | FatFS 挂载/探针 + 配置引擎 + syslog + 栈水位探针 | 2152 B(余 47%)/ 静态 2776 B |
| timeSyncTask | `512*4` | 2KB | TCP 时间同步 | 616 B(余 69%)/ 静态 **1024 B**(= ISR 底线,无再加深空间) |
| adcTask | `512*4` | 2KB | TPAFE5160 采样消费 + L2 相量(TIM3 1 kHz 节拍 + 快照 + 压环 + 全周傅氏,B1→L2 2026-10-11) | **928 / 2048**(余 1120 B / 54%,台架 `@test` 实测 2026-10-11);静态 832 B |
| adcTask | `640*4` | 2.5KB | TPAFE5160 采样消费 + L2 相量 + L1-6 有效性校验(TIM3 1 kHz 节拍,B1→L2→L1-6 2026-10-11) | **952 / 2560**(余 1608 B / 62%,台架 `@test` 实测 2026-10-11);静态 1080 B |
| idle(内核) | `configMINIMAL_STACK_SIZE=128` | 0.5KB | 空闲 | 未观测(未取句柄) |
| timer(内核) | `configTIMER_TASK_STACK_DEPTH=256` | 1KB | 软定时器 | 未观测 |
@@ -0,0 +1,116 @@
[+0ms] [----/--/-- --:--:--][APP] boot: syslog init OK
[+0ms] [----/--/-- --:--:--][APP] fw build: Oct 11 2026 00:38:20
[+10ms] [----/--/-- --:--:--][APP] reset cause: software (NVIC_SystemReset) (CSR=0x14000000)
[+21ms] PREVRUN seg=2 seq=1914766133 t=1240757
[+21ms] TICKRUN uw=1240801 n=1240801 duw=44
[+21ms] [----/--/-- --:--:--][RTC] sd2506_init: OK
[+31ms] [----/--/-- --:--:--][APP] SD2506 init: OK (ret=0)
[+31ms] [2026-10-10 17:13:03][CLK] sys_clock_init: RTC initial time 2026-10-10 17:13:03
[+42ms] [2026-10-10 17:13:03][CLK] sys_clock_init: wall clock base = unix 1791652383, base_tick=137
[+52ms] [2026-10-10 17:13:03][APP] RS485 init: OK (UART4, DE=PA15)
[+64ms] [2026-10-10 17:13:03][NAND] Resetting NAND...
[+94ms] [2026-10-10 17:13:03][NAND] Reading NAND ID...
[+94ms] [2026-10-10 17:13:03][NAND] NAND ID: MID=0xC8, DID=0x52
[+94ms] [2026-10-10 17:13:03][NAND] Scanning bad blocks...
[+223ms] [2026-10-10 17:13:03][NAND] BBT scan: 0 bad blocks found
[+234ms] [2026-10-10 17:13:03][NAND] Enabling ECC...
[+234ms] [2026-10-10 17:13:03][NAND] Unlocking block protection...
[+244ms] [2026-10-10 17:13:03][NAND] Locating BBT pool...
[+244ms] [2026-10-10 17:13:03][NAND] Loading persisted BBT...
[+255ms] [2026-10-10 17:13:03][NAND] NAND init OK
[+255ms] [2026-10-10 17:13:03][APP] NAND init: OK
[+255ms] [2026-10-10 17:13:03][ADC] Init OK
[+266ms] [2026-10-10 17:13:03][APP] ADC init: OK
[+266ms] [2026-10-10 17:13:03][APP] ADC input layer init: OK
[+266ms] [2026-10-10 17:13:03][APP] phasor layer init: OK (inst=5)
[+276ms] [2026-10-10 17:13:03][APP] SD2506 ID: 2512153425482405
[+287ms] [2026-10-10 17:13:03][APP] SD2506 time: 2026-10-10 17:13:04 (week 2)
[+287ms] [2026-10-10 17:13:03][APP] SD2506 temp: 28 C
[+297ms] [2026-10-10 17:13:03][APP] SD2506 battery: 3.11 V
[+297ms] [2026-10-10 17:13:03][APP] App init OK
[+308ms] [2026-10-10 17:13:03][NAND_FTL] Initializing NAND FTL...
[+339ms] [2026-10-10 17:13:03][NAND_FTL] Map resumed: 14094/97504 sectors used
[+339ms] [2026-10-10 17:13:03][NAND_FTL] Map head=117088 tail=99894 epoch=1
[+349ms] [2026-10-10 17:13:03][NAND_FTL] NAND FTL ready (capacity: 97504 pages = 190 MB)
[+421ms] [2026-10-10 17:13:03] [FS] FATFS mounted
[+473ms] [2026-10-10 17:13:03][SYSLOG] runlog boot entry: power on
[+473ms] [2026-10-10 17:13:03][CFG] register: section 'network' (4 keys)
[+484ms] [2026-10-10 17:13:03][CFG] load: OK (523B, heap free 14728B)
[+494ms] [2026-10-10 17:13:03][NET_CFG] load: OK ip=192.168.1.100
[+546ms] [2026-10-10 17:13:03][ADC_TASK] first: UA=11429 UB=1026 UC=817 UN=11453 IA=11452 IB=976 IC=1017 IN=865 T=940
[+556ms] [2026-10-10 17:13:03][ADC_TASK] phasor(first) C01-IA-F1: Re=0 Im=0 rms=0 (x0.1)
[+566ms] [2026-10-10 17:13:03][ADC_TASK] phasor(first) C02-UA-F1: Re=3 Im=0 rms=3 (x0.1)
[+566ms] [2026-10-10 17:13:03][ADC_TASK] phasor(first) C03-UN-F1: Re=0 Im=0 rms=1 (x0.1)
[+577ms] [2026-10-10 17:13:03][ADC_TASK] phasor(first) C04-IA-F2: Re=3 Im=1 rms=3 (x0.1)
[+587ms] [2026-10-10 17:13:03][ADC_TASK] phasor(first) C05-IA-F5: Re=0 Im=-2 rms=2 (x0.1)
[+598ms] [2026-10-10 17:13:03][NET_TASK] === Network Init ===
[+598ms] [2026-10-10 17:13:03][NET_TASK] net init: OK
[+598ms] [2026-10-10 17:13:03][NET_TASK] MAC: 3C:AB:72:53:2B:12
[+608ms] [2026-10-10 17:13:03][NET_TASK] IP_INF: IP=192.168.1.100 GW=192.168.1.1 MASK=255.255.255.0
[+608ms] MISS start snap=0x00000067 req=0x00000077 t=717
[+619ms] [2026-10-10 17:13:03][WD] [WD] armed: timeout ~2498ms (worst ~1701ms), miss_tol=800ms
[+629ms] [2026-10-10 17:13:03][UI_TASK] UI task: started, wait net ready
[+2541ms] [2026-10-10 17:13:05][NET_TASK] PHY: 100M FULL
[+2551ms] [2026-10-10 17:13:05][NET_TASK] netTask: started (single-socket mode)
[+2593ms] [2026-10-10 17:13:05] [FTP] waiting for connection...
[+2624ms] [2026-10-10 17:13:05][TIME_SYNC] time_sync: TCP listen on :8888 (sock=1)
[+2634ms] [2026-10-10 17:13:05][UI_TASK] UI task: net ready, init port
[+2645ms] [2026-10-10 17:13:05][UI_TASK] UI task: ui_port_init enter
[+2645ms] [2026-10-10 17:13:05][UI_PORT] theme: mono dark_bg=true applied
[+2655ms] [2026-10-10 17:13:05][UI_TASK] UI port init: OK
[+2655ms] [2026-10-10 17:13:05][UI_TASK] UI task: ui_menu_init enter
[+2666ms] [2026-10-10 17:13:05][UI_MENU] menu build start: total=39408 free=36572 big=36572
[+2676ms] [2026-10-10 17:13:05][UI_MENU_VIEW] view init: root frame w=66 h=107
[+2686ms] [2026-10-10 17:13:05][UI_MENU] menu build done: total=39292 free=35708 big=35696 used=3584
[+2686ms] [2026-10-10 17:13:05][UI_TASK] UI menu init: OK
[+2697ms] [2026-10-10 17:13:05][UI_STANDBY] standby: ready (idle=60000ms)
[+2697ms] [2026-10-10 17:13:05][UI_TASK] UI standby: ready (idle=60s)
[+2749ms] [2026-10-10 17:13:05][UI_TASK] UI net sink: started (port 7003)
[+2749ms] MISS start snap=0x00000067 req=0x00000077 t=2857
[+2760ms] [PROF] t=2861 uic=0 uip=0 uipn=0 uil=0 uiw=0 uis=0 uisn=0 adc=2455 adcm=1983 adcn=0 gl=0
[+2770ms] [PROF2] t=2861 defd=11954 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+4922ms] [PROF] t=5025 uic=213 uip=19574 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=4618 adcm=1983 adcn=0 gl=0
[+4933ms] [PROF2] t=5025 defd=11954 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+5335ms] [2026-10-10 17:13:08] [STACK] default peak_used=2152/4096 free_min=1944 (47%)
[+5346ms] [2026-10-10 17:13:08] [STACK] net peak_used=972/3840 free_min=2868 (74%)
[+5356ms] [2026-10-10 17:13:08] [STACK] ftp peak_used=740/4096 free_min=3356 (81%)
[+5356ms] [2026-10-10 17:13:08] [STACK] ui peak_used=4052/16384 free_min=12332 (75%)
[+5366ms] [2026-10-10 17:13:08] [STACK] timesync peak_used=684/2048 free_min=1364 (66%)
[+5377ms] [2026-10-10 17:13:08] [STACK] adc peak_used=952/2560 free_min=1608 (62%)
[+5377ms] [2026-10-10 17:13:08] [STACK] heap free=14576 min_ever=6640
[+6932ms] [PROF] t=7038 uic=408 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=6631 adcm=1983 adcn=0 gl=0
[+6943ms] [PROF2] t=7038 defd=11954 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+8948ms] [PROF] t=9054 uic=608 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=8647 adcm=1983 adcn=0 gl=0
[+8958ms] [PROF2] t=9054 defd=11954 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+10304ms] [2026-10-10 17:13:13][ADC_TASK] frames=10002 idle=0 skip=23 seq=10006 frst_err=0 ring=9979 adc1_rc=0 adc1_err=0 adc1_seq=10004 adc1_gap=23 adc1_hw=0 tgap=1
[+10315ms] [2026-10-10 17:13:13][ADC_TASK] phasor(hb) C01-IA-F1: Re=2 Im=0 rms=2 (x0.1)
[+10325ms] [2026-10-10 17:13:13][ADC_TASK] phasor(hb) C02-UA-F1: Re=1 Im=0 rms=1 (x0.1)
[+10335ms] [2026-10-10 17:13:13][ADC_TASK] phasor(hb) C03-UN-F1: Re=0 Im=0 rms=0 (x0.1)
[+10346ms] [2026-10-10 17:13:13][ADC_TASK] phasor(hb) C04-IA-F2: Re=0 Im=-1 rms=1 (x0.1)
[+10346ms] [2026-10-10 17:13:13][ADC_TASK] phasor(hb) C05-IA-F5: Re=-1 Im=0 rms=1 (x0.1)
[+10956ms] [PROF] t=11057 uic=802 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=10650 adcm=1983 adcn=0 gl=0
[+10966ms] [PROF2] t=11057 defd=47667 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+12977ms] [PROF] t=13074 uic=1002 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=12667 adcm=1983 adcn=0 gl=0
[+12977ms] [PROF2] t=13074 defd=47667 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+14986ms] [PROF] t=15091 uic=1202 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=14684 adcm=1983 adcn=0 gl=0
[+14996ms] [PROF2] t=15091 defd=47667 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+17009ms] [PROF] t=17108 uic=1402 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=16701 adcm=1983 adcn=0 gl=0
[+17019ms] [PROF2] t=17108 defd=47667 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+19025ms] [PROF] t=19125 uic=1602 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=18718 adcm=1983 adcn=0 gl=0
[+19036ms] [PROF2] t=19125 defd=47667 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+20305ms] [2026-10-10 17:13:23][ADC_TASK] frames=20002 idle=0 skip=25 seq=20006 frst_err=0 ring=19977 adc1_rc=0 adc1_err=0 adc1_seq=20004 adc1_gap=25 adc1_hw=0 tgap=2
[+20316ms] [2026-10-10 17:13:23][ADC_TASK] phasor(hb) C01-IA-F1: Re=0 Im=0 rms=0 (x0.1)
[+20326ms] [2026-10-10 17:13:23][ADC_TASK] phasor(hb) C02-UA-F1: Re=-2 Im=-2 rms=3 (x0.1)
[+20337ms] [2026-10-10 17:13:23][ADC_TASK] phasor(hb) C03-UN-F1: Re=0 Im=0 rms=1 (x0.1)
[+20337ms] [2026-10-10 17:13:23][ADC_TASK] phasor(hb) C04-IA-F2: Re=-1 Im=-1 rms=1 (x0.1)
[+20348ms] [2026-10-10 17:13:23][ADC_TASK] phasor(hb) C05-IA-F5: Re=2 Im=1 rms=2 (x0.1)
[+21059ms] [PROF] t=21158 uic=1799 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=20751 adcm=1983 adcn=0 gl=0
[+21069ms] [PROF2] t=21158 defd=47964 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+23075ms] [PROF] t=23175 uic=1999 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=22768 adcm=1983 adcn=0 gl=0
[+23085ms] [PROF2] t=23175 defd=47964 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+25094ms] [PROF] t=25192 uic=2199 uip=58732 uipn=9991 uil=10003 uiw=10337 uis=1 uisn=0 adc=24785 adcm=1983 adcn=0 gl=0
[+25094ms] [PROF2] t=25192 defd=47964 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+27102ms] [PROF] t=27209 uic=2399 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=26802 adcm=1983 adcn=0 gl=0
[+27112ms] [PROF2] t=27209 defd=47964 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
[+29122ms] [PROF] t=29226 uic=2599 uip=58732 uipn=9995 uil=9999 uiw=10337 uis=1 uisn=0 adc=28819 adcm=1983 adcn=0 gl=0
[+29132ms] [PROF2] t=29226 defd=47964 defs=7 netp=0 netn=0 adcp=10 adcq=0 gl=0
@@ -27,6 +27,8 @@
|---|---|---|---|
| 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` |
| 2026-10-10 | `prod_adc_l1` / 开机 + 30 s 空载 | `adc` **584/2048(71%)**(+56 B,L1 层 adc_input_poll/raw 上链);`default` 2164/4096(47%);heap free=15088 min_ever=7152 | `20261010_prod_adc_l1_boot_log.txt` |
| 2026-10-11 | `prod_phasor` / 开机 + 30 s 空载(L2 台架闭环) | `adc` **928/2048(54%)**(+344 B,压环 + `phasor_run` + `log_phasors` 上链);`default` 2152/4096(47%);heap free=15088 min_ever=7152 | `20261011_prod_phasor_boot_log.txt` |
| 2026-10-11 | `prod_adc_health` / 开机 + 30 s 空载(L1-6 + 抬栈 640 words) | `adc` **952/2560(62%)**(静态最坏链 1080 B,`adc_health_report`→`syslog_post` 回显尾);`default` 2152/4096(47%);heap free=14576 **min_ever=6640**(抬栈 -512 B,符合预算) | `20261011_prod_adc_health_boot_log.txt` |
## 4. 关联
@@ -67,7 +67,7 @@
| **B0 产品定义** | 采集是否持续 / 采样率与通道 / 转发目标 / 保护元件清单——决定 B1 与保护层的**规模** | ✅ 已确认(2026-10-10,见 §1.5) |
| **B1 ADC 采集链路** | 周期 CONVST + `adc_task` 消费 `tpafe5160_snapshot()` + 建任务 + 栈预算 | ✅ 已实现并 `@test` 实机闭环(2026-10-10;`adcTask` 512 words,台架 1000 Hz) |
| **N-18 硬件缺陷** | V0.1 跨转换器无同一时刻性 → 限定 V0.1 可实现的保护范围 | ⚠️ 硬件改版项(V0.2) |
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | 🔶 `adcTask` 已核算(**L2 接入后复测 2026-10-11:静态 832 B / 台架实测峰值 928/2048 / 余 54%**);`protectTask` 为后续 |
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | 🔶 `adcTask` 已核算(**L1-6 后:栈抬至 640 words,静态 1080 B / 台架实测峰值 952/2560 / 余 57%**);`protectTask` 为后续 |
### 1.5 B0 产品定义(2026-10-10 确认)
@@ -243,7 +243,7 @@
| L1-3 | STM32 ADC1 启动与扫描 | 9 通道、144 cycles、**TIM3 TRGO 硬件触发 + DMA** | 全库出现 `HAL_ADC_Start_DMA`;9 通道码值随注入变化 | ✅ 2026-10-10(v2.0):`App/algo/adc_input.c` 的 `stm32_take()`——ADC1 由 TIM3 更新事件经 TRGO 触发一轮 9 通道,`HAL_ADC_Start_DMA(&hadc1, buf, 18)` + DMA2_Stream4 循环模式把码值自动搬进**乒乓双缓冲**,任务侧只消费刚完成的半区(**零忙等**,实测单拍 `adcp` 122 µs → **8 µs**);台架 `@test` PASS——`adc1_seq` 每拍 +1、`adc1_err=0`、`adc1_hw=0`。⚠ 判据"随注入变化"以"逐通道独立读数 + 零停摆 + 跨次开机读数不同"替代(台架无信号源,同 §7.1 无示波器口径);**引脚级注入验证(`ADC通道映射说明.md` §8 步骤 2)仍为待做项** |
| L1-4 | 通道语义映射 | 见 `docs/硬件平台/ADC通道映射说明.md`(**按语义取数,不写死下标**) | `UA→buf[6]`、`UN→buf[5]`、`IA→buf[2]`;STM32 侧 `UB→ADC_CHANNEL_14` | ✅ 2026-10-10:`App/algo/adc_input.c` 的 `k_adc_map[]` 语义表(`UA/UN/IA`→TPAFE `buf[6]/[5]/[2]`,`UB/UC/IB/IC/IN/TEMP`→ADC1 `CH14/3/6/1/2/5`)+ `adc_input_raw()` 按语义取数;开机**映射自检**(`adc_input_init()` 校验 STM32 映射通道必落在扫描序列内 → 挡住"映射到不扫描的通道"静默错)通过(`ADC input layer init: OK`)。台架首帧日志 8 路 + 温度全部读出:`UA=11429 UN=11454 IA=11452`(与 TIM3 轮次一致)、`UB=1018 UC=1044 IB=943 IC=1069 IN=1052 T=850`(互异、非饱和;**两次开机读数不同** → 确为实时转换而非常量) |
| L1-5 | 通道标定(一次系数 + 零漂) | 每通道 `k`、`b`;系数定点 `2^10` | 注入标准源,读数误差 ≤ 目标精度 | ⬜ |
| L1-6 | 采样有效性校验 | FRSTDATA 跳变、帧序号单调、丢帧计数 | 芯片静默/丢帧被检出并置告警 | ⬜ |
| L1-6 | 采样有效性校验 | FRSTDATA 跳变、帧序号单调、丢帧计数 | 芯片静默/丢帧被检出并置告警 | ✅ 2026-10-11:新增 `App/algo/adc_health.c/h`(纯逻辑判定层:静默 100 ms 门限 / 丢帧边沿 / 序号倒退锁存 / FRSTDATA·HAL 错误·STM32 停摆计数增量)+ `adc_task.c` 告警编排(严重事件与故障上升沿 `DBG_ERROR` + 每类每次开机一次 `SYSLOG_SELFTEST`,恢复 `DBG_INFO`;gap 不告警只计数,心跳增 `tgap`);主机单测 `test/host/adc_health/` **31 用例全绿**(`adc-health-unit-test` 钩子);台架 `@test` PASS 零 `[ERR]`(健康不误报,`boot_log_data/20261011_prod_adc_health_boot_log.txt`)。⚠ 抬栈:判定链 `adc_health_report`→`syslog_post` 回显尾使 adcTask 静态最坏链 832→**1080 B** → 栈 512→**640 words**(余 1480 B / 57%) |
| L1-7 | 等周波采样(软件测频 + 调频闭环) | 20 点/周波;测频范围建议 **45~55 Hz**(参考 40.5~60.5) | 频率偏移 ±2 Hz 时幅值误差 ≤ 1% | ⬜ |
| L1-8 | 零序通道接入(外部专用 / 自产切换) | 外部 `UN`/`IN`;自产 `3I0 = Ia+Ib+Ic`(V0.2 起) | 零序通道可切换来源,值正确 | ⬜ |
| L1-9 | 二次谐波/五次谐波提取入口 | k=2(涌流)、k=5(选线) | 相量层可产出对应谐波相量 | ✅ 2026-10-11:`phasor.c` 实例表 `C04-IA-F2`(k=2)/ `C05-IA-F5`(k=5)随每拍重算产出,台架心跳日志 `phasor(hb) C04/C05` 行可见(`boot_log_data/20261011_prod_phasor_boot_log.txt`);谐波**抑制/提取正确性**已由主机单测覆盖(`test/host/phasor/`) |
@@ -463,7 +463,7 @@
| 阶段 | 名称 | 内容 | 前置 | 里程碑 |
| --- | --- | --- | --- | --- |
| **P0** | 采样与相量底座 | B1(周期 CONVST + `adcTask` 消费 + 建任务 + 栈预算)+ L1 + L2 | B0 + B1 ✅ | 每 1 ms 产出正确的基波相量 —— **✅ 2026-10-11 台架闭环**(L1-5 标定 / L1-6 有效性 / L1-7 等周波为 P0 遗留项,精度复核依赖标准源) |
| **P0** | 采样与相量底座 | B1(周期 CONVST + `adcTask` 消费 + 建任务 + 栈预算)+ L1 + L2 | B0 + B1 ✅ | 每 1 ms 产出正确的基波相量 —— **✅ 2026-10-11 台架闭环**(L1-6 同日落地 ✅;L1-5 标定 / L1-7 等周波为 P0 遗留项,精度复核依赖标准源) |
| **P1** | 基础保护元件 | **V0.1 有效子集**:过流(A 相,`IA`)、过负荷(A 相)+ 定值模型;B/C 相过流**建接口不使能** | P0 | 标准源注入 A 相可正确动作 |
| **P2** | 电压/频率类保护 | 过压/欠压(`UA`)、过频/低频、零序过压(`UN`) | P0 | 电压/频率越限正确动作 |
| **P3** | 异常检测与闭锁 | L5 自检闭锁、采样通道自检;三相类(涌流/PT·CT 断线/母线接地)**建接口不使能** | P1/P2 | 自检失败闭锁;未使能元件不误动 |
@@ -602,3 +602,4 @@ B0 产品定义 ✅(2026-10-10 已确认,见 §1.5)
| 2026-10-10 | **L2 相量层落地 + L2-2 实例数口径对齐** | 新增 `App/algo/sample_ring.c/h`(L2 输入:按语义通道保存 2 周波 = 40 点环缓冲,整帧写后统一推进写指针)与 `App/algo/phasor.c/h`(L2 核心:全周傅氏单频 DFT,N = 20;系数表**离线预乘 √2/N** → `fAmSQ` 直接为**有效值**;计算区/使用区**双区原子切换**;实例表 `k_inst[]` 数据驱动);主机侧单测 `test/host/phasor/` **57 用例全绿**(`phasor-unit-test` 钩子)。**§3.2 L2-2 行口径对齐**:参考项目为 **4 个实例**,本项目按 V0.1 有效通道展开为 **5 个**(`C01-IA-F1`/`C02-UA-F1`/`C03-UN-F1`/`C04-IA-F2`/`C05-IA-F5`),已加注说明 4 → 5 的来历;§4.3 相量区 RAM 行同步为 5 实例。⚠ §3.2 的 L2 各点状态**仍标 ⬜**——实现与主机单测已完成,但**台架 `@test` 闭环未做**,且 L2-3 的完成判据(标准源读数 = 设定有效值)在无信号源台架上不可达,故不置 ✅(口径见 §3.2 表下注) |
| 2026-10-10 | **L1-1/L1-3 节拍源与搬运方式升级(v2.8)** | 节拍源 **TIM6 → TIM3**(更正硬事实:F4 上 ADC1 的外部触发清单里没有 TIM6/TIM7 TRGO,只接 DAC),TIM3 更新事件同时触发 TPAFE CONVST 与(经 TRGO)ADC1 一轮 9 通道;L1-3 由"软件触发 + 逐通道轮询"改为 **DMA2_Stream4 循环搬运 + 乒乓双缓冲**,`stm32_scan()` → `stm32_take()`,单拍 `adcp` **122 µs → 8 µs**。§1.4 采样软件行、§3.2 L1-1/L1-3/L1-4 同步。完整设计与实测见 `docs/子系统设计/ADC采样节拍设计说明.md` §11 |
| 2026-10-11 | **L2 台架闭环:P0 收尾** | `@build` 0 错 0 警 → `@test` 闭环把 `phasor(first)`/`phasor(hb)` 列为 Required 并校验顺序 `App init OK>phasor(first)>phasor(hb)`(⚠ `net init: OK` **不在**该序内——adcTask 与 netTask 并行,`phasor(first)` ≈+500 ms 早于 `net init: OK` ≈+574 ms 属正常)→ **PASS**:5 实例相量开机即产出、心跳 5 实例持续刷新、`frames` 每 10 s +10000(1000.0 Hz)、`idle=0`、`frst_err=0`、`adc1_err=0`、`adc1_hw=0`、`fw build` 身份戳匹配、回读一致、锚点 ×1、零 `[ERR]`/HardFault;证据 `boot_log_data/20261011_prod_phasor_boot_log.txt`。栈复测:adcTask 静态 832 B / 实测峰值 **928/2048(余 54%)**,7 任务全 PASS(RAM 方案 §2.3 已同步)。§3.1 L1-9 置 ✅(`C04-IA-F2`/`C05-IA-F5` 台架产出);§3.2 L2-1~L2-4/L2-6/L2-7 置 ✅(精度判据保留"待标准源"注),**L2-5 更正为"V0.1 不适用、随 V0.2"**(跨转换器合成被 N-18 禁止、零序走外部专用通道——原表下注"L2-1~L2-7 实现完成"对 L2-5 系误记);§7.1 P0 里程碑置 ✅(遗留 L1-5/L1-6/L1-7)。下一步 = **P1**(A 相过流/过负荷 + 定值模型)与 **L1-6 采样有效性校验** |
| 2026-10-11 | **L1-6 采样有效性校验落地** | 新增 `App/algo/adc_health.c/h`(**纯逻辑判定层**,零平台依赖免桩单测):① 静默——两侧帧序号连续 ≥100 ms 无前进(电平位,可自愈;`adc_health_flags()` 为 L5-4 闭锁预留);② 丢帧——TPAFE 序号一次前进 >1 计 `tgap`(与 STM32 侧 `adc1_gap` 对称,边沿事件不告警——消费者超拍是已知现象,告警会淹没真故障);③ 单调性——序号倒退锁存位;④ 错误增量——FRSTDATA / HAL 错误回调 / STM32 停摆计数增量(事件位与锁存位**编号对齐**,消费者按位图"每类每次开机留痕一次")。`adc_task.c` 只做告警编排:严重事件/上升沿 `DBG_ERROR` + `SYSLOG_SELFTEST`("adc sampling fault"),下降沿 `DBG_INFO`,心跳行增 `tgap`。主机单测 `test/host/adc_health/` **31 用例全绿**(100 ms 门限两侧、tick 回绕、边沿语义、NULL 守卫、init 幂等;`adc-health-unit-test` 钩子登记)。台架 `@test` PASS:零 `[ERR]`(健康不误报)、`tgap=1→2` 与 `adc1_gap` 同步可见、`frames` 1000.0 Hz;证据 `boot_log_data/20261011_prod_adc_health_boot_log.txt`。⚠ **抬栈**:`adc_health_report`→`syslog_post` 控制台回显尾使 adcTask 静态最坏链 832→**1080 B**(512 words 余 968 B < 1024 B 底线)→ **512→640 words**,复测余 **1480 B / 57%**、堆 min_ever 7152→6640 B(AGENTS 任务表 / RAM 方案 §2.3 已同步)。§3.1 L1-6 置 ✅ |