fix(console): gate adcTask logs on console-writer readiness
B1 on-board closed loop surfaced a byte-level console interleave: before the console writer (defaultTask) registers, con_append() routes to dbg_console_write_raw() -> con_tx_bounded(), which is register-level polling with no mutual exclusion. adcTask logged every 1 ms, so its first-frame line collided with defaultTask's [NAND_FTL] init line and the required marker spanned two interleaved lines -> false FAIL. - console_log: add dbg_console_writer_ready() (returns s_con_writer_up) - adc_task: gate first-frame and 10 s stats logs on writer readiness; defer the first-frame report until the writer is up - docs: close B1/P1-1 in the registry; flip stale "remaining @test" notes; correct the console doc's obsolete "drop-only, no interleave" claim (that held for HAL gState, not register-level raw send) Bench (run_boot_test.py): VERDICT PASS, readback OK. adcTask frames/seq +10000 per 10 s = 1000 Hz, idle=0, frst_err=0; stack 496/2048 (75%). @build 0/0.
This commit is contained in:
@@ -26,6 +26,11 @@
|
||||
* 都换成 DWT 周期计数硬上界(DWT 使能失败时退回旧 HAL 行为)。
|
||||
* 另加 USART1 未初始化(huart1.Instance == NULL)短路:防止在
|
||||
* HAL_Init 早期/断言-故障上报路径上解引用 NULL 读写地址 0。
|
||||
* 2026-10-10 王建锋 新增 dbg_console_writer_ready() 查询:写者未注册时
|
||||
* con_append 走无锁直发(前提是"此窗口只有 defaultTask 记日志"),
|
||||
* adcTask(B1)等周期任务此时落日志会与 defaultTask 的存储初始化
|
||||
* 日志字节级交错(台架实测 [ADC_TASK] 首帧行与 [NAND_FTL] 行交错)。
|
||||
* 提供就绪查询供周期任务门控自身日志,不改直发路径本身。
|
||||
*/
|
||||
|
||||
#include "console_log.h"
|
||||
@@ -223,6 +228,19 @@ void dbg_console_writer_attach(void) {
|
||||
s_con_writer_up = 1U;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:查询控制台写者是否已注册(1=已注册,此后日志走环形缓冲行级原子路径)
|
||||
* 返回值:s_con_writer_up(volatile 读,任意任务上下文可调)
|
||||
* 限定条件:无
|
||||
* 函数说明:供**周期性任务**在写者就绪前抑制自身日志。写者未注册时 con_append 走
|
||||
* dbg_console_write_raw 无锁直发(设计前提是"此窗口只有 defaultTask 记日志"),
|
||||
* 其余任务此时落日志会与 defaultTask 的存储初始化日志逐字节交错
|
||||
* (2026-10-10 台架:adcTask 首帧日志与 [NAND_FTL] 初始化行交错)。
|
||||
*/
|
||||
uint8_t dbg_console_writer_ready(void) {
|
||||
return s_con_writer_up;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:USART1 僵尸通道自愈(清错误锁存 + 整外设重初始化)
|
||||
* 函数说明:RX 悬空噪声(PA10 未接线)锁存的 ORE/NE/FE/PE 使 HAL 轮询 TX 恒快速失败
|
||||
|
||||
@@ -34,6 +34,10 @@ extern "C" {
|
||||
* DBG_PRINT 宏内用库 snprintf 完成)
|
||||
* dbg_console_write_raw - 异常/早期路径:有界单次直发(不加锁)
|
||||
* dbg_console_writer_attach- 写者任务(defaultTask)注册自己为唯一发送者
|
||||
* dbg_console_writer_ready - 写者是否已注册(1=已注册)。供**周期性任务**在写者就绪前
|
||||
* 抑制日志用:写者未注册时 con_append 走无锁直发路径
|
||||
* (仅假设 defaultTask 在日志),其余任务此时落日志会与
|
||||
* defaultTask 的存储初始化日志字节级交错(2026-10-10 台架实测)
|
||||
* dbg_console_drain - 写者任务排空缓冲并发送(单次有界;TX 失败自动软复位自愈)
|
||||
* dbg_console_dropped - 因缓冲满丢弃的行数(诊断)
|
||||
* dbg_console_tx_fault - 因僵尸通道软复位自愈的次数(诊断)
|
||||
@@ -47,6 +51,7 @@ extern "C" {
|
||||
int dbg_console_write_line(const char *line, unsigned len);
|
||||
void dbg_console_write_raw(const char *buf, unsigned len);
|
||||
void dbg_console_writer_attach(void);
|
||||
uint8_t dbg_console_writer_ready(void);
|
||||
void dbg_console_drain(void);
|
||||
uint32_t dbg_console_dropped(void);
|
||||
uint32_t dbg_console_tx_fault(void);
|
||||
|
||||
+25
-12
@@ -20,12 +20,17 @@
|
||||
* v1.1 2026-10-05 王建锋 P3-11:注明"预留桩(未启用)",避免误认为已实现
|
||||
* v2.0 2026-10-10 王建锋 B1:实现真实消费者(1ms 节拍 + 原子快照 + 帧统计 +
|
||||
* 看门狗心跳),由 Src/freertos.c 创建为 adcTask
|
||||
* v2.1 2026-10-10 王建锋 日志门控:首帧/周期统计仅在 dbg_console_writer_ready()
|
||||
* 为真后落日志。写者未注册时控制台走无锁直发,与
|
||||
* defaultTask 的存储初始化日志字节级交错(台架实测);
|
||||
* 就绪前挂起上报,就绪后补报最近一帧。
|
||||
*/
|
||||
|
||||
#include "adc_task.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "tpafe5160.h"
|
||||
#include "task_watchdog.h"
|
||||
#include "console_log.h"
|
||||
|
||||
#define DBG_TAG "[ADC_TASK]"
|
||||
#include "dbg_log.h"
|
||||
@@ -82,31 +87,39 @@ void adc_task_func(void *arg) {
|
||||
r = tpafe5160_snapshot(s_frame, (uint8_t)TPAFE5160_CH_NUM);
|
||||
if (r == 1) {
|
||||
s_frames_consumed++;
|
||||
if (first_logged == 0u) {
|
||||
first_logged = 1u;
|
||||
/* 只报 TPAFE 三路(UA=buf[6] UN=buf[5] IA=buf[2]),验证取数契约 */
|
||||
DBG_INFO("first frame: UA=%d UN=%d IA=%d",
|
||||
s_frame[6], s_frame[5], s_frame[2]);
|
||||
}
|
||||
} else if (r == 0) {
|
||||
s_frames_idle++;
|
||||
} else {
|
||||
/* r == -1:参数错。调用点 count 为常量,不可达;不计入 idle 以区分异常 */
|
||||
}
|
||||
|
||||
/* 2b) 首帧码值上报:**写者就绪后**才落日志。写者未注册时 con_append 走
|
||||
* 无锁直发路径,与 defaultTask 的存储初始化日志会字节级交错
|
||||
* (2026-10-10 台架实测);此时挂起上报,就绪后补报最近一帧。
|
||||
* 只报 TPAFE 三路(UA=buf[6] UN=buf[5] IA=buf[2]),验证取数契约 */
|
||||
if ((first_logged == 0u) && (s_frames_consumed != 0u) &&
|
||||
(dbg_console_writer_ready() != 0u)) {
|
||||
first_logged = 1u;
|
||||
DBG_INFO("first frame: UA=%d UN=%d IA=%d",
|
||||
s_frame[6], s_frame[5], s_frame[2]);
|
||||
}
|
||||
|
||||
/* 3) 看门狗心跳(本任务已纳入 required_mask) */
|
||||
task_wd_beat(TASK_WD_ADC);
|
||||
|
||||
/* 4) 周期心跳日志:帧统计 + 驱动侧 FRSTDATA 错误计数 */
|
||||
/* 4) 周期心跳日志:帧统计 + 驱动侧 FRSTDATA 错误计数。
|
||||
* 写者就绪前抑制(同 2b 的交错理由);到点无论是否落日志都推进下个上报点 */
|
||||
{
|
||||
uint32_t now = osKernelGetTickCount();
|
||||
|
||||
if ((int32_t)(now - report_at) >= 0) {
|
||||
DBG_INFO("frames=%lu idle=%lu seq=%lu frst_err=%u",
|
||||
(unsigned long)s_frames_consumed,
|
||||
(unsigned long)s_frames_idle,
|
||||
(unsigned long)tpafe5160_frame_seq(),
|
||||
(unsigned)tpafe5160_frstdata_err());
|
||||
if (dbg_console_writer_ready() != 0u) {
|
||||
DBG_INFO("frames=%lu idle=%lu seq=%lu frst_err=%u",
|
||||
(unsigned long)s_frames_consumed,
|
||||
(unsigned long)s_frames_idle,
|
||||
(unsigned long)tpafe5160_frame_seq(),
|
||||
(unsigned)tpafe5160_frstdata_err());
|
||||
}
|
||||
report_at = now + ADC_TASK_REPORT_MS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
## 关键点
|
||||
|
||||
- **首次转换在 `app_main_init` 末尾由 `tpafe5160_start_conv_irq` 启动**(中断驱动);**无周期重触发** → 现只采到一帧(登记簿 P1-1)
|
||||
- **首次转换在 `app_main_init` 末尾由 `tpafe5160_start_conv_irq` 启动**(中断驱动);**运行期周期重触发自 2026-10-10 起由 `adcTask` 接管**(每 1 ms,B1)
|
||||
- **取数只用 `tpafe5160_snapshot(int16_t *dst, uint8_t count)`**(**仅任务上下文**,内部临界区原子拷贝;返回 1=新帧 / 0=无新帧 / -1=参数无效)。配套的 `tpafe5160_frame_seq()` 给帧序号、`tpafe5160_frstdata_err()` 给"FRSTDATA 无跳变"帧计数
|
||||
- ⚠️ **不要用缓冲区指针取数**:旧的 `get_buf()` / `data_ready()` / `clear_ready()` 已于 2026-10-10 **删除**(审计 E-45 / E-58)——`get_buf` 只给指针、任务再逐通道拷,中间被 BUSY EXTI 抢占就拷回**两帧混合**数据;`s_ready` 电平标志在 `start_conv_irq` 里被清 0,等于**用重触发去丢帧**。现由**帧序号**(只增不清)+ **临界区快照**取代
|
||||
- **`tpafe5160_init()` 做首帧有效性自检**(E-44):完整跑一帧转换+读取,若整帧读下来 FRSTDATA **没有发生任何跳变**(芯片没在驱动并行总线;板上上拉会把它钉死为高)→ 返回 `TPAFE5160_FRSTDATA_ERR`(-3) 并打 `[ERR] Init FRSTDATA no-toggle`。判据刻意不锁死"哪个 RD 边沿拉高/拉低"(手册只给"RD 下降沿 → FRSTDATA 高/低"两个跳变,本板未实测边沿次序),只要求"一帧内必须跳变" → 既抓死芯片,也不会因极性假设错误误杀好芯片
|
||||
- 采样数据的消费者 `App/task/adc_task.c` **仍是空桩**(已挂进 `MDK-ARM/*.uvprojx`,尚未在 `Src/freertos.c` 建任务)
|
||||
- 采样数据的消费者 `App/task/adc_task.c` **已实现**(B1,2026-10-10:每 1 ms 触发 CONVST + `tpafe5160_snapshot()` 原子取数;`adcTask` 在 `Src/freertos.c` 的 `USER CODE` 区创建)
|
||||
- CONVST→BUSY→RD 三段时序对**建立/保持时间敏感**,改动需对照芯片手册
|
||||
- ⚠️ 本项目 ADC 相关功能**新增任务/缓冲前须核算 RAM**(见 `docs/内存管理/`);接消费者前的强制门禁见根 `AGENTS.md`「接 ADC / RS-485 消费者前的强制门禁」
|
||||
- ⚠️ **通道语义不是通道号**:`buf[i]` 对应哪个电气量必须查 `docs/硬件平台/ADC通道映射说明.md`(`buf[2]=IA`、`buf[5]=UN`、`buf[6]=UA`);V0.1 上 8 路电气量分属两片转换器属硬件缺陷(N-18)→ **禁止**跨转换器做相位/功率/功率因数类运算
|
||||
|
||||
@@ -443,10 +443,10 @@ sequenceDiagram
|
||||
- 实现:`defaultTask` 循环驱动(闪烁指示系统活跃)。
|
||||
- 判据:目检 6 路 LED 随系统状态变化。
|
||||
|
||||
### 5.9 ADC 采集(FR-ADC)⬜ 待实现
|
||||
### 5.9 ADC 采集(FR-ADC)🔶 采集链路已实现(B1);保护/遥测算法与上行待实现
|
||||
|
||||
- **需求(B0 已确认,2026-10-10)**:**持续采集** 8 路电气量(Ua/Ub/Uc/U0、Ia/Ib/Ic/I0,**1000 Hz / 20 点/周波**),经保护/遥测算法后**上送 IEC 60870-5-104**(以太网 TCP 2404;遥测上送短浮点、采集上传系数 = 1)。
|
||||
- **现状**:`tpafe5160_init()` 与 `tpafe5160_start_conv_irq()` 在启动序列调用一次;**全仓库无周期性 CONVST 重触发**;`tpafe5160_snapshot()` 无消费者(`adc_task.c` 为空桩——2026-10-10 起已挂进 `uvprojx`,仍未在 `freertos.c` 创建);STM32 侧 ADC1 已生成但**全仓库无 `HAL_ADC_Start`**。
|
||||
- **现状(采集链路 B1 已实现,2026-10-10)**:启动序列仍调用一次 `tpafe5160_init()` + `tpafe5160_start_conv_irq()`;**运行期周期 CONVST 重触发已由 `adcTask` 接管**(每 1 ms)+ `tpafe5160_snapshot()` 原子消费(8 通道)+ 帧统计,台架 `@test` 确认 `frame_seq` 严格 1000 Hz 递增、`idle=0`、`frst_err=0`;STM32 侧 ADC1 已生成但**全仓库无 `HAL_ADC_Start`**(按 N-18 仅逐通道独立监视,消费者为后续)。
|
||||
- **后果**:上电后仅采集 1 个样本,此后数据永久陈旧。
|
||||
- **B0 结论**(2026-10-10,详见 `docs/算法/继电保护功能复现规划.md` §1.5):① 持续采集 ② 1000 Hz(20 点/周波),通道 = 4U+4I(点表 `4011~4018`)③ 上行 **IEC 60870-5-104**(2404,非 ModBus RTU 上行)④ `APP_ADC_ENABLE` 语义 = 门控 ADC 采集链路(ADC 为遥测/保护必需来源;是否接线或删除占位宏待定)。
|
||||
- **实现约束**(见 §9):周期 CONVST 重触发 + `adc_task` 消费 `tpafe5160_snapshot()`;**原子快照 API 已就位**(2026-10-10 修 E-44 / E-45 / E-58,旧的 `get_buf` / `data_ready` / `clear_ready` 已删 → 取数不再撕裂、重触发不再丢帧、芯片不驱动总线会被 `init()` 首帧自检抓到);栈预算核算;V0.1 通道映射已固化 → `docs/硬件平台/ADC通道映射说明.md`(13/17 路置换;语义 UA/UB/UC/UN、IA/IB/IC/IN、V_ZL2=温度,其余备用;网名 ADC17 = PC4 用 `ADC_CHANNEL_14`,**不是** `ADC_CHANNEL_12`)。⚠ **8 路电气量分属 TPAFE / STM32 两片转换器属 V0.1 硬件缺陷**(跨转换器无同一时刻性、精度与量程不一致,登记簿 N-18,V0.2 改版要求全部走 TPAFE)→ 在 V0.1 上主板侧只做**逐通道独立监视**,功率 / 功率因数 / 相角 / 矢量类量一律取子板计量模块结果,不得由主板混算。
|
||||
@@ -770,7 +770,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
|
||||
| 缺口 | 现状 | 影响 |
|
||||
|---|---|---|
|
||||
| **ADC 采集链路** | `adc_task.c` 空桩(已挂进 `uvprojx`、未建任务);无周期 CONVST 重触发;`tpafe5160_snapshot()` 无消费者;STM32 侧无 `HAL_ADC_Start` | 上电后仅采 1 个样本(驱动取数契约已于 2026-10-10 修好,接消费者不再有撕裂/丢样风险) |
|
||||
| **ADC 采集链路** | ✅ **采集链路已实现(B1,2026-10-10)**:`adcTask` 每 1 ms 触发 CONVST + `tpafe5160_snapshot()` 原子消费,台架 `@test` 闭环(1000 Hz);STM32 侧仍无 `HAL_ADC_Start`(N-18,逐通道独立监视,后续) | 数据路径已通;剩余为上层保护/遥测算法与 104 上行 |
|
||||
| **RS-485 采集链路** | `rs485_task.c` 空桩;`App/protocol/` 仅 README | 无 RS-485 数据收发(B0 定:**对下 ModBus RTU 采集**) |
|
||||
| **DTU 核心转发职责** | **B0 已定(2026-10-10)**:上行 **IEC 60870-5-104**(以太网 TCP 2404,遥测短浮点系数 1);RS-485 对下 ModBus RTU 采集 | 转发目标已明确,待实现 |
|
||||
|
||||
@@ -780,7 +780,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
|
||||
```text
|
||||
【阶段 B 功能】 B0 产品定义确认 ✅ ─┬─ B3 E-59 门禁固化(并行)
|
||||
(当前最高优先) └─ E-58 原子快照 → B1 ADC → B2 RS485
|
||||
(当前最高优先) └─ E-58 原子快照 → B1 ADC ✅ → B2 RS485
|
||||
↓
|
||||
【阶段 C 结构】 C1 pending 二期 ─ C3 日志管线 ─ C4 栈(S-1) ─ C5 收口 ─ C6 USART1 TX-only
|
||||
↓
|
||||
@@ -790,7 +790,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
| 阶段 | 关键任务 | 前置 |
|
||||
|---|---|---|
|
||||
| **B0** | 产品定义确认 ✅(2026-10-10):持续采集 / 1000 Hz·20 点周波 / 上行 IEC 60870-5-104(2404)/ RS-485 对下 ModBus RTU;详见 `docs/算法/继电保护功能复现规划.md` §1.5 | — |
|
||||
| **B1** | ADC 采集链路实现(周期 CONVST + `adc_task` 消费;**先修原子快照 API**) | B0 + E-59 门禁 |
|
||||
| **B1** | ADC 采集链路实现(周期 CONVST + `adc_task` 消费;**先修原子快照 API**) | ✅ 已实现并 `@test` 闭环(2026-10-10) |
|
||||
| **B2** | RS-485 采集链路实现(双缓冲 + 序号 + DE 收尾 + 协议状态机) | B0 + E-59 门禁 |
|
||||
| **B3** | E-59 门禁固化入 `AGENTS.md`(接消费者前先修缺陷 + 栈预算) | — |
|
||||
| **C1** | pending 二期(ACCEPT + SEND pending 化) | — |
|
||||
@@ -801,7 +801,7 @@ cfg-file-unit-test、test-suite-switch、gitlint。
|
||||
|
||||
| 开关 | 位置 | 现状 |
|
||||
|---|---|---|
|
||||
| `APP_NET_ENABLE` / `APP_ADC_ENABLE` / `APP_RS485_ENABLE` | `App/app/app_cfg.h` | **未接线占位,不门控任何代码**——三宏全库零消费点,各模块一律编译进产品;B0 已确认 ADC / RS-485 均为必需链路(ADC=遥测/保护来源,RS-485=对下 ModBus RTU 采集)→ 建议在 B1/B2 落地时接线为真实门控(或删除占位宏)。**在接线前不要把它们当开关用** |
|
||||
| `APP_NET_ENABLE` / `APP_ADC_ENABLE` / `APP_RS485_ENABLE` | `App/app/app_cfg.h` | **未接线占位,不门控任何代码**——三宏全库零消费点,各模块一律编译进产品;B0 已确认 ADC / RS-485 均为必需链路(ADC=遥测/保护来源,RS-485=对下 ModBus RTU 采集)→ 建议在后续落地时接线为真实门控(或删除占位宏)。**在接线前不要把它们当开关用** |
|
||||
| `TEST_SUITE_*` | `test/board/test_config.h` | 测试套件**互斥**,一次构建只开一个;全注释 = 正常产品固件 |
|
||||
|
||||
---
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 268,300 B (262.01 KB) | 1,048,576 B (1024 KB) | 25.6% |
|
||||
| ER_IROM1 | 268,332 B (262.04 KB) | 1,048,576 B (1024 KB) | 25.6% |
|
||||
| RW_IRAM1 | 89,200 B (87.11 KB) | 131,072 B (128 KB) | 68.1% |
|
||||
| RW_CCM | 49,184 B (48.03 KB) | 65,280 B (64 KB) | 75.3% |
|
||||
| **Flash (ROM 合计)** | **269,060 B (262.8 KB)** | 1,048,576 B (1024 KB) | **25.7%** |
|
||||
| **Flash (ROM 合计)** | **269,092 B (262.8 KB)** | 1,048,576 B (1024 KB) | **25.7%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
@@ -104,7 +104,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 采样(1 ms 采样节拍触发 CONVST + 原子快照消费,B1 2026-10-10) | 未观测 / 静态 **504 B**(余 1544 B / 75%) |
|
||||
| adcTask | `512*4` | 2KB | TPAFE5160 采样(1 ms 采样节拍触发 CONVST + 原子快照消费,B1 2026-10-10) | **496 / 2048**(余 1552 B / 75%,台架 `@test` 实测);静态 504 B |
|
||||
| idle(内核) | `configMINIMAL_STACK_SIZE=128` | 0.5KB | 空闲 | 未观测(未取句柄) |
|
||||
| timer(内核) | `configTIMER_TASK_STACK_DEPTH=256` | 1KB | 软定时器 | 未观测 |
|
||||
|
||||
|
||||
@@ -102,15 +102,19 @@ flowchart LR
|
||||
P3 -- "有界直发 ≤256B" --> U
|
||||
```
|
||||
|
||||
### 3.4 HAL 并发语义与本设计的配合(实现实测)
|
||||
### 3.4 并发语义与本设计的配合(实现实测)
|
||||
|
||||
轮询 `HAL_UART_Transmit`(`stm32f4xx_hal_uart.c:1135`):`gState READY → BUSY_TX(全程)→ READY`;并发调用见非 READY **立即**返回 `HAL_BUSY`(不排队)。本设计的三个运行区间:
|
||||
写者**已注册**后(稳态):任务上下文唯一调用者 = 写者(`defaultTask`),零竞争;残余窗口 = ISR 直发撞写者发送中(丢失、不挂死,§7)。
|
||||
|
||||
写者**未注册**期(内核启动 → `defaultTask` `attach`,时长取决于存储 bring-up,通常秒级):`con_append` 走 `dbg_console_write_raw` → `con_tx_bounded`(**寄存器级轮询 TXE/TC,无 `gState` 锁**,见 §4.4)。⚠ **2026-10-10 起此路径无互斥**——旧实现走 `HAL_UART_Transmit`,其 `gState` 检查跨整行保持、竞争失败方立即 `HAL_BUSY`,故当时"只丢不交错";改为寄存器级轮询后该保证**不再成立**:两个任务同时裸发会**逐字节交错**(2026-10-10 台架实测:`adcTask` 首帧日志与 `defaultTask` 的 `[NAND_FTL]` 初始化行交错)。
|
||||
|
||||
| 区间 | 发送者构成 | 并发行为 |
|
||||
|------|-----------|---------|
|
||||
| 内核启动前 | 仅主线程(单线程) | 无并发,直发安全 |
|
||||
| 写者未注册(内核启动 → defaultTask attach,时长取决于存储 bring-up,通常秒级) | 多任务直发 | 竞争失败方立即 `HAL_BUSY` → **整行丢失(未计数、未告警)**;`gState` 检查跨整行保持 → **只丢不交错** |
|
||||
| 写者已注册(稳态) | 任务上下文唯一调用者 = 写者 | 任务上下文零竞争;残余窗口 = ISR 直发撞写者发送中(立即返回、丢失、不挂死,§7) |
|
||||
| 写者未注册(内核启动 → attach) | **约定只有 `defaultTask` 记日志** | 遵守约定 → 无并发;**其他任务此时记日志 → 逐字节交错**(裸发无互斥) |
|
||||
| 写者已注册(稳态) | 任务上下文唯一调用者 = 写者 | 任务上下文零竞争;残余窗口 = ISR 直发撞写者发送中(丢失、不挂死,§7) |
|
||||
|
||||
**纪律(2026-10-10 固化)**:周期 / 常驻任务**不得**在写者注册前记日志——用 `dbg_console_writer_ready()`(§5)门控自身日志(`adcTask` 的首帧与 10 s 心跳即按此门控)。内核前代码仍可直接裸发(单线程,无并发)。
|
||||
|
||||
## 4. 详细设计
|
||||
|
||||
@@ -196,6 +200,7 @@ sequenceDiagram
|
||||
- 有界:`len > 256 → 256`(截尾);发送走 `con_tx_bounded`(**寄存器级轮询 TXE/TC**,超时判据 = DWT `CYCCNT`,`CON_TX_TIMEOUT_CYC` = 100 ms 对应周期数),不持临界区、不等待状态;
|
||||
- **2026-10-10:DWT 不可用时改走 `con_tx_counted`(指令计数上界 `CON_TX_GUARD_MAX`),不再回退 `HAL_UART_Transmit`**。两个理由:① HAL 的超时判据是 `HAL_GetTick`——断言/停摆现场 tick 未必在走;② `HAL_UART_Transmit → UART_WaitOnFlagUntilTimeout` 这条尾巴会被 armlink 挂进**每个**碰日志的任务的最坏栈链(`configASSERT` 在 FreeRTOS 内部可达 → 三个内核钩子都在链尾),实测每条链多背 64 B;
|
||||
- 适用:内核前 / 未注册期、ISR、异常钩子(栈溢出 / 堆失败)、崩溃上报;
|
||||
- **调用方纪律(2026-10-10 补充)**:`con_tx_bounded` **无互斥**(寄存器级轮询,无 `HAL` 的 `gState` 锁)→ 写者注册前**只允许 `defaultTask`**(存储 bring-up 阶段)走此路径;其他常驻任务须用 `dbg_console_writer_ready()` 门控日志(见 §3.4)。
|
||||
- 调用方纪律:**只交已知合法的缓冲**——钩子侧先做指针范围校验(Flash / SRAM / CCM 窗口)并拷入本地缓冲再发,TCB 指针不接触 UART(`Src/freertos.c vApplicationStackOverflowHook`,2026-09-24 加固;指针不可信时发占位文本,"上报崩溃的代码不能再崩一次")。2026-10-10 补充:钩子里的 `name[49]/num[16]` 改**函数级 static**(终点路径、打印完即复位,无并发)——放栈上会让这 81 B 出现在每个任务的最坏链上;行号转换改原地反转,去掉 `HAL_Delay`(`con_tx_bounded` 已等 TC)。
|
||||
|
||||
### 4.5 `fputc` 重定向(MicroLIB `printf`)
|
||||
@@ -224,6 +229,7 @@ sequenceDiagram
|
||||
| `dbg_console_write_line` | `int (const char *line, unsigned len)` | 生产者(任务上下文) | 整行入环 / 直发;0 = 写入字节数,-1 = 参数非法 / 被丢弃 | 截断 ≤192B(保行首时间戳/标记信息) |
|
||||
| `dbg_console_write_raw` | `void (const char *buf, unsigned len)` | **任意**(ISR / 钩子 / 内核前) | 有界直发 ≤256B,不等待、不加锁 | 缓冲须已知合法 |
|
||||
| `dbg_console_writer_attach` | `void (void)` | 写者任务、主循环前 | 注册唯一写者 | 仅一次(defaultTask) |
|
||||
| `dbg_console_writer_ready` | `uint8_t (void)` | 任意(常驻任务) | 写者是否已注册(1=已注册) | 2026-10-10 加:周期任务据此门控日志,避免写者注册前裸发交错(§3.4) |
|
||||
| `dbg_console_drain` | `void (void)` | **仅写者任务** | 排空环并发出 + 刷丢弃计数 | defaultTask 主循环周期调用 |
|
||||
| `dbg_console_dropped` | `uint32_t (void)` | 任意 | 诊断:累计丢弃行数 | 外部读取 |
|
||||
| `dbg_console_tx_fault_log_take` | `uint8_t (void)` | **仅写者任务** | 取并清"TX 故障待上报"标志 | 2026-10-10 加:drain 内**不得**调 `syslog_post`(会成环),由 defaultTask 在 drain 之外补记 run.log |
|
||||
@@ -249,8 +255,8 @@ sequenceDiagram
|
||||
|------|------|---------|---------|
|
||||
| 缓冲满(日志突发 / 写者卡滞) | 生产者等 200ms 后丢行 | `s_con_drop` 累计 → 写者刷 `[ERR] CONSOLE dropped N lines`(@test FAIL,永不静默) | — |
|
||||
| 写者未注册(内核前) | 单线程直发 | — | 无(无并发) |
|
||||
| 未注册期多任务并发直发 | 竞争失败方立即 `HAL_BUSY` → 整行丢失 | **未计数、未告警**(已知折中,§3.4 / §9-D5) | 启动窗口(秒级);2026-09-25 实测未发生 |
|
||||
| ISR 直发撞写者发送中 | 立即 `HAL_BUSY` 返回 → 丢失,不挂死 | 未计数 | ISR 日志频率极低,best-effort 语义 |
|
||||
| 未注册期其他任务直发 | **逐字节交错**(`con_tx_bounded` 无互斥,非旧 `HAL_BUSY`) | 交错行可致 `@test` 标记失配(2026-10-10 台架实证) | 已固化纪律:周期任务用 `dbg_console_writer_ready()` 门控(§3.4 / §9-D5) |
|
||||
| ISR 直发撞写者发送中 | 与写者发送竞争 → 丢失,不挂死 | 未计数 | ISR 日志频率极低,best-effort 语义 |
|
||||
| 内核状态损坏(栈溢出 / 堆耗尽) | 钩子裸发固定文本 → 复位(栈溢出)/ 仅告警(堆) | `[ERR] STACK OVERFLOW task=…` / `[ERR] MALLOC FAILED …`;任务名范围校验 + 本地拷贝,TCB 指针不入 UART | — |
|
||||
| 调用方指针损坏(脏指针) | 无法进入 UART(缓冲恒为环 / 模块本地) | 2026-09-24 HardFault 路径结构性消除 | — |
|
||||
| UART 物理失效(发送卡死 / 超时) | `con_tx_bounded` 在 DWT 上界内返回 `HAL_TIMEOUT` → 该块丢弃 + **UART 重初始化**(僵尸通道自愈,§12) | 2026-10-10 起:drain 内**只置标志** `s_con_tx_fault_log`,由 defaultTask 在 drain 之外 `syslog_post(SYSLOG_RUN, "console tx fault, uart reinit")` 补记 run.log(旧实现直接在 drain 里调 `syslog_post` → `write_line → con_append → drain → syslog_post → write_line` **调用图成环**,静态栈在每个任务上多叠一条日志尾巴) | 已知缺口:丢弃计数与故障计数不分离 |
|
||||
@@ -276,7 +282,7 @@ sequenceDiagram
|
||||
| D2 | 整行 `HAL_UART_Transmit` + `gState` 检查 | 消除交错,但不解决脏指针(调用方缓冲仍入 UART);竞争失败方无等待/重试,整行静默丢;调用方阻塞时长不受控(等 UART 物理速率) |
|
||||
| D3 | 专用日志任务 | 违反 G3(RAM 紧张不新增任务/栈);defaultTask 本就是存储子系统唯一写者,单写者纪律收敛到同一任务,且主循环已是 50ms 事件驱动 |
|
||||
| D4 | TX DMA / 中断驱动发送 | 发送率低(115200、日志行稀疏),收益不足;不解决 G2(DMA 同样读调用方缓冲);DMA 缓冲可达性 / 所有权 / 双缓冲复杂度不值 |
|
||||
| D5 | 环 + 直发双路径(**采纳**) | 注册稳态走环(零丢失、有计数);内核前 / ISR / 钩子走有界直发(G4:不等待、不死锁、零内核对象);未注册期"只丢不交错、未计数"是 K1/K3 约束下的代价,启动窗口秒级、实测未发生(§3.4) |
|
||||
| D5 | 环 + 直发双路径(**采纳**) | 注册稳态走环(零丢失、有计数);内核前 / ISR / 钩子走有界直发(G4:不等待、不死锁、零内核对象);未注册期此路径**无互斥**(2026-10-10 起为寄存器级轮询,无 `HAL` `gState`)→ 约定**只有 defaultTask** 记日志,其他常驻任务用 `dbg_console_writer_ready()` 门控(§3.4) |
|
||||
| D6 | 每生产者 SPSC 无锁队列 | 多生产者仍需 MPMC;单环 + 临界区整行拷贝更简,生产者临界区 ≤192B 微秒级;事件位复用免新增内核对象 |
|
||||
| D7 | `printf` 保为主路径 | MicroLIB 逐字符回调开销 + 遗留语义;`DBG_*` 宏调用点格式化整行一次入环(一次入环、一次事件) |
|
||||
|
||||
@@ -300,6 +306,7 @@ sequenceDiagram
|
||||
| 2026-09-25 | 写者任务体迁出:`Src/freertos.c` 的 `StartDefaultTask` 任务体(存储 bring-up / 配置引擎 / 控制台 attach+drain / syslog / LED / 栈水位)整体移入 `App/task/default_task.c`(`default_task_func()`,与其余 5 任务文件同址);`freertos.c` 恢复"接线 + 崩溃钩子"的 CubeMX 形态(719→361 行);行为零变化,`@build` 0/0 + `@test` PASS 复验 |
|
||||
| 2026-10-02 | **ORE 僵尸通道喂狗节奏保护**(台架 gen-288):round-3 的"单次 drain 预算 250ms"只限单次调用——ORE 锁存在外设软复位后**毫秒级重锁**(PA10 悬空 + RX 使能),背靠背 drain 每轮再耗 100ms 块超时 → 主循环周期拉到 450~500ms → 100ms 节流的喂狗抽样间隙超过 IWDG 最坏容限 1.7s → 停喂 → 误复位(且心跳位全员健康、无 stall 日志,纯**节奏性饥饿**,非死等)。修复:发送故障后立即结束本轮 drain 并进入 300ms 发送冷却(冷却期内 drain 直接让位主循环),保证喂狗节奏 ≤ ~300ms |
|
||||
| 2026-10-02 | **round 8b 加固**:发送超时判据改用 DWT `CYCCNT`(时间源无关)。原 `HAL_UART_Transmit` 的 `HAL_GetTick() - Tickstart` 依赖 TIM7 的 `uwTick`,TIM7 一旦停摆超时永不成立 → 写者死等 TXE → 唯一喂狗者停摆 → IWDG 复位。裸发送与缓冲满等待两处均换成 DWT 周期计数硬上界(DWT 使能失败时退回旧 HAL 行为);另加 `huart1.Instance == NULL` 短路,防早期/断言路径解引用 NULL |
|
||||
| 2026-10-10 | **新增 `dbg_console_writer_ready()` + 未注册期纪律固化**:裸发为寄存器级轮询(无 `gState`)→ 未注册期多任务并发**逐字节交错**(台架 `adcTask` 首帧日志与 `[NAND_FTL]` 行交错实证)。新增 `dbg_console_writer_ready()` 供周期任务门控;`adcTask` 首帧/心跳日志据此门控(§3.4 / §4.4) |
|
||||
|
||||
## 12. ORE 僵尸通道(2026-10-02 台架实证)
|
||||
|
||||
@@ -322,7 +329,7 @@ sequenceDiagram
|
||||
|
||||
| # | 项 | 说明 |
|
||||
|---|----|------|
|
||||
| O1 | 未注册期窗口丢行未计数 | 启动窗口(内核启动 → attach)直发竞争丢整行且无计数(HAL `HAL_BUSY` 立即返回);若未来开机日志密度上升,可升级为"内核前静态待发行 + attach 后统一补发"或有界等待直发 |
|
||||
| O1 | 未注册期裸发无互斥 | 启动窗口(内核启动 → attach)`dbg_console_write_raw` 无互斥 → 多任务并发会**逐字节交错**(非旧 `HAL_BUSY` 丢整行)。2026-10-10 已固化"周期任务用 `dbg_console_writer_ready()` 门控"纪律;若未来开机日志密度上升,可升级为"内核前静态待发行 + attach 后统一补发"或给裸发加轻量互斥 |
|
||||
| O2 | `HAL_UART_Transmit` 超时未计数 | 超时块(UART 物理失效)丢弃但不入 `s_con_drop`;v2 可加独立超时计数 |
|
||||
| O3 | `printf` 逐字节开销 | 遗留 `printf` 路径 = 逐字节临界区 + 逐字节事件置位;遗留调用点全部切 `DBG_*` 宏后开销自然消失(不改变机制) |
|
||||
| O4 | **ORE 僵尸未根治** | §12:现仅有缓解(250ms 预算 / 300ms 冷却 / DWT 超时),机制根源是 USART1 使能了 RX。根治需 `.ioc` 改 TX-only + CubeMX 重生成 → 已登记 `待处理内容.md` **S-3** |
|
||||
@@ -343,3 +350,4 @@ sequenceDiagram
|
||||
| v1.1 | 2026-09-25 | 文件拆分同步:写者任务体迁至 `App/task/default_task.c`(`Src/freertos.c` 只留 CubeMX 接线与崩溃钩子);§3.2 文件清单 / §4.3 / §6 / §11 位置引用更新 |
|
||||
| v1.2 | 2026-10-02 | 新增 §12 ORE 僵尸通道(台架 gen-288 实证:节奏性喂狗饥饿,非死等;缓解已做、TX-only 根治待办)+ §11 时间线两条 10-02 记录;§13 新增 O4;原 §12/§13 顺延为 §13/§14 |
|
||||
| v1.3 | 2026-10-10 | 栈链整改(**未抬栈**)三处:① 裸发改为纯寄存器轮询——DWT 不可用时走 `con_tx_counted`(计数上界),**不再回退 `HAL_UART_Transmit`**(tick 依赖不可信 + 其调用链污染所有任务最坏栈链);② 切断 `drain → syslog_post → write_line` **调用图成环**,改为置标志 + 写者任务在 drain 之外补记(新 API `dbg_console_tx_fault_log_take`);③ 行缓冲按模块可收紧(`dbg_log.h` 新增 `DBG_LINE_BUF_MAX`,深链模块 128)+ 时间戳缓冲并入行缓冲(32 → 24)。§4.4 / §5 / §6 / §7 / §8 同步;实测 defaultTask 静态最坏链 5312 → 2776 B |
|
||||
| v1.4 | 2026-10-10 | 新增 `dbg_console_writer_ready()`(写者就绪查询)并固化"未注册期只有 defaultTask 记日志、周期任务用就绪门控"纪律;更正 §3.4 / §7 / §9-D5 / §13-O1 的"只丢不交错"旧结论(裸发已改寄存器级轮询、无 `gState` 互斥) |
|
||||
|
||||
@@ -498,7 +498,7 @@ snapshot == required → miss_streak=0、证据门闩复位、喂狗
|
||||
- `Src/iwdg.c`:`USER CODE BEGIN 0` 放空实现 + `#define HAL_IWDG_Init(a_h) iwdg_deferred_start(a_h)` → 生成区原样、**重生成零 diff**(§2.4)。
|
||||
- `Src/stm32f4xx_it.c`:4 个 `__asm void X_Handler` 放 `USER CODE BEGIN 0`,**必须写在 4 个 `#define X X_Gen` 之前**(写在之后会被自己的宏改名);生成实体经宏改名让位,链接器自动移除(`.map` 各 `Removing … (2 bytes)`),向量表仍指向我们的 `__asm` 版。
|
||||
|
||||
> **L3 清单已清空**:所有定制要么在 `.ioc`(L1)、要么在 `USER CODE` 区(L2)——**重生成应当零 diff**。剩余 1 项 WARN 是 `Src/freertos.c` 的 `timeSyncTask` 手工定义(属性块在 `USER CODE BEGIN Variables` 区,本身受保护,WARN 只提示"它不在 `.ioc` 里")。**`adcTask`(B1,2026-10-10)同为手工定义**——属性块在同区、`osThreadNew` 在 `USER CODE BEGIN RTOS_THREADS` 区,同样受保护、同样不在 `.ioc` 里(B1 原计划走 L1,实际按 timeSyncTask 先例落 L2:避免为单任务触发全工程重生成;详见 `待处理内容.md` §3.1 P1-1)。
|
||||
> **L3 清单已清空**:所有定制要么在 `.ioc`(L1)、要么在 `USER CODE` 区(L2)——**重生成应当零 diff**。剩余 1 项 WARN 是 `Src/freertos.c` 的 `timeSyncTask` 手工定义(属性块在 `USER CODE BEGIN Variables` 区,本身受保护,WARN 只提示"它不在 `.ioc` 里")。**`adcTask`(B1,2026-10-10)同为手工定义**——属性块在同区、`osThreadNew` 在 `USER CODE BEGIN RTOS_THREADS` 区,同样受保护、同样不在 `.ioc` 里(B1 原计划走 L1,实际按 timeSyncTask 先例落 L2:避免为单任务触发全工程重生成)。
|
||||
|
||||
**为什么 `fault_handler_enable()`(SHCSR 使能三位)写不进 `.ioc`**(2026-10-01 查模板源码三重证据):① `tpl_main_c.ftl` 的 `MX_NVIC_Init()` 只在 `systemHandler=="false"` 时生成 `HAL_NVIC_EnableIRQ`,而三个 Fault 在 `NVIC-STM32F417_Modes.xml` 都标 `Y`;② 全部模板中 `SHCSR` 只出现 1 次且是 MPU 清理的 `&= ~MEMFAULTENA`(禁用),无任何 `|=`;③ `.ioc` 无 MPU,且 `HAL_MPU_Enable` 只置 `MEMFAULTENA` 一位。⚠ `.ioc` 的 `NVIC.MemoryManagement_IRQn=true` **不代表已使能**(只是向量可见)。现走 L2(`USER CODE BEGIN 1`)+ 审计项兜底。
|
||||
|
||||
@@ -571,4 +571,5 @@ python scripts/check_cubemx_survival.py --write # 确认改动无误后重建
|
||||
| 2026-10-09 | **IWDG 延后启动由 L3 升级为 L2:不再需要每次重生成后手工删那一句** | 起因是提问"能否在初始化函数下方的自定义区里先反初始化"。查证:**反初始化不可行**——IWDG 一旦启动就**无法停止**(参考手册:唯一停止手段是复位),故不能在 `IWDG_Init 2` 区撤销。改用等价且免手工的做法:`Src/iwdg.c` 的 `USER CODE BEGIN 0`(标准保护位)放空实现 `iwdg_deferred_start()` + `#define HAL_IWDG_Init(a_h) iwdg_deferred_start(a_h)`,把**本编译单元里**那句生成调用 `HAL_IWDG_Init(&hiwdg)` 改名到空实现 → 生成区保持 CubeMX 原样、**重生成零 diff**。`.map` 证实 `Removing stm32f4xx_hal_iwdg.o(i.HAL_IWDG_Init), (94 bytes)`、`iwdg.o(i.MX_IWDG_Init)` 只引用 `.bss`(空实现被编译器消掉)。审计项 `iwdg-defer-start` 相应由 `wholefile`+锚点注释改为 `protected`(区 `0`)+ 代码符号断言(`iwdg_deferred_start` / `#define HAL_IWDG_Init`——`protected` 比对前会剥掉注释,锚点注释不能当断言)。§10.2 硬教训②与 L3 存量清单同步:L3 只剩 4 个 Fault Handler 实体(同一招可根治,尚未做)。`@build` 0 错误 0 警告;审计 21 通过 / 1 警告 / 0 失败 |
|
||||
| 2026-10-09 | **4 个 Fault Handler 由 L3 升级为 L2:重生成完全零 diff** | 用与 iwdg 同一招。`Src/stm32f4xx_it.c` 的 4 个 `__asm void X_Handler` 从**生成区**搬进 `USER CODE BEGIN 0`,且必须写在文件头那 4 个 `#define X X_Gen` **之前**(写在之后会被自己的宏改名);配套的 `#undef X` 随之删除(不再需要)。生成区恢复 CubeMX 原样(`void HardFault_Handler(void)` + `HardFault_IRQn 0` / `W1_HardFault_IRQn 0` 标记区),4 个锚点注释(`HARD-FAULT-ANCHOR` / `MEMFAULT-ANCHOR` / `BUSFAULT-ANCHOR` / `USAGEFAULT-ANCHOR`)全部退役。`.map` 复核:`startup_stm32f407xx.o(RESET) refers to stm32f4xx_it.o(.emb_text) for HardFault_Handler`(向量表仍指向我们的 `__asm` 版)、`.emb_text → i.fault_entry_* → i.hard_fault_report`、4 个 `*_Gen` 各 `Removing ... (2 bytes)`。审计项 `hardfault-handler` / `fault-handlers-3` 由 `wholefile`+锚点改为 `protected`(区 `0`)+ 代码符号断言。**L3 清单清空**,重生成预期零 diff。`@build` 0 错误 0 警告;审计 21 通过 / 1 警告 / 0 失败 |
|
||||
| 2026-10-10 | **正文按当前代码重写(清理立项前的描述)** | 正文原样保留了大量**立项前(2026-09-29)**的状态取证与已废弃的"路径 C 考古",与现状矛盾,故重写为现状设计说明(1144 → 571 行;**历史与逐次决策全部保留在下方变更记录,未删**)。主要更正:① §1.1"现状:无任何硬件看门狗"改为**历史背景**(IWDG 已在 `.ioc`/`hal_conf`/工程三处就位);② **ftpTask 早已纳入监视**——经 `lftpd_task_wd_beat()` 弱钩子(事件循环 / RETR·STOR 分片 / 连接与卷锁等待),旧正文"首期不埋点、由掩码剔除"及 R3/O1 已作废;③ 补齐正文缺失的三块现状实现:**FTL 心跳路由**(`task_wd_bind()` + `nand_ftl_wd_beat()`)、**FTL 直接喂狗**(`nand_ftl_wd_feed()`,含"设备存活但功能冻结"边界)、**round 7/8/8b 取证机制**(`/log/wdev.log`、`.noinit` 槽 + `UNINIT_CCM`、`PREVRUN`/`TICKRUN`/`MISS start`/`STALL`);④ 掩码改为按代码实况列表(产品 `0x37` / `ENABLE_HW_LAYER_TESTS` `0x35` / **testTask 任何构建都不入掩码**)并写明"精确相等"语义;⑤ 复位原因优先级按 `reset_cause_str()` 实际顺序改写(旧表把 POR 排第一,代码是 **IWDG 最优先**);⑥ §4.6 更正为**已集成**:看门狗复位写 `selftest.log`(旧正文"未改");⑦ §8 预算改用 `.map` 实测(`task_watchdog.o` 1098 B 代码 / 44+104 B RAM / `.noinit` 48 B;`iwdg.o` 仅 28 B,`HAL_IWDG_Init` 94 B 被移除);⑧ 附录 B 自相矛盾修正(旧表把"借助 CubeMX"列为否决,实际已选它);⑨ §7 由"验证计划"改为**验证记录**(V2/V4/V5 ✅、U1 39 断言 ✅,V3/V6/V7 标为未单独注入、V8 未做)。连带同步:`Src/iwdg.c`、`Src/freertos.c`、`App/task/default_task.c` 三处注释的章节引用(旧 §4.5/§4.6 → 新 §4.1/§4.4),`scripts/check_cubemx_survival.py` 提示语(§10.1 → §10.2/§10.3),`实机测试实施指南.md`(§10 → §7 ×3)、`看门狗单元测试说明.md`(§10 → §7)、`模拟器差距清单.md` H-1(§4.9 → §4.7,并更正"模拟器不编译本模块、无 IWDG 桩")、`docs/README.md`("实施中/待验证" → 已闭环)。⚠️ **下方历史行里的 §x.y 引用指当时编号**,不再回溯改写 |
|
||||
| 2026-10-10 | **adcTask 纳入监视(B1):必需掩码 `0x37`→`0x77`** | B1(ADC 采集链路)落地时新增 `adcTask`(`App/task/adc_task.c`:1 ms 采样节拍触发 CONVST + 消费 `tpafe5160_snapshot()`)并纳入 IWDG 监视:`task_wd_id_t` 新增 `TASK_WD_ADC = 6`;`wd_required_mask()` 产品 `0x37`→`0x77`、`ENABLE_HW_LAYER_TESTS` `0x35`→`0x75`(adcTask **不依赖任何就绪屏障** → 任何构建都置位)。adcTask 主循环每 1 ms `task_wd_beat(TASK_WD_ADC)`;**不做 NAND I/O → 不登记 FTL 心跳路由**(无需 `task_wd_bind()`)。主机侧单测 `beat_all()` 与掩码断言(`tc_003`/`tc_005`/`tc_011` 的 `0x37`→`0x77`)同步,39 断言全绿。任务由 `Src/freertos.c` 的 `USER CODE` 区手工创建(同 timeSyncTask,不在 `.ioc` 里),栈 512 words、优先级 Normal,`stack_report.py` 实测最坏链 504 B(余 1544 B / 75%)。见 `docs/算法/继电保护功能复现规划.md` §7 / `待处理内容.md` B1 |
|
||||
| 2026-10-10 | **adcTask 纳入监视(B1):必需掩码 `0x37`→`0x77`** | B1(ADC 采集链路)落地时新增 `adcTask`(`App/task/adc_task.c`:1 ms 采样节拍触发 CONVST + 消费 `tpafe5160_snapshot()`)并纳入 IWDG 监视:`task_wd_id_t` 新增 `TASK_WD_ADC = 6`;`wd_required_mask()` 产品 `0x37`→`0x77`、`ENABLE_HW_LAYER_TESTS` `0x35`→`0x75`(adcTask **不依赖任何就绪屏障** → 任何构建都置位)。adcTask 主循环每 1 ms `task_wd_beat(TASK_WD_ADC)`;**不做 NAND I/O → 不登记 FTL 心跳路由**(无需 `task_wd_bind()`)。主机侧单测 `beat_all()` 与掩码断言(`tc_003`/`tc_005`/`tc_011` 的 `0x37`→`0x77`)同步,39 断言全绿。任务由 `Src/freertos.c` 的 `USER CODE` 区手工创建(同 timeSyncTask,不在 `.ioc` 里),栈 512 words、优先级 Normal,`stack_report.py` 实测最坏链 504 B(余 1544 B / 75%)。见 `docs/算法/继电保护功能复现规划.md` §7 |
|
||||
| 2026-10-10 | **B1 `@test` 实机闭环:adcTask 掩码真机验证** | 台架闭环(`test/host/run_boot_test.py`)确认 `adcTask` 纳入掩码后**无 adc 相关误复位**:`[STACK] adc peak_used=496/2048 free_min=1552 (75%)`、`frames/seq` 每 10 s 严格 +10000(=1000 Hz)、`idle=0`/`frst_err=0`、全片回读 `No difference found`。启动早期两次 `MISS start snap=0x67 req=0x77` 仅缺 bit4(`timeSync` 未启动,属正常就绪窗;adc 的 bit6 自始置位),掩码随后收敛、全程无复位。同轮另修 `dbg_console_writer_ready()` 门控(adcTask 周期日志在写者注册前抑制,见 `控制台单写者日志设计说明.md`) |
|
||||
|
||||
+17
-27
@@ -37,7 +37,7 @@
|
||||
|
||||
| 级别 | 数量 | 关键项 |
|
||||
|---|---|---|
|
||||
| **P1** | 0 (+2 收尾) | **P1-1 ADC 采样路径**(✅ 已实现,剩 `@test` 实机闭环);P1-10 测试固件构建实测闭环(主体已闭环,见 §3.1) |
|
||||
| **P1** | 0 (+1 收尾) | P1-10 测试固件构建实测闭环(主体已闭环,见 §3.1) |
|
||||
| 登记簿 | 9 | 网络:N-2(49s 日志静默,**低风险观察项**)、N-3(L5 基线重验)、N-4(pending 二期)、N-16(A2/A4 专项负向验证)、N-17(探针窗口心跳缺口);存储/日志:**S-3(USART1 TX-only 根治)**、S-4(dhara 重试自旋)、S-5(可选全序列卷锁);硬件:**N-18(8 路电气量分属两转换器 = V0.1 缺陷,V0.2 改版项)** |
|
||||
| 测试/基础设施 | 5 | T-7(CI runner 未就绪)+ 测试架构专项 **S12**(断言宏)、**S1-c**(可选单测)、**A-4**(采集链路测试约束)、**A-5 残余**(CI 体积门禁盲区) |
|
||||
|
||||
@@ -48,10 +48,10 @@
|
||||
|
||||
1. **网络层已是全项目最成熟子系统**(pending 机制 + 四份 Trap 记录 + 量化基线 + 探针族)。
|
||||
剩余网络工作都是"二期扩展/收口",**没有紧急项**。
|
||||
2. **产品功能缺口正在收口:ADC 采集链路(B1)已实现,RS-485(B2)仍为空桩**。
|
||||
`adc_task` 已由空桩转为真实消费者(2026-10-10,剩 `@test` 实机闭环);`rs485_task` 仍为空桩,
|
||||
且受 E-59 门禁挡住(E-50 / E-49 未修)。DTU 的核心职责(数据采集与转发)中,**采集侧还差
|
||||
RS-485 一路**——这既是 P1-1 已修复后的剩余,也是 E-59 那条"休眠缺陷闸门"的另一面。
|
||||
2. **产品功能缺口正在收口:ADC 采集链路(B1)已闭环,RS-485(B2)仍为空桩**。
|
||||
`adc_task` 已由空桩转为真实消费者并 `@test` 实机闭环(2026-10-10:`frame_seq` 严格 1000 Hz
|
||||
递增、`idle=0`、`frst_err=0`);`rs485_task` 仍为空桩,且受 E-59 门禁挡住(E-50 / E-49 未修)。
|
||||
DTU 的核心职责(数据采集与转发)中,**采集侧还差 RS-485 一路**——即 E-59 那条"休眠缺陷闸门"的另一面。
|
||||
3. **验证债已基本还清,重心是"功能债"**:剩余验证债仅 **N-3(L5 基线重锁,待 PC peer)**
|
||||
(原 **S-1 栈风险已于 2026-10-10 削链闭环并销项**:defaultTask 静态最坏链 5312 → 2776 B、
|
||||
实测峰值 3392 → 2152 B,**未抬栈**,见 `docs/内存管理/RAM使用分析与优化方案.md`)。
|
||||
@@ -71,16 +71,15 @@
|
||||
> 持续采集 / **1000 Hz(20 点/周波)** / RS-485 **对下 ModBus RTU 采集**;结论详见
|
||||
> `docs/算法/继电保护功能复现规划.md` §1.5,并已同步 `docs/产品需求/产品需求设计文档.md` §5.9/§5.10/§9。
|
||||
> **B3(纪律门禁)已于 2026-10-10 固化进 `AGENTS.md` 并销项**;同日 TPAFE 侧前置缺陷
|
||||
> **E-44 / E-45 / E-58 全部修复** → **B1(ADC 采集链路)已于 2026-10-10 实现**
|
||||
> (`adc_task` 真实消费者 + 建任务 + 栈预算,剩 `@test` 实机闭环);
|
||||
> **E-44 / E-45 / E-58 全部修复** → **B1(ADC 采集链路)已于 2026-10-10 实现并 `@test`
|
||||
> 实机闭环销项**(`adc_task` 真实消费者 + 建任务 + 栈预算 + 台架 1000 Hz 确认);
|
||||
> B2 仍欠 **E-50 / E-49**(RS485 驱动契约未修,门禁仍挡着)。
|
||||
|
||||
| 序 | 任务 | 前置 | 说明 |
|
||||
|---|---|---|---|
|
||||
| **B1** | **ADC 采集链路实现**(消化 P1-1;E-58 已闭环) | B0 ✅ + **E-59 门禁**(TPAFE 侧已满足) | ✅ **已实现(2026-10-10)**:`adc_task` 由空桩转为真实消费者——每 1 ms 触发 `tpafe5160_start_conv_irq()` + `tpafe5160_snapshot()` 原子取数(AGENTS 铁律)+ 帧统计 + 每 10 s 心跳日志;任务在 `Src/freertos.c` 手工创建(**同 timeSyncTask,落 `USER CODE` 受保护区**;不采用 L1/`.ioc`——见 §3.1 P1-1 说明)、栈 **512 words / Normal**、纳入 IWDG 必需掩码(`TASK_WD_ADC`,产品 `0x37`→`0x77`);`stack_report.py` 静态最坏链 **504 B(余 1544 B / 75%)**、`@build` 0/0、看门狗主机单测 39 断言全绿。**剩余 = `@test` 实机闭环**(确认 BUSY 连续脉冲 + `tpafe5160_frame_seq()` 持续递增)。⚠ 本阶段用**任务周期软触发**(`osDelayUntil`)产生采样节拍;**精确 1 kHz / 等周波调频**的硬件定时器触发为后续(需 CubeMX 加 TIM)。STM32 侧 ADC1(UB/UC/IB/IC/IN)仍无 `HAL_ADC_Start` → 按 N-18 此路仅逐通道独立监视、不做跨转换器运算,消费者为后续 |
|
||||
| **B2** | **RS-485 采集链路实现**(消化 E-50、E-49) | B0 ✅ + **E-59 门禁**(**尚未满足**:E-50 / E-49 未修) | 双缓冲 + 序号(防包撕裂)+ DE 收尾(超时路径等 TC)+ 协议状态机(`App/protocol/` 正是为此预留);**B0 定用途 = 对下 ModBus RTU 采集** |
|
||||
|
||||
**建议**:B1 已实现(剩 `@test` 实机闭环);下一步是 **B2**——但 B2 之前必须先修 **E-50 / E-49**(RS485 驱动契约未修,E-59 门禁仍挡着)。
|
||||
**建议**:B1 已闭环;下一步是 **B2**——但 B2 之前必须先修 **E-50 / E-49**(RS485 驱动契约未修,E-59 门禁仍挡着)。
|
||||
|
||||
### 2.2 阶段 C:结构债清理(二期)+ 存储侧健壮性
|
||||
|
||||
@@ -115,16 +114,7 @@
|
||||
|
||||
## 3. 待办详述
|
||||
|
||||
### 3.1 P1(2 项收尾:均剩 `@test` 实机闭环)
|
||||
|
||||
#### P1-1 ADC 采样数据路径产品构建中死亡(✅ 已实现,剩 `@test` 实机闭环)
|
||||
- **位置**:`App/app/app_main.c`(`tpafe5160_start_conv_irq()` 仅启动时调用一次)+ `Drivers/BSP/TPAFE5160/tpafe5160.c` + `App/task/adc_task.c`
|
||||
- **证据(原)**:启动序列调用一次 `tpafe5160_start_conv_irq()`;全仓库无周期性 CONVST 重触发;`tpafe5160_snapshot()` 无任何消费者(`adc_task.c` 是空桩);STM32 侧 ADC1 已生成却**全仓库无 `HAL_ADC_Start`**(一路彻底未跑)。
|
||||
- **影响**:上电后仅采集 1 个样本,此后数据永久陈旧;且 `APP_ADC_ENABLE` 为未接线占位(已如实标注,不再冒充开关),形成"看似启用实则失效"的假象。
|
||||
- **修复落地(2026-10-10,B1)**:**驱动侧取数契约已修**(E-44 FRSTDATA 有效性校验 + `init()` 首帧自检、E-45 帧序号、E-58 原子快照,索引见 `docs/问题记录/错误码传播审计.md` §2.2);**消费者本体**:`adc_task.c` 由空桩改为真实消费者——每 1 ms 触发一次 CONVST + `tpafe5160_snapshot()` 原子取数 + 帧统计 + 每 10 s 心跳日志;**建任务**:在 `Src/freertos.c` 的 `USER CODE` 区手工创建 `adcTask`(512 words / Normal)。**取数索引按 `docs/硬件平台/ADC通道映射说明.md`**(TPAFE `buf[2]=IA`/`buf[5]=UN`/`buf[6]=UA`)。
|
||||
- **为何不用 L1(`.ioc` 的 `FREERTOS.Tasks01`)**:属性块落 `USER CODE BEGIN Variables`、创建调用落 `USER CODE BEGIN RTOS_THREADS`——二者均为 CubeMX 保护模板区(同 `timeSyncTask`,见 `docs/子系统设计/看门狗设计说明.md` §10.3),**重生成不丢**;且避免为单一任务触发一次全工程重生成。若后续追求"GUI 可见",可再迁 L1。
|
||||
- **剩余**:`@test` 实机闭环(确认 `tpafe5160_frame_seq()` 持续递增、BUSY 连续脉冲)。STM32 侧 ADC1(UB/UC/IB/IC/IN)仍无 `HAL_ADC_Start`——按 N-18 此路仅逐通道独立监视,消费者为后续(非本项)。
|
||||
- **置信度**:high(代码级确证 + `@build` 0/0 + `stack_report.py` PASS)。
|
||||
### 3.1 P1(1 项收尾:P1-10 剩构建实测闭环)
|
||||
|
||||
#### P1-10 测试固件静态 RAM 预算(基线已重建、测试缓冲已瘦身,剩构建实测闭环)
|
||||
- **位置**:`MDK-ARM/STM32F407-Demo/STM32F407-Demo.sct`(`RW_IRAM1 0x20000000 0x00020000` = 128KB;芯片 192KB 的上部 64KB 有意未映射,克隆芯片兼容性考量)
|
||||
@@ -157,7 +147,7 @@
|
||||
|
||||
| # | 事项 | 发现 | 证据与现状 | 出处 |
|
||||
|---|---|---|---|---|
|
||||
| N-18 | **8 路电气量分属两片转换器(V0.1 硬件缺陷,需下一版硬件修改)**——UA/UN/IA 走 TPAFE5160(16 位、8 通道同步、±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC(12 位、顺序扫描、0~3.3 V 单极性):① 两片转换器无共同采样触发 + STM32 侧顺序扫描(9 通道一轮 ≈ 67 µs)→ 跨转换器通道**无同一时刻性、相位关系不确定**,主板侧功率/功率因数/相角/对称分量类运算不成立;② 同族电气量精度与量程不一致(LSB ≈ 152.6 µV vs ≈ 806 µV,且 STM32 侧前端无中点偏置、负半周削顶);③ 语义与硬件归属交叉,固件映射/UI 通道序/自检注入须逐通道查表绕开 | 2026-10-10 定性更正(**撤销** 2026-10-09 建档时"有意分配、不要修正"的说法) | **V0.2 改版要求**:8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN **全部接 TPAFE5160**,与 TPAFE 上 5 路备用路(AIN5/13/7/15/12)对调串联电阻在转换器一侧的目的地——元件数量与料号不变,属走线级改动。**V0.1 现板软件口径**:主板侧只做逐通道独立监视,禁止跨转换器做相位/功率/功率因数/矢量类运算(此类量取子板计量模块结果)。固件侧尚无消费者(P1-1 / B1 未实现),实现时按语义映射表取数即可 → V0.2 改版只改映射表内容,上层语义与代码不动 | `硬件平台/ADC通道映射说明.md` §1/§7;`硬件平台/V0.1_网表详细分析报告.md` §1.4 V10、§6-3 |
|
||||
| N-18 | **8 路电气量分属两片转换器(V0.1 硬件缺陷,需下一版硬件修改)**——UA/UN/IA 走 TPAFE5160(16 位、8 通道同步、±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC(12 位、顺序扫描、0~3.3 V 单极性):① 两片转换器无共同采样触发 + STM32 侧顺序扫描(9 通道一轮 ≈ 67 µs)→ 跨转换器通道**无同一时刻性、相位关系不确定**,主板侧功率/功率因数/相角/对称分量类运算不成立;② 同族电气量精度与量程不一致(LSB ≈ 152.6 µV vs ≈ 806 µV,且 STM32 侧前端无中点偏置、负半周削顶);③ 语义与硬件归属交叉,固件映射/UI 通道序/自检注入须逐通道查表绕开 | 2026-10-10 定性更正(**撤销** 2026-10-09 建档时"有意分配、不要修正"的说法) | **V0.2 改版要求**:8 路电气量 UA/UB/UC/UN/IA/IB/IC/IN **全部接 TPAFE5160**,与 TPAFE 上 5 路备用路(AIN5/13/7/15/12)对调串联电阻在转换器一侧的目的地——元件数量与料号不变,属走线级改动。**V0.1 现板软件口径**:主板侧只做逐通道独立监视,禁止跨转换器做相位/功率/功率因数/矢量类运算(此类量取子板计量模块结果)。固件侧消费者已落地(B1,2026-10-10,按语义映射表取数)→ V0.2 改版只改映射表内容,上层语义与代码不动 | `硬件平台/ADC通道映射说明.md` §1/§7;`硬件平台/V0.1_网表详细分析报告.md` §1.4 V10、§6-3 |
|
||||
|
||||
**测试与验证基础设施**
|
||||
|
||||
@@ -179,7 +169,7 @@
|
||||
|---|---|---|---|
|
||||
| **S12** | 模块级轻量断言宏 | ⬜ 待做(第 4 波按需) | 3.3.1 |
|
||||
| **S1-c** | `sys_log` / `time_sync` 主机侧单测 | ⬜ 可选(价值递减) | 3.3.2 |
|
||||
| **A-4** | ADC / RS485 采集链路的**测试可验证性约束** | ⏸ 待 B1/B2 落地时执行 | 3.3.3 |
|
||||
| **A-4** | ADC / RS485 采集链路的**测试可验证性约束** | ⏸ ADC 侧随 B1 闭环;RS485 待 B2 | 3.3.3 |
|
||||
| **A-5 残余** | CI 体积门禁盲区(`mem-numbers` 在 CI 被跳过) | ⬜ 未消除 | 3.3.4 |
|
||||
|
||||
#### 3.3.1 S12:模块级轻量断言宏 ⬜
|
||||
@@ -221,8 +211,8 @@
|
||||
|
||||
#### 3.3.3 A-4:ADC / RS485 采集链路的测试可验证性约束 ⏸
|
||||
|
||||
**背景**:`adc_task.c` / `rs485_task.c` 仍是空桩,`App/protocol/` 只有 README 与 `.gitkeep`。
|
||||
本项不是"缺陷",而是**对上游 B1 / B2 的设计约束**——应在动手前明确,否则后续无法补测。
|
||||
**背景**:`adc_task.c` 已实现(B1,2026-10-10),`rs485_task.c` 仍是空桩,`App/protocol/` 只有 README 与 `.gitkeep`。
|
||||
本项不是"缺陷",而是**对上游 B2(B1 已完成)的设计约束**——应在动手前明确,否则后续无法补测。
|
||||
|
||||
**约束**(建议纳入 B1 / B2 设计):
|
||||
|
||||
@@ -233,7 +223,7 @@
|
||||
且**撕裂在单测里测不出来**(时序相关),必须在设计上消除;
|
||||
3. **DE 收尾必须有超时路径覆盖**(RS485 半双工特有陷阱)。
|
||||
|
||||
**完成判据**:B1 / B2 设计文档体现上述三条;协议解析函数有对应 L0.5 单测。
|
||||
**完成判据**:B2 设计文档体现上述三条;协议解析函数有对应 L0.5 单测。(B1 侧:ADC 无协议解析面,其"同一时刻性"由 E-58 原子快照保证、已闭环。)
|
||||
|
||||
#### 3.3.4 A-5 残余:CI 体积门禁盲区 ⬜
|
||||
|
||||
@@ -254,8 +244,8 @@ S14 已在 workflow 显式提示"体积门禁未执行"(`::notice::`)并在
|
||||
|
||||
## 4. 待确认(需手册/硬件/产品定义,暂不直接改码)
|
||||
|
||||
1. TPAFE5160 是否有自动扫描模式(决定 P1-1 定 P0 还是 P1)。
|
||||
2. `APP_ADC_ENABLE` / `APP_RS485_ENABLE` 是否应在产品构建真实门控模块(关联 P1-1;当前宏已如实标注为"未接线占位",此处确认的是**是否接入真实门控**)。
|
||||
1. TPAFE5160 是否有自动扫描模式(仅影响后续"硬件定时器 1 kHz 触发"方案选型;B1 已用周期 CONVST 软触发闭环,不再影响缺陷定级)。
|
||||
2. `APP_ADC_ENABLE` / `APP_RS485_ENABLE` 是否应在产品构建真实门控模块(当前宏已如实标注为"未接线占位",此处确认的是**是否接入真实门控**;B1 取数不依赖该宏)。
|
||||
3. RS-485 PD0 DE 的半双工方向语义需硬件实测确认(本次仅静态审查)。
|
||||
|
||||
---
|
||||
@@ -331,7 +321,7 @@ S14 已在 workflow 显式提示"体积门禁未执行"(`::notice::`)并在
|
||||
| ftpTask 栈峰值 | 740 / 4096(余 81%);静态 1216 B | 同上 |
|
||||
| uiTask 栈峰值 | 4016 / 16384(余 75%);静态 1336 B | 同上 |
|
||||
| timeSyncTask 栈峰值 | 792 / 2048(余量 61%) | 同上 |
|
||||
| adcTask 栈峰值(B1,2026-10-10 新建) | 未观测(待 `@test`);静态最坏链 **504 B**(余 1544 B / 75%) | `stack_report.py` |
|
||||
| adcTask 栈峰值(B1,2026-10-10 新建) | **496 / 2048**(余 1552 B / 75%,台架 `@test` 实测);静态最坏链 504 B | 台架 `@test` + `stack_report.py` |
|
||||
| testTask 栈峰值(产品态空转) | 496 / 8192(余量 93%) | 同上 |
|
||||
| 队列响应性(挂起客户端) | 92.5ms(pending 一期) | `e02_probe.py` |
|
||||
| M3 压力档帧周期 | med 60.1 / p95 66.4 / max 69.3ms,零尖峰 | `链路延迟测试说明.md` |
|
||||
|
||||
@@ -131,7 +131,7 @@ STM32(U17)为 LQFP144 脚号。
|
||||
| **通道归属(硬件缺陷)** | 8 路电气量分属两片转换器:UA/UN/IA → TPAFE,UB/UC/IB/IC/IN → STM32 ADC | **V0.1 硬件缺陷**(非有意分配,理由见 §1)→ V0.1 上禁止跨转换器做相位/功率/功率因数/矢量类运算;**V0.2 改版要求 8 路电气量全部走 TPAFE**(登记簿 N-18) |
|
||||
| STM32 ADC 外设 | **已生成(2026-10-09,CubeMX 6.17 + FW_F4)**:`Src/adc.c`/`Inc/adc.h` 已入库并挂进 `MDK-ARM/*.uvprojx`;`Inc/stm32f4xx_hal_conf.h` 的 `HAL_ADC_MODULE_ENABLED` 已生效;HAL `stm32f4xx_hal_adc.c/_ex.c` + `stm32f4xx_ll_adc.h` 已补入仓库(HAL 原本是裁剪子集);`Src/main.c` 里 `MX_ADC1_Init()` 排在 `MX_IWDG_Init()` 之后。生成配置核对无误:9 通道 / Rank 1~9 / 全部 144 cycles / `ScanConvMode=ENABLE` / `ContinuousConvMode=DISABLE` / `ExternalTrigConv=ADC_SOFTWARE_START` + `EDGE_NONE` / `EOCSelection=ADC_EOC_SINGLE_CONV` / `DataAlign=RIGHT` / 12 位;`HAL_ADC_MspInit()` 已把 PA0~PA7+PC4 配成 `GPIO_MODE_ANALOG` | 硬件通路已打通(`hadc1` 可用);**仍无消费者**——见下面两行 |
|
||||
| ADC 时钟 | CubeMX 的 F4 ADC 面板**有** Clock Prescaler 一项(此前"面板没有该项、固定 DIV2"的判断有误),已选 **PCLK2/4 → ADCCLK = 21 MHz** ✓。面板里 **DIV2 是灰的、选不到**:DB 里 `FadcConstraint Max=36000000`,APB2 = 84 MHz → DIV2 = 42 MHz 超限,该候选值被 `Action="DISABLE"` 禁掉,超规值进不来 | **不设额外防护(2026-10-09 决定)**:约束已由 CubeMX 把关;`.ioc` 虽不保存 `ADC1.ClockPrescaler` 键,重生成也只会回落到约束允许的值。按 144+12 cycles 算 ≈ 7.4 µs/通道、9 通道一轮 ≈ 67 µs |
|
||||
| `adc_task` | **空桩**:`App/task/adc_task.c` 只 `osDelay(1000)`;**2026-10-10 起已挂进 `MDK-ARM/*.uvprojx`**(此前 Keil/模拟器两边都不注册 = 永不编译,改它不生效;simulator 无任务层故只挂 Keil),任务仍未在 `Src/freertos.c` 创建 | 无消费者,数据路径死(登记簿 P1-1) |
|
||||
| `adc_task` | **已实现(B1,2026-10-10)**:`App/task/adc_task.c` 每 1 ms 触发 CONVST + `tpafe5160_snapshot()` 原子取数(8 通道)+ 帧统计;任务在 `Src/freertos.c` 的 `USER CODE` 区创建为 `adcTask`(512 words / Normal) | 数据路径已通(台架 `@test`:`frame_seq` 严格 1000 Hz 递增) |
|
||||
| TPAFE 采样触发 | `tpafe5160_start_conv_irq()` 仅在 `app_main_init` 调一次,**无周期 CONVST 重触发** | 只采到一帧,无连续波形 |
|
||||
| 前端偏置 | 每路 1k 串联 + 1k 到 `*_GND` + 滤波 C,**无中点偏置** | STM32 侧只能测 **0~3.3 V 单极性**,交流量负半周被削顶;主板侧只做监视可接受,若要算 RMS/功率需硬件补偏置或明确算法口径 |
|
||||
| TPAFE 量程 | 默认 ±5 V(RANGE 接 GND),16 位二进制补码,LSB ≈ 152.59 µV | 用 `tpafe5160_to_voltage()` 换算 |
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
> **参考来源**:`D:\Code\DTU\参考资料\huaiyuan\huaiyuan\Scatter_P_HV03.01_SV01.01\项目分析文档\04-算法与采样专题\ADC采集至数据使用全流程详解`(同专题另有《项目详细分析-交流采样与有效值计算》《傅氏算法详解》《项目详细分析-阶段6-继电器保护单元分析》)。
|
||||
> **阅读前提**:先读 `docs/算法/傅氏算法详解.md`(算法原理)与 `docs/硬件平台/ADC通道映射说明.md`(采样通道权威口径)。
|
||||
> **相关文档**:`docs/产品需求/产品需求设计文档.md`、`docs/待处理内容.md`、`docs/内存管理/RAM使用分析与优化方案.md`。
|
||||
> **状态**:规划稿——保护链路本体尚未实现;其前置的 **ADC 采集链路(`adc_task`)已于 2026-10-10 实现**(B1:周期 CONVST + 原子快照消费 + 建任务 + 栈预算,剩 `@test` 实机闭环),见登记簿 **P1-1 / B1**。
|
||||
> **状态**:规划稿——保护链路本体尚未实现;其前置的 **ADC 采集链路(`adc_task`)已于 2026-10-10 实现并 `@test` 实机闭环**(B1:周期 CONVST + 原子快照消费 + 建任务 + 栈预算 + 台架 1000 Hz 确认)。
|
||||
|
||||
---
|
||||
|
||||
@@ -65,9 +65,9 @@
|
||||
| 依赖 | 说明 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| **B0 产品定义** | 采集是否持续 / 采样率与通道 / 转发目标 / 保护元件清单——决定 B1 与保护层的**规模** | ✅ 已确认(2026-10-10,见 §1.5) |
|
||||
| **B1 ADC 采集链路** | 周期 CONVST + `adc_task` 消费 `tpafe5160_snapshot()` + 建任务 + 栈预算 | ✅ 已实现(2026-10-10;`adcTask` 512 words,剩 `@test` 实机闭环) |
|
||||
| **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` 已核算(静态 504 B / 余 1544 B / 75%);保护任务为后续 |
|
||||
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | 🔶 `adcTask` 已核算(静态 504 B / 余 75%;台架实测峰值 496/2048);保护任务为后续 |
|
||||
|
||||
### 1.5 B0 产品定义(2026-10-10 确认)
|
||||
|
||||
@@ -238,8 +238,8 @@
|
||||
|
||||
| # | 功能点 | 关键参数 | 完成判据 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| L1-1 | 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | 🔶 B1 已软触发(`osDelayUntil`);硬件定时器 1 kHz 为后续 |
|
||||
| L1-2 | TPAFE 快照消费 | 8 通道 / 帧 | `adc_task` 每拍调 `tpafe5160_snapshot()`,返回 1/0/-1 有处理 | ✅ B1 已实现(`adc_task.c`,剩 `@test`) |
|
||||
| L1-1 | 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | 🔶 B1 已软触发(`osDelayUntil`)并台架确认 `frame_seq` 严格 1000 Hz 递增;硬件定时器 1 kHz 为后续 |
|
||||
| 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` | ⬜ |
|
||||
| L1-5 | 通道标定(一次系数 + 零漂) | 每通道 `k`、`b`;系数定点 `2^10` | 注入标准源,读数误差 ≤ 目标精度 | ⬜ |
|
||||
@@ -592,4 +592,4 @@ B0 产品定义 ✅(2026-10-10 已确认,见 §1.5)
|
||||
| 2026-10-10 | 同步 B0 确认到下游章节 | §7.3 依赖图 B0 由"阻塞"改"已确认";§9 R1 由"B0 未定"改为"B0 残留待确认项(B0-a/b/c)" |
|
||||
| 2026-10-10 | B0 残留项闭环 + 新增 §1.6 范围评估 | B0-a **本期不做**(`UBA`/`V1`/`V2` 无硬件通道)、B0-b **保留 TCP 8888**(SNTP 5105 不做);B0-c **定为"骨架全做 + 有效通道子集闭环"**;新增 **§1.6** 由 V0.1 硬件(N-18 + 无中点偏置)推导本期可做保护范围 = TPAFE 三路(`UA`/`UN`/`IA`)有效子集;同步 §1.3、§3.3、§6.4(零序口径更正)、§7.1/§7.2、§9 R1 |
|
||||
| 2026-10-10 | 恢复被外部工具回写的旧稿 | 文件曾被外部格式化工具回写为旧稿:**§1.5/§1.6/§5 丢失、§10 混入 66 组下划线(u)标签、表格被填充对齐**。本次按权威来源重建 §1.5/§1.6、补齐 **§5 定值参数模型**,清除全部下划线标签并把表格压回仓库紧凑风格;内容与 §1.3/§3.3/§6.4/§7/§9 的定稿一致 |
|
||||
| 2026-10-10 | **B1 落地:ADC 采集链路实现** | `App/task/adc_task.c` 由空桩转为真实消费者——每 1 ms 触发 `tpafe5160_start_conv_irq()` + `tpafe5160_snapshot()` 原子取数 + 帧统计 + 每 10 s 心跳日志;`Src/freertos.c` 手工创建 `adcTask`(512 words / Normal,落 `USER CODE` 保护区)+ 纳入 IWDG 必需掩码(`TASK_WD_ADC`,`0x37`→`0x77`)。§1.4 采样软件行、§1.4 依赖表 B1 行、§3.2 任务表(L1-1/L1-2)、§4 栈预算行、§7.1 P0 行同步更新。⚠ 本阶段为**任务周期软触发**(`osDelayUntil`);硬件定时器 1 kHz 触发为后续。剩 `@test` 实机闭环 |
|
||||
| 2026-10-10 | **B1 落地:ADC 采集链路实现** | `App/task/adc_task.c` 由空桩转为真实消费者——每 1 ms 触发 `tpafe5160_start_conv_irq()` + `tpafe5160_snapshot()` 原子取数 + 帧统计 + 每 10 s 心跳日志;`Src/freertos.c` 手工创建 `adcTask`(512 words / Normal,落 `USER CODE` 保护区)+ 纳入 IWDG 必需掩码(`TASK_WD_ADC`,`0x37`→`0x77`)。§1.4 采样软件行、§1.4 依赖表 B1 行、§3.2 任务表(L1-1/L1-2)、§4 栈预算行、§7.1 P0 行同步更新。⚠ 本阶段为**任务周期软触发**(`osDelayUntil`);硬件定时器 1 kHz 触发为后续。同日 `@test` 实机闭环 PASS(`frame_seq` 严格 1000 Hz 递增、`idle=0`、`frst_err=0`、栈峰值 496/2048) |
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
**最值得先动的两件事**(2026-10-10 更新——原列的 **E-58 已闭环**,**E-34 / E-04 已闭环**,见 §2.2):
|
||||
|
||||
1. **E-59(P1,元发现)**——`adc_task` / `rs485_task` 均为空桩。TPAFE 侧契约缺陷
|
||||
1. **E-59(P1,元发现)**——`rs485_task` 仍为空桩(`adc_task` 已实现,B1 2026-10-10)。TPAFE 侧契约缺陷
|
||||
(**E-44 / E-45 / E-58**)已于 2026-10-10 **全部修复**,RS485 侧 **E-50 / E-49 仍未修**;
|
||||
门禁已固化进 `AGENTS.md`,接消费者前仍欠"栈预算 + RS485 双缓冲/序号"。
|
||||
2. **E-50(P2)**——RS485 单缓冲无 ISR/任务同步 → 读出跨两帧拼接的数据;与 E-59 同族,
|
||||
|
||||
Reference in New Issue
Block a user