feat(adc): B1 实现 ADC 采集链路(adcTask + 看门狗)
B1(ADC 采集链路)落地,消化 P1-1: - adc_task.c:空桩 -> 真实消费者。每 1ms 触发一次 CONVST, 用 tpafe5160_snapshot() 原子取数(AGENTS 铁律)+ 帧统计 + 每 10s 心跳日志。只取数,不做保护运算。 - Src/freertos.c:手工创建 adcTask(512 words / Normal,落 USER CODE 保护区,同 timeSyncTask 先例)。 - task_watchdog:新增 TASK_WD_ADC;required_mask 产品 0x37 -> 0x77、ENABLE_HW_LAYER_TESTS 0x35 -> 0x75。 - default_task.c:栈水位探针增列 adcTask(extern + 表项)。 - 脚本:stack_report.py 增 ROOTS/RUNTIME_ALIAS;gen_task_table 增 adcTask(README/AGENTS 任务表已 --write)。 - 单测:watchdog_test.c beat_all/掩码断言同步(39 断言全绿)。 - 文档:待处理内容/看门狗设计/RAM 方案/继保规划 同步。 验证:@build 0 错 0 警;stack_report 静态最坏链 504B(余 75%); pre-commit 全绿。剩 @test 实机闭环。
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
"stack-overflow-hook-impl": "a006edbd30d2c4d7",
|
||||
"malloc-failed-hook-impl": "fcd7250e5cd6403b",
|
||||
"stack-overflow-hook-helper": "cacd9fd028be9b5b",
|
||||
"watchdog-module": "c2823569e3c42317",
|
||||
"watchdog-module": "3d908285b092c402",
|
||||
"reset-cause-latch": "52fc71acbb0f1aed",
|
||||
"iwdg-hal-driver": "4b902875a84554e9",
|
||||
"hal-iwdg-enabled": "1a8ed6cff34f7ba6",
|
||||
|
||||
@@ -54,7 +54,7 @@ STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v
|
||||
- **FatFs 打开模式陷阱(2026-09-20 台架实测,`Lib/FatFs` 移植版)**:`FA_OPEN_APPEND`(0x30) = `FA_OPEN_ALWAYS|FA_SEEKEND`,**不含 `FA_WRITE`(0x02)**——不带写位打开的文件 `f_write` 恒返回 `FR_DENIED`(7)(/log 写失败真根因);追加写必须用 `FA_WRITE|FA_OPEN_APPEND`。该移植的 `f_write` 簇分配失败时返回 `FR_OK`+短写(无错误码),判失败必须校验写回字节数。标志位为旧式编号(`FA_READ`=0x01 / `FA_WRITE`=0x02 / `FA_CREATE_NEW`=0x04 / `FA_CREATE_ALWAYS`=0x08 / `FA_OPEN_ALWAYS`=0x10 / `FA_OPEN_APPEND`=0x30 / `FA_SEEKEND`=0x20(ff.c 内部定义)),与上游 FatFs R0.14 不同,勿照抄上游代码示例
|
||||
- **FatFs 文件名约束(2026-09-20 台架实证,`.fschk` 无限重格式化事故根因)**:本移植 `Lib/FatFs/ffconf.h` 为 `FF_USE_LFN=0`,**只支持严格 8.3 短名**——主名≤8 字符、扩展≤3 字符、**不得以点开头**(`.fschk` 会被 `ff.c create_short` 把点后当扩展域解析超限 → `f_open` 恒返 `FR_INVALID_NAME`(6),纯 RAM 名字判定、不碰盘)。ff.c `create_short` 全部拒绝点已加 DEBUG 打印:`[ERR][FATFS] SFN reject (原因) seg='名字片段' bad_ch=坏字符`,非法名字调用看开机日志即可定位。自愈类逻辑**严禁**把名字/参数类错误码(`FR_INVALID_NAME` 等)归入卷损坏触发集(整卷重格式化不可逆)
|
||||
- **ADC 取数只用 `tpafe5160_snapshot()`(原子快照)**(2026-10-10 修 E-44/E-45/E-58):旧的 `get_buf()` / `data_ready()` / `clear_ready()` 已从驱动**删除**——`get_buf` 只给缓冲区指针、任务再逐通道拷,两步之间被 BUSY EXTI 抢占并跨过一帧周期就拷回**两帧混合**数据(8 通道失去同一时刻性,且无错误指示);`s_ready` 电平标志有三个写者,`start_conv_irq` 触发前清 0 = **重触发本身就会抹掉一帧未消费数据**。现口径:帧序号只增不清(`tpafe5160_frame_seq()`)、取数=临界区内拷贝(`tpafe5160_snapshot(dst, count)` 返回 1/0/-1,**仅任务上下文**)、FRSTDATA 全程无跳变(芯片不驱动并行总线)由 `tpafe5160_frstdata_err()` 计数且 `tpafe5160_init()` 首帧自检直接返回 `-3` + `[ERR]`
|
||||
- **接 ADC / RS-485 消费者前的强制门禁(E-59,2026-10-10 固化)**:`adc_task` / `rs485_task` 从空桩转为真实消费者**之前**必须确认——① 驱动契约已修:TPAFE **E-44 / E-45 / E-58 已修 ✅**、RS485 **E-36 / E-37 已修 ✅** 但 **E-50(单缓冲无同步 → 包撕裂)未修 ❌**、**E-49(TX 超时拉 DE)未修 ❌**;② 栈预算:两任务**尚未入 `Src/freertos.c` 栈表**,建任务前后各跑一次 `scripts/stack_report.py`。与"改栈前跑 `stack_report.py`"同级。另按 N-18:V0.1 上两片转换器之间**禁止**做相位/功率/功率因数类运算
|
||||
- **接 ADC / RS-485 消费者前的强制门禁(E-59,2026-10-10 固化)**:`adc_task` / `rs485_task` 从空桩转为真实消费者**之前**必须确认——① 驱动契约已修:TPAFE **E-44 / E-45 / E-58 已修 ✅**、RS485 **E-36 / E-37 已修 ✅** 但 **E-50(单缓冲无同步 → 包撕裂)未修 ❌**、**E-49(TX 超时拉 DE)未修 ❌**;② 栈预算:建任务前后各跑一次 `scripts/stack_report.py`。**`adc_task` 已过闸(B1,2026-10-10)**:消费者本体 + `adcTask`(512 words / Normal,`USER CODE` 区手工创建,同 timeSyncTask)+ 栈预算(静态 504 B / 余 75%)+ IWDG 心跳(`TASK_WD_ADC`)均已落地;**`rs485_task` 仍被挡(E-50 / E-49 未修)**。另按 N-18:V0.1 上两片转换器之间**禁止**做相位/功率/功率因数类运算
|
||||
- **`DBG_*` 每条日志约 90 B Flash + 216 B 栈**(2026-10-02 S10 实测;2026-10-10 修正栈量):`dbg_log.h` 的 `DBG_INFO/ERROR/DEBUG` 在**每个调用点内联**行缓冲 `char __con_line[DBG_LINE_BUF_MAX]`(默认 = `console_log.h` 的 `DBG_CON_LINE_MAX` **192 B**)+ 时间戳缓冲 **24 B**(已并入同一数组,原为独立 32 B)+ 完整 `snprintf` 调用序列 → 单条约 **90 B Flash**(字符串常量另计)。给新模块接入日志时按"条数 × 90 B"估算 Flash 代价(实测 `sd2506_init` 加 6 条 = +576 B;`app_main` 加 3 条 = +180 B);**深调用链模块另需核算栈**——每条日志在栈上多占一份行缓冲、会进 `stack_report.py` 的最坏链:实测 defaultTask 那条链上 9 个帧各含一份 → **约 1.5 KB 纯粹是日志行缓冲**(2026-10-10 把该链 5312 → 2776 B 的主要杠杆之一)。故**日志不是免费的**——已覆盖的步骤不要再加"进入前/完成后"重复锚点,只在真正黑洞(原先静默返回)处补
|
||||
- **深调用链模块收紧日志行缓冲:`#define DBG_LINE_BUF_MAX 128U`,写在 `#include "dbg_log.h"` 之前**(2026-10-10 加)。已收紧:`nand_ftl.c`/`gd5f2gq5ue.c`/`cfg_file.c`/`net_cfg.c`/`net_socket.c`/`ch395f.c`/`time_sync.c`/`default_task.c`。⚠ **取值必须 ≥ 该模块最长日志行**(时间戳 20 + 标签 + 正文),否则该行被截断——各文件注释已写出实测行长。改前/改后各跑一次 `stack_report.py`
|
||||
|
||||
@@ -67,18 +67,20 @@ STM32F407ZGTx @168MHz(HSE 8MHz → PLL M=4/N=168/P=2);**仅 Keil MDK-ARM v
|
||||
| testTask | 2048 | BelowNormal |
|
||||
| uiTask | 4096 | BelowNormal |
|
||||
| timeSyncTask | 512 | Normal |
|
||||
| adcTask | 512 | Normal |
|
||||
<!-- TASK_TABLE:END -->
|
||||
|
||||
(实际值以 `Src/freertos.c` 为准;testTask 仅在启用测试套件时创建。改动栈/缓冲前先核对此表与实测。2026-09-21 上调:defaultTask 512→1024(扛 mount/mkfs/FAT探针/cfg/syslog 深层 FatFS I/O,旧值经 `configCHECK_FOR_STACK_OVERFLOW=2` 钩子实测溢出)、testTask 1024→2048(存储套件 deep call chain + 局部缓冲溢出)。FreeRTOS 堆已迁 CCM,任务栈合计已不占 SRAM;2026-09-21 可观测性落地后实测:ftpTask 峰值曾达 3480B/4096B(余量 15%,低于 1024B 底线)→ 已按 `docs/内存管理/RAM使用分析与优化方案.md` §1.4 把 lftpd 9 处大局部缓冲静态化(BSS +4.6KB),复测峰值 **1184B/4096B(余量 71%)**,6 任务全 PASS)
|
||||
|
||||
## 架构要点
|
||||
|
||||
`Src/main.c`(CubeMX 初始化)→ `app_main_init` → `osKernelStart` → 6 任务(`osKernelStart` 之前全是内核启动前代码:禁调任何 FreeRTOS/CMSIS-RTOS API,见「平台约束」)
|
||||
`Src/main.c`(CubeMX 初始化)→ `app_main_init` → `osKernelStart` → 7 任务(`osKernelStart` 之前全是内核启动前代码:禁调任何 FreeRTOS/CMSIS-RTOS API,见「平台约束」)
|
||||
|
||||
- `app_main_init`(时间子系统优先,使后续日志带时间戳):`sd2506_init` → `sys_clock_init`(墙钟;RTC 故障时降级默认时间基准并返回 -1 触发"时钟芯片异常"自检;`sys_clock_get` 每 30 天惰性再基准化防 49.7 天 tick 回绕)→ `rs485_init` → `gd5f2gq5ue_init` → `tpafe5160_init` → SD2506 诊断 → `tpafe5160_start_conv_irq`
|
||||
- `app_main_init`(时间子系统优先,使后续日志带时间戳):`sd2506_init` → `sys_clock_init`(墙钟;RTC 故障时降级默认时间基准并返回 -1 触发"时钟芯片异常"自检;`sys_clock_get` 每 30 天惰性再基准化防 49.7 天 tick 回绕)→ `rs485_init` → `gd5f2gq5ue_init` → `tpafe5160_init` → SD2506 诊断 → `tpafe5160_start_conv_irq`(一次性;**运行期周期 CONVST 触发自 2026-10-10 起由 `adcTask` 接管**,见下)
|
||||
- **就绪屏障**(`App/app/sys_events.h` Event Flags,取代魔法延时):`SYS_EVT_NET_READY`(netTask 置位)/ `STORAGE_READY`(defaultTask:卷挂载 + 网络配置加载完成)/ `FTP_READY` / `TIMESYNC_READY`;消费者用 `osEventFlagsWait` 阻塞等待
|
||||
- netTask:`net_stack_bring_up`(配置已由 defaultTask 在屏障前加载,本任务只读 RAM 副本 → `net_init` + PHY 强制 100M 全双工 → 递增网络代次号)→ 置 NET_READY → 循环 `net_poll` + `net_process_messages`;消费 `SYS_EVT_NET_RECONFIG` → 立即重建网络(新 IP 免重启生效,各 TCP 服务据代次号重建监听)
|
||||
- defaultTask:`f_mount` forced(无卷自动 `f_mkfs` FAT32;挂载后卷健康探针:小写两击确认,FAT 区陈旧/擦除时自动重格式化自愈,`/config.ini` 回落工厂默认——2026-09-20 /log 写失败修复)→ 网络配置加载(`net_cfg_load`;旧档迁移已于 2026-10-10 删除,见「模块约定」网口配置条)→ STORAGE_READY → LED 闪烁;同时是 syslog(`/log/run.log`·`selftest.log`,定长 64B 记录)的**唯一写者**与**配置引擎属主**(`cfg_file` 静态态单任务收敛于此:UI 保存请求执行 `net_cfg_save_run` + 2s `cfg_file_poll`,经 `SYS_EVT_CFG_SAVE` 事件唤醒;netTask/uiTask 不得直接触碰配置引擎,见 P1-3)
|
||||
- adcTask(**B1,2026-10-10**):每 1 ms 触发一次 CONVST(`tpafe5160_start_conv_irq()`)→ `tpafe5160_snapshot()` 临界区原子取最新一帧(8 通道)→ 帧统计 + 每 10 s 心跳日志;只取数、不做保护运算(V0.1 仅 TPAFE 三路 `UA`/`UN`/`IA` 测量有效,见 N-18)。手写于 `Src/freertos.c` 的 `USER CODE` 区(同 timeSyncTask,512 words / Normal),纳入 IWDG `required_mask`(`TASK_WD_ADC`)。⚠ 本阶段为**任务周期软触发**;硬件定时器 1 kHz 触发为后续(需 CubeMX 加 TIM)
|
||||
- 全景 `docs/架构设计/项目架构总览.md`(六层分层 / 启动时序 / 存储·网络·UI 栈 / 目录组织)
|
||||
|
||||
## 硬件引脚
|
||||
|
||||
+77
-12
@@ -1,11 +1,13 @@
|
||||
/*
|
||||
* 模块名称:ADC Sampling Task
|
||||
* 模块功能:TPAFE5160 8 通道同步采样,数据缓存与通知
|
||||
* 状态说明:**预留桩(未启用)**——采集链路尚未实现,产品定义未定
|
||||
* (见 docs/待处理内容.md 阶段 B0/B1)。当前 init/func 为空实现,
|
||||
* 不触发 CONVST、不消费数据。
|
||||
* 2026-10-10 起本文件已挂进 MDK-ARM 工程(此前两边都不注册 = 永不编译,
|
||||
* 改它不生效),但仍未在 Src/freertos.c 创建任务。
|
||||
* 模块功能:TPAFE5160 8 通道同步采样——1ms 采样节拍 + 原子快照消费 + 帧统计
|
||||
* 状态说明:**B1 已落地(2026-10-10)**——本任务从空桩转为真实消费者:
|
||||
* 每 1ms 触发一次 CONVST,用 tpafe5160_snapshot() 原子取数(AGENTS 铁律),
|
||||
* 统计帧数/无新帧次数,并纳入看门狗 required_mask(TASK_WD_ADC)。
|
||||
* ⚠ B1 阶段用**任务周期软触发**(osDelayUntil)产生采样节拍,满足 L1-1
|
||||
* 判据(BUSY 连续脉冲 + frame_seq 持续递增);**精确 1 kHz / 等周波调频**
|
||||
* 的硬件定时器触发为后续(需 CubeMX 加 TIM)。
|
||||
* V0.1 上只有 TPAFE 三路(UA/UN/IA)测量有效;本任务只取数,不做保护运算。
|
||||
* 接入前必读:取数只用 tpafe5160_snapshot()(临界区原子快照,仅任务上下文;
|
||||
* 旧的 get_buf/data_ready/clear_ready 已删除);接消费者前的强制门禁
|
||||
* 见根 AGENTS.md「接 ADC / RS-485 消费者前的强制门禁」+ 建任务前后各跑
|
||||
@@ -16,23 +18,39 @@
|
||||
* 修改记录:
|
||||
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||
* v1.1 2026-10-05 王建锋 P3-11:注明"预留桩(未启用)",避免误认为已实现
|
||||
* v2.0 2026-10-10 王建锋 B1:实现真实消费者(1ms 节拍 + 原子快照 + 帧统计 +
|
||||
* 看门狗心跳),由 Src/freertos.c 创建为 adcTask
|
||||
*/
|
||||
|
||||
#include "adc_task.h"
|
||||
#include "cmsis_os.h"
|
||||
#include "tpafe5160.h"
|
||||
#include "task_watchdog.h"
|
||||
|
||||
#define DBG_TAG "[ADC_TASK]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
/* 采样节拍周期(ms)。B1:任务周期软触发;硬件定时器方案见文件头说明 */
|
||||
#define ADC_TASK_BEAT_MS 1U
|
||||
/* 心跳日志周期(ms):周期性上报帧统计,作为采集链路存活的观测面 */
|
||||
#define ADC_TASK_REPORT_MS 10000U
|
||||
|
||||
/* 最新一帧原始码值(8 通道;语义映射见 docs/硬件平台/ADC通道映射说明.md) */
|
||||
static int16_t s_frame[TPAFE5160_CH_NUM];
|
||||
/* 统计:已消费帧数 / 无新帧次数(首拍必为无新帧,之后应稳定为 0 增量) */
|
||||
static uint32_t s_frames_consumed;
|
||||
static uint32_t s_frames_idle;
|
||||
|
||||
/*
|
||||
* 函数功能:ADC 任务初始化
|
||||
* 入口参数:无
|
||||
* 返 回 值:0 - 成功,-1 - 失败
|
||||
* 限定条件:TPAFE5160 硬件已上电
|
||||
* 函数说明:配置采样参数,准备数据缓冲区
|
||||
* 限定条件:tpafe5160_init() 已在 app_main_init()(内核启动前)完成
|
||||
* 函数说明:驱动初始化不在本任务(见限定条件);此处仅清帧统计。
|
||||
*/
|
||||
int adc_task_init(void) {
|
||||
s_frames_consumed = 0u;
|
||||
s_frames_idle = 0u;
|
||||
DBG_INFO("adc_task_init");
|
||||
return 0;
|
||||
}
|
||||
@@ -41,13 +59,60 @@ int adc_task_init(void) {
|
||||
* 函数功能:ADC 任务主函数
|
||||
* 入口参数:arg - FreeRTOS 传入参数(未使用)
|
||||
* 返 回 值:无
|
||||
* 限定条件:adc_task_init() 已成功调用
|
||||
* 函数说明:定时触发 TPAFE5160 同步采样并处理数据
|
||||
* 限定条件:adc_task_init() 已调用;内核已启动
|
||||
* 函数说明:每 1ms 触发一次 CONVST(采样节拍),随后原子快照取最新一帧并统计。
|
||||
* 首拍无帧属正常(本次转换尚未完成);之后每拍消费上一拍触发的帧,
|
||||
* 故稳态下 consumed 每拍 +1、idle 不再增长。idle 持续增长 = EXTI 未在
|
||||
* 读帧(异常),由周期心跳日志暴露。
|
||||
*/
|
||||
void adc_task_func(void const *arg) {
|
||||
void adc_task_func(void *arg) {
|
||||
uint32_t next = osKernelGetTickCount();
|
||||
uint32_t report_at = next + ADC_TASK_REPORT_MS;
|
||||
uint8_t first_logged = 0u;
|
||||
|
||||
(void)arg;
|
||||
|
||||
for (;;) {
|
||||
osDelay(1000);
|
||||
int r;
|
||||
|
||||
/* 1) 采样节拍:触发一次 CONVST(B1:任务周期软触发) */
|
||||
tpafe5160_start_conv_irq();
|
||||
|
||||
/* 2) 原子快照消费最新一帧(仅任务上下文;1=有新帧 0=无新帧 -1=参数错) */
|
||||
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 以区分异常 */
|
||||
}
|
||||
|
||||
/* 3) 看门狗心跳(本任务已纳入 required_mask) */
|
||||
task_wd_beat(TASK_WD_ADC);
|
||||
|
||||
/* 4) 周期心跳日志:帧统计 + 驱动侧 FRSTDATA 错误计数 */
|
||||
{
|
||||
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());
|
||||
report_at = now + ADC_TASK_REPORT_MS;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5) 等下一个节拍(固定周期;落后则立即补齐,不累积漂移) */
|
||||
next += ADC_TASK_BEAT_MS;
|
||||
(void)osDelayUntil(next);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
int adc_task_init(void);
|
||||
void adc_task_func(void const *arg);
|
||||
void adc_task_func(void *arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "vol_lock.h"
|
||||
|
||||
/* 任务句柄与属性块(CubeMX 生成全局,定义于 Src/freertos.c):
|
||||
* 栈水位观测需 6 任务句柄 + 属性块 stack_size(配置栈大小的唯一定义处) */
|
||||
* 栈水位观测需各任务句柄 + 属性块 stack_size(配置栈大小的唯一定义处) */
|
||||
extern osThreadId_t defaultTaskHandle;
|
||||
extern const osThreadAttr_t defaultTask_attributes;
|
||||
extern osThreadId_t netTaskHandle;
|
||||
@@ -55,6 +55,8 @@ extern osThreadId_t uiTaskHandle;
|
||||
extern const osThreadAttr_t uiTask_attributes;
|
||||
extern osThreadId_t timeSyncTaskHandle;
|
||||
extern const osThreadAttr_t timeSyncTask_attributes;
|
||||
extern osThreadId_t adcTaskHandle;
|
||||
extern const osThreadAttr_t adcTask_attributes;
|
||||
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
/* 栈水位观测节奏:首次报告须晚于 bring-up 深链(mount/mkfs/探针/cfg/syslog),
|
||||
@@ -85,6 +87,7 @@ static const stack_probe_task_t s_stack_probe[] = {
|
||||
{ "test", &testTaskHandle, &testTask_attributes },
|
||||
{ "ui", &uiTaskHandle, &uiTask_attributes },
|
||||
{ "timesync", &timeSyncTaskHandle, &timeSyncTask_attributes },
|
||||
{ "adc", &adcTaskHandle, &adcTask_attributes },
|
||||
};
|
||||
|
||||
#define STACK_PROBE_COUNT (sizeof(s_stack_probe) / sizeof(s_stack_probe[0]))
|
||||
|
||||
@@ -190,14 +190,17 @@ static uint32_t wd_required_mask(void) {
|
||||
| (1u << (uint32_t)TASK_WD_NET)
|
||||
| (1u << (uint32_t)TASK_WD_FTP)
|
||||
| (1u << (uint32_t)TASK_WD_UI)
|
||||
| (1u << (uint32_t)TASK_WD_TIMESYNC);
|
||||
| (1u << (uint32_t)TASK_WD_TIMESYNC)
|
||||
| (1u << (uint32_t)TASK_WD_ADC); /* adcTask 不依赖任何屏障,任何构建都置位 */
|
||||
|
||||
#if defined(ENABLE_HW_LAYER_TESTS)
|
||||
/* 见函数说明:CH395F 硬件层测试构建 = default + 屏障等待者(等待分片喂位) */
|
||||
/* 见函数说明:CH395F 硬件层测试构建 = default + 屏障等待者(等待分片喂位)
|
||||
* + adcTask(其采集不依赖网络/存储屏障,任何构建都在置位) */
|
||||
m = (1u << (uint32_t)TASK_WD_DEFAULT)
|
||||
| (1u << (uint32_t)TASK_WD_FTP)
|
||||
| (1u << (uint32_t)TASK_WD_UI)
|
||||
| (1u << (uint32_t)TASK_WD_TIMESYNC);
|
||||
| (1u << (uint32_t)TASK_WD_TIMESYNC)
|
||||
| (1u << (uint32_t)TASK_WD_ADC);
|
||||
#endif
|
||||
|
||||
return m;
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef enum {
|
||||
TASK_WD_TEST = 3,
|
||||
TASK_WD_UI = 4,
|
||||
TASK_WD_TIMESYNC = 5,
|
||||
TASK_WD_ADC = 6, /* adcTask:1ms 采样节拍消费者(B1,2026-10-10) */
|
||||
TASK_WD_ID_MAX
|
||||
} task_wd_id_t;
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ main.c
|
||||
| testTask | 2048 words | BelowNormal | 硬件测试入口 |
|
||||
| uiTask | 4096 words | BelowNormal | LVGL UI 界面 |
|
||||
| timeSyncTask | 512 words | Normal | 墙钟时间同步 |
|
||||
| adcTask | 512 words | Normal | TPAFE5160 采样(1ms 节拍 + 原子快照) |
|
||||
<!-- TASK_TABLE:END -->
|
||||
|
||||
> 上表与 `Src/freertos.c` 的 `osThreadAttr_t` 一致(2026-09-25 校准);改动栈大小前先读
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "time_sync.h"
|
||||
#include "sys_events.h"
|
||||
#include "default_task.h"
|
||||
#include "adc_task.h" /* B1(2026-10-10):ADC 采集消费者(手写任务,见 Variables 区) */
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
@@ -112,6 +113,10 @@ static int hook_ptr_ok(const void *p)
|
||||
* 靠审计 WARN 提示),建监听 → net_bind → CH395F → 日志尾。2026-10-10 整改后
|
||||
* 静态最坏链 1024 B(整改前 1736 B)、实测峰值 616 B;⚠ 余量 1024 B **正好**
|
||||
* 等于 ISR 底线 → 本任务链上再加任何调用(或新日志行)都必须先抬栈。
|
||||
* adcTask 512 words:本区下方手工定义(同上,不在 `.ioc` 里)。B1(2026-10-10)
|
||||
* ADC 采集消费者:链上仅 tpafe5160_start_conv_irq + tpafe5160_snapshot(临界区
|
||||
* 原子拷贝)+ task_wd_beat + 周期 DBG_INFO(每 10s 一条)。栈值以
|
||||
* `scripts/stack_report.py` 实测最坏链为准,改动前后各跑一次。
|
||||
*/
|
||||
/* 存储测试变量(g_storage_stats / s_perf_buf)已迁至 test/board/storage_test_task.c */
|
||||
osThreadId_t timeSyncTaskHandle;
|
||||
@@ -120,6 +125,14 @@ const osThreadAttr_t timeSyncTask_attributes = {
|
||||
.stack_size = 512 * 4,
|
||||
.priority = (osPriority_t) osPriorityNormal,
|
||||
};
|
||||
/* B1(2026-10-10):ADC 采集消费者(1ms 采样节拍 + 原子快照 + 帧统计)。
|
||||
* 手写于此而非 .ioc(同 timeSyncTask:不在 Tasks01 里 → 重生成会丢,靠审计 WARN 提示)。 */
|
||||
osThreadId_t adcTaskHandle;
|
||||
const osThreadAttr_t adcTask_attributes = {
|
||||
.name = "adcTask",
|
||||
.stack_size = 512 * 4,
|
||||
.priority = (osPriority_t) osPriorityNormal,
|
||||
};
|
||||
/* USER CODE END Variables */
|
||||
/* Definitions for defaultTask */
|
||||
osThreadId_t defaultTaskHandle;
|
||||
@@ -294,6 +307,12 @@ void MX_FREERTOS_Init(void) {
|
||||
/* 本地时间同步任务(PC 推送 TCP):依赖 netTask 处理消息队列 */
|
||||
timeSyncTaskHandle = osThreadNew(time_sync_task, NULL, &timeSyncTask_attributes);
|
||||
|
||||
/* B1(2026-10-10):ADC 采集任务。1ms 采样节拍触发 CONVST,消费 tpafe5160
|
||||
* 原子快照并喂 IWDG 心跳(TASK_WD_ADC)。不依赖任何就绪屏障(无网络/存储依赖)
|
||||
* → 任何构建都创建、都置心跳位。驱动 tpafe5160_init() 已在 app_main_init
|
||||
* (内核启动前)完成;本任务只做运行期采样。 */
|
||||
adcTaskHandle = osThreadNew(adc_task_func, NULL, &adcTask_attributes);
|
||||
|
||||
/* P2-13(2026-10-04):产品构建(未选任何 TEST_SUITE_*)不需要 testTask。
|
||||
* 上方生成区按 .ioc FREERTOS.Tasks01 无条件创建它,其 2048 words(8KB) 栈 + TCB
|
||||
* 取自 CCM 堆;而产品构建下 start_test_task() 仅打印一行后 osDelay(1000) 永久空转,
|
||||
|
||||
@@ -36,10 +36,10 @@
|
||||
<!-- MEM_SNAPSHOT:BEGIN generated by scripts/check_mem_numbers.py -->
|
||||
| 区域 | 用量 | 容量 | 占比 |
|
||||
|---|---|---|---|
|
||||
| ER_IROM1 | 267,528 B (261.26 KB) | 1,048,576 B (1024 KB) | 25.5% |
|
||||
| RW_IRAM1 | 89,168 B (87.08 KB) | 131,072 B (128 KB) | 68.0% |
|
||||
| ER_IROM1 | 268,300 B (262.01 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 合计)** | **268,276 B (262.0 KB)** | 1,048,576 B (1024 KB) | **25.6%** |
|
||||
| **Flash (ROM 合计)** | **269,060 B (262.8 KB)** | 1,048,576 B (1024 KB) | **25.7%** |
|
||||
<!-- MEM_SNAPSHOT:END -->
|
||||
|
||||
各区的容量与常量来源:
|
||||
@@ -92,6 +92,7 @@
|
||||
`Src/freertos.c` 中 `osThreadAttr_t.stack_size` 单位为**字节**(CubeMX 生成代码,`1024 * 4` 表示 4096 字节):
|
||||
|
||||
> ✅ **本表已于 2026-10-10 重新基线**(产品构建 `suite=NONE`,开机 + 空闲采样,静态链取 `stack_report.py`)。
|
||||
> 同日**增列 `adcTask`**(B1:ADC 采集消费者,512 words,静态最坏链 504 B / 余 75%)。
|
||||
> 此前 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 已销项。
|
||||
|
||||
@@ -103,6 +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%) |
|
||||
| idle(内核) | `configMINIMAL_STACK_SIZE=128` | 0.5KB | 空闲 | 未观测(未取句柄) |
|
||||
| timer(内核) | `configTIMER_TASK_STACK_DEPTH=256` | 1KB | 软定时器 | 未观测 |
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
| 超时 | 标称 **2498 ms**,最坏(LSI 47 kHz)**≈1701 ms** | `WD_IWDG_PRESCALER=4` / `WD_IWDG_RELOAD=1249`(`task_watchdog.c`) |
|
||||
| 抽样周期 | **100 ms**(`WD_POLL_PERIOD_MS`) | 同上 |
|
||||
| 缺失容忍 | **连续 8 轮 = 800 ms** 后停喂(`WD_MISS_TOLERANCE`) | 同上 |
|
||||
| 必需掩码 | 产品构建 **`0x37`**(default/net/ftp/ui/timesync);`ENABLE_HW_LAYER_TESTS` 下 **`0x35`**(剔 net) | `wd_required_mask()` |
|
||||
| 必需掩码 | 产品构建 **`0x77`**(default/net/ftp/ui/timesync/adc);`ENABLE_HW_LAYER_TESTS` 下 **`0x75`**(剔 net) | `wd_required_mask()` |
|
||||
| 喂狗者 | **仅 defaultTask**(`task_wd_poll`,主循环每轮调用、内部节流) | `App/task/default_task.c` |
|
||||
| 启动时刻 | **defaultTask 存储 bring-up 之后**(`task_wd_start()`);`MX_IWDG_Init()` 只填参数不启动 | `default_task.c:175`、`Src/iwdg.c` 的 `USER CODE BEGIN 0` |
|
||||
| 复位归因 | 停喂 → IWDG 自然溢出 → `RCC_CSR.IWDGRSTF`(不用 `NVIC_SystemReset`) | `task_wd_poll()` |
|
||||
@@ -189,9 +189,9 @@ static HAL_StatusTypeDef iwdg_deferred_start(const IWDG_HandleTypeDef *a_h) { (v
|
||||
|
||||
| 构建 | 掩码 | 会置位的任务 |
|
||||
|---|---|---|
|
||||
| 产品 | `0x37` = bit0,1,2,4,5 | default / net / **ftp** / ui / timesync |
|
||||
| `ENABLE_HW_LAYER_TESTS`(CH395F 硬件层测试,netTask 入口自挂起) | `0x35` = bit0,2,4,5 | default / ftp / ui / timesync(屏障等待按 100 ms 分片喂位) |
|
||||
| 测试套件(`TEST_SUITE_*`,创建 testTask) | 同上 `0x37` | **testTask 任何构建都不入掩码、也不置位**(它可长阻塞;置位反而引入多余位误杀) |
|
||||
| 产品 | `0x77` = bit0,1,2,4,5,6 | default / net / **ftp** / ui / timesync / **adc** |
|
||||
| `ENABLE_HW_LAYER_TESTS`(CH395F 硬件层测试,netTask 入口自挂起) | `0x75` = bit0,2,4,5,6 | default / ftp / ui / timesync / **adc**(屏障等待按 100 ms 分片喂位;adcTask 不依赖任何屏障,任何构建都置位) |
|
||||
| 测试套件(`TEST_SUITE_*`,创建 testTask) | 同上 `0x77` | **testTask 任何构建都不入掩码、也不置位**(它可长阻塞;置位反而引入多余位误杀) |
|
||||
|
||||
> 2026-10-02 台架:旧版"仅剔 NET 位 + 屏障等待者不置位"会让测试构建陷入 IWDG 复位循环——**掩码与会置位集合必须成对维护**,改任一处都要同步。
|
||||
|
||||
@@ -356,6 +356,7 @@ snapshot == required → miss_streak=0、证据门闩复位、喂狗
|
||||
| ftpTask | 主循环 = lftpd 事件循环:`lftpd.c` 事件循环每轮、RETR/STOR 每分片;`lftpd_inet.c` 连接/数据等待每轮每片;`lftpd_io.c` 卷锁等待每片;入口 `task_wd_bind()` |
|
||||
| uiTask | 主循环;就绪屏障等待分片;入口 `task_wd_bind()` |
|
||||
| timeSyncTask | 主循环;监听重试(500 ms/2 s)前;accept 轮询;`time_sync_handle_conn` 的 **200 ms 切片**;屏障等待分片;入口 `task_wd_bind()` |
|
||||
| adcTask | 主循环每 1 ms 节拍 `task_wd_beat(TASK_WD_ADC)`;**不做 NAND I/O → 不登记 FTL 心跳路由**(无需 `task_wd_bind()`) |
|
||||
| testTask | **不埋点、不登记、不入掩码** |
|
||||
| NAND FTL | `gd5f2gq5ue.c`:长操作入口 `nand_ftl_wd_beat()` + `nand_ftl_wd_feed()`;`gd5f_wait_busy` 每 100 ms 双管(路由到调用者任务) |
|
||||
|
||||
@@ -497,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` 里")。
|
||||
> **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)。
|
||||
|
||||
**为什么 `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`)+ 审计项兜底。
|
||||
|
||||
@@ -570,3 +571,4 @@ 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 |
|
||||
|
||||
+20
-17
@@ -37,7 +37,7 @@
|
||||
|
||||
| 级别 | 数量 | 关键项 |
|
||||
|---|---|---|
|
||||
| **P1** | 1 (+1 收尾) | **P1-1 ADC 采样路径产品构建中死亡**;P1-10 测试固件构建实测闭环(主体已闭环,见 §3.1) |
|
||||
| **P1** | 0 (+2 收尾) | **P1-1 ADC 采样路径**(✅ 已实现,剩 `@test` 实机闭环);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,9 +48,10 @@
|
||||
|
||||
1. **网络层已是全项目最成熟子系统**(pending 机制 + 四份 Trap 记录 + 量化基线 + 探针族)。
|
||||
剩余网络工作都是"二期扩展/收口",**没有紧急项**。
|
||||
2. **真正的产品功能缺口在 ADC 与 RS-485 采集链路**:`adc_task`/`rs485_task` 均为空桩,
|
||||
DTU 的核心职责(数据采集与转发)**尚未实现**。这既是 P1-1 的根源,也是 E-59 那条
|
||||
"休眠缺陷闸门"的另一面——不是缺陷难修,而是**功能没接**。
|
||||
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 那条"休眠缺陷闸门"的另一面。
|
||||
3. **验证债已基本还清,重心是"功能债"**:剩余验证债仅 **N-3(L5 基线重锁,待 PC peer)**
|
||||
(原 **S-1 栈风险已于 2026-10-10 削链闭环并销项**:defaultTask 静态最坏链 5312 → 2776 B、
|
||||
实测峰值 3392 → 2152 B,**未抬栈**,见 `docs/内存管理/RAM使用分析与优化方案.md`)。
|
||||
@@ -70,16 +71,16 @@
|
||||
> 持续采集 / **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 现在只欠栈预算 + 建任务**;
|
||||
> **E-44 / E-45 / E-58 全部修复** → **B1(ADC 采集链路)已于 2026-10-10 实现**
|
||||
> (`adc_task` 真实消费者 + 建任务 + 栈预算,剩 `@test` 实机闭环);
|
||||
> B2 仍欠 **E-50 / E-49**(RS485 驱动契约未修,门禁仍挡着)。
|
||||
|
||||
| 序 | 任务 | 前置 | 说明 |
|
||||
|---|---|---|---|
|
||||
| **B1** | **ADC 采集链路实现**(消化 P1-1;E-58 已闭环) | B0 ✅ + **E-59 门禁**(TPAFE 侧已满足) | 周期 CONVST 重触发 + `adc_task` 消费 **`tpafe5160_snapshot()`**(**2026-10-10 驱动契约已修**:E-44 FRSTDATA 有效性校验 + `init()` 首帧自检返 `-3`、E-45 帧序号取代就绪电平标志、E-58 临界区原子快照;旧 `get_buf`/`data_ready`/`clear_ready` **已删**,删除前零调用者);`adc_task.c` **已挂进 `uvprojx`**(此前 Keil/模拟器两边都不注册 = 永不编译;simulator 无任务层,只挂 Keil);**仍欠**:栈预算核算(两任务未入 `freertos.c` 栈表,建任务前后各跑 `stack_report.py`;原 S-1 栈风险已于 2026-10-10 **削链销项**,defaultTask 现静态 2776/4096 余 32%、实测 2152 B)+ 消费者本体 + 建任务走 **L1(`.ioc` 的 `FREERTOS.Tasks01`)**;**取数必须按 `docs/硬件平台/ADC通道映射说明.md`**(TPAFE `buf[2]=IA`/`buf[5]=UN`/`buf[6]=UA`;STM32 侧 ADC1 **已于 2026-10-09 生成**:`hadc1` + `MX_ADC1_Init()`、9 通道 Rank1~9、144 cycles、ADCCLK=21 MHz、软件触发,网名 ADC17=PC4 用 `ADC_CHANNEL_14`;⚠ 全仓库至今**无 `HAL_ADC_Start`** → STM32 侧一路未跑) |
|
||||
| **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 采集** |
|
||||
|
||||
**建议**:驱动契约与编译接线已在 2026-10-10 铺完 → B1 的下一步是**栈预算 + 建任务(L1)**,
|
||||
再谈消费者与节拍;B2 之前必须先修 E-50 / E-49。
|
||||
**建议**:B1 已实现(剩 `@test` 实机闭环);下一步是 **B2**——但 B2 之前必须先修 **E-50 / E-49**(RS485 驱动契约未修,E-59 门禁仍挡着)。
|
||||
|
||||
### 2.2 阶段 C:结构债清理(二期)+ 存储侧健壮性
|
||||
|
||||
@@ -102,7 +103,7 @@
|
||||
|
||||
```
|
||||
【阶段 B 功能】 B0 产品定义确认 ✅ ─┬─ B3 E-59 门禁固化(并行)
|
||||
(当前最高优先) └─ E-58 原子快照 → B1 ADC → B2 RS485
|
||||
(当前最高优先) └─ E-58 原子快照 → B1 ADC ✅ → B2 RS485
|
||||
↓
|
||||
【阶段 C 结构】 C1 pending 二期 ─ C3 日志管线(N-2/S-3)
|
||||
─ C5 收口 ─ C6 USART1 TX-only
|
||||
@@ -114,15 +115,16 @@
|
||||
|
||||
## 3. 待办详述
|
||||
|
||||
### 3.1 P1(未闭环 1 项 + 1 项收尾)
|
||||
### 3.1 P1(2 项收尾:均剩 `@test` 实机闭环)
|
||||
|
||||
#### P1-1 ADC 采样数据路径产品构建中死亡
|
||||
- **位置**:`App/app/app_main.c`(`tpafe5160_start_conv_irq()` 仅启动时调用一次)+ `Drivers/BSP/TPAFE5160/tpafe5160.c`
|
||||
- **证据**:启动序列调用一次 `tpafe5160_start_conv_irq()`;全仓库无周期性 CONVST 重触发;`tpafe5160_snapshot()` 无任何消费者(`adc_task.c` 是空桩——2026-10-10 起已挂进 `uvprojx`,但仍未在 `freertos.c` 建任务);STM32 侧 ADC1 已生成却**全仓库无 `HAL_ADC_Start`**(一路彻底未跑)。
|
||||
#### 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):**驱动侧取数契约已修**(E-44 FRSTDATA 有效性校验 + `init()` 首帧自检、E-45 帧序号、E-58 原子快照,索引见 `docs/问题记录/错误码传播审计.md` §2.2)→ 接消费者不再有"撕裂 / 重触发丢样 / 芯片静默死亡"三类风险。本条剩余 = **周期重触发 + 消费者 + 建任务**。
|
||||
- **修复建议**:周期 CONVST 重触发(定时器或任务)+ `adc_task` 消费 `tpafe5160_snapshot()`;建任务走 **L1(`.ioc` 的 `FREERTOS.Tasks01`)** 并做栈预算;若基线版本有意不实现采集,应删除启动调用并以 `APP_ADC_ENABLE` 真实门控。
|
||||
- **置信度**:high(代码级确证);P0/P1 定级取决于产品定义(见 §4 待确认)。
|
||||
- **修复落地(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)。
|
||||
|
||||
#### P1-10 测试固件静态 RAM 预算(基线已重建、测试缓冲已瘦身,剩构建实测闭环)
|
||||
- **位置**:`MDK-ARM/STM32F407-Demo/STM32F407-Demo.sct`(`RW_IRAM1 0x20000000 0x00020000` = 128KB;芯片 192KB 的上部 64KB 有意未映射,克隆芯片兼容性考量)
|
||||
@@ -329,6 +331,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` |
|
||||
| testTask 栈峰值(产品态空转) | 496 / 8192(余量 93%) | 同上 |
|
||||
| 队列响应性(挂起客户端) | 92.5ms(pending 一期) | `e02_probe.py` |
|
||||
| M3 压力档帧周期 | med 60.1 / p95 66.4 / max 69.3ms,零尖峰 | `链路延迟测试说明.md` |
|
||||
@@ -338,7 +341,7 @@ S14 已在 workflow 显式提示"体积门禁未执行"(`::notice::`)并在
|
||||
## 7. 内存预算(支撑 §6 与定栈规则)
|
||||
|
||||
现行权威数据 = `docs/内存管理/RAM使用分析与优化方案.md` v1.2(2026-09-21,§2.1 受管快照):
|
||||
任务栈在 CCM 堆(defaultTask 1024w / netTask 1024w / ftpTask 1024w / testTask 2048w / uiTask 4096w / timeSyncTask 512w);
|
||||
任务栈在 CCM 堆(defaultTask 1024w / netTask 960w / ftpTask 1024w / testTask 2048w / uiTask 4096w / timeSyncTask 512w / **adcTask 512w**);
|
||||
产品构建 RW_IRAM1 84,960/131,072 B(64.8%)+ RW_CCM 49,184/65,280 B(75.3%);
|
||||
实测堆 `free=8,664 / min_ever=4,728` B;台账工具 `scripts/ram_report.py` + `scripts/stack_report.py`。
|
||||
**旧栈表/旧余量数字作废,勿引用。**
|
||||
|
||||
@@ -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`)当前为空桩,见登记簿 **P1-1 / B1**。
|
||||
> **状态**:规划稿——保护链路本体尚未实现;其前置的 **ADC 采集链路(`adc_task`)已于 2026-10-10 实现**(B1:周期 CONVST + 原子快照消费 + 建任务 + 栈预算,剩 `@test` 实机闭环),见登记簿 **P1-1 / B1**。
|
||||
|
||||
---
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
| 操作系统 | FreeRTOS V10.3.1(CMSIS-RTOS v2) |
|
||||
| 已实现子系统 | 网络(CH395F)、存储(GD5F2GQ5UE SPI NAND + dhara FTL + FatFs)、时间(SD2506 RTC + `sys_clock`)、配置(cfg_file)、日志、UI(远端显示)、看门狗(IWDG)、FTP |
|
||||
| 采样硬件 | TPAFE5160(16 位、8 通道**同步**、±5 V 双极性、并行 `GPIOG[15:0]`)+ STM32 内部 ADC1(12 位、9 通道**顺序**扫描、0~3.3 V 单极性) |
|
||||
| 采样软件 | `Drivers/BSP/TPAFE5160/tpafe5160.h` 驱动就绪(原子快照 API);`App/task/adc_task.c` **空桩**;无周期 CONVST 重触发;STM32 侧无 `HAL_ADC_Start` |
|
||||
| 采样软件 | `Drivers/BSP/TPAFE5160/tpafe5160.h` 驱动就绪(原子快照 API);`App/task/adc_task.c` **已实现真实消费者(B1,2026-10-10)**——每 1 ms 触发 CONVST + `tpafe5160_snapshot()` 取数 + 帧统计;STM32 侧仍无 `HAL_ADC_Start` |
|
||||
| 保护算法层 | **完全缺失**(无傅氏、无保护元件、无出口、无定值模型) |
|
||||
| 已知硬件缺陷 | **N-18**:8 路电气量分属两片转换器 → V0.1 上禁止跨转换器做相位/功率/矢量运算 |
|
||||
|
||||
@@ -65,9 +65,9 @@
|
||||
| 依赖 | 说明 | 状态 |
|
||||
| --- | --- | --- |
|
||||
| **B0 产品定义** | 采集是否持续 / 采样率与通道 / 转发目标 / 保护元件清单——决定 B1 与保护层的**规模** | ✅ 已确认(2026-10-10,见 §1.5) |
|
||||
| **B1 ADC 采集链路** | 周期 CONVST + `adc_task` 消费 `tpafe5160_snapshot()` + 建任务 + 栈预算 | ⬜ 未实现(驱动契约已就绪) |
|
||||
| **B1 ADC 采集链路** | 周期 CONVST + `adc_task` 消费 `tpafe5160_snapshot()` + 建任务 + 栈预算 | ✅ 已实现(2026-10-10;`adcTask` 512 words,剩 `@test` 实机闭环) |
|
||||
| **N-18 硬件缺陷** | V0.1 跨转换器无同一时刻性 → 限定 V0.1 可实现的保护范围 | ⚠️ 硬件改版项(V0.2) |
|
||||
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | ⬜ 待做 |
|
||||
| **栈预算** | 保护任务栈需入 `Src/freertos.c` 并经 `scripts/stack_report.py` 核算 | 🔶 `adcTask` 已核算(静态 504 B / 余 1544 B / 75%);保护任务为后续 |
|
||||
|
||||
### 1.5 B0 产品定义(2026-10-10 确认)
|
||||
|
||||
@@ -238,8 +238,8 @@
|
||||
|
||||
| # | 功能点 | 关键参数 | 完成判据 | 状态 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| L1-1 | 周期 CONVST 重触发 | 1000 Hz(与保护节拍同源) | 示波器见 U3 `BUSY` 连续脉冲;`tpafe5160_frame_seq()` 持续递增 | ⬜ |
|
||||
| L1-2 | TPAFE 快照消费 | 8 通道 / 帧 | `adc_task` 每拍调 `tpafe5160_snapshot()`,返回 1/0/-1 有处理 | ⬜ |
|
||||
| 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-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` | 注入标准源,读数误差 ≤ 目标精度 | ⬜ |
|
||||
@@ -459,7 +459,7 @@
|
||||
|
||||
| 阶段 | 名称 | 内容 | 前置 | 里程碑 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **P0** | 采样与相量底座 | B1(周期 CONVST + `adcTask` 消费 + 建任务 + 栈预算)+ L1 + L2 | B0 + B1 | 每 1 ms 产出正确的基波相量 |
|
||||
| **P0** | 采样与相量底座 | B1(周期 CONVST + `adcTask` 消费 + 建任务 + 栈预算)+ L1 + L2 | B0 + B1 ✅ | 每 1 ms 产出正确的基波相量 |
|
||||
| **P1** | 基础保护元件 | **V0.1 有效子集**:过流(A 相,`IA`)、过负荷(A 相)+ 定值模型;B/C 相过流**建接口不使能** | P0 | 标准源注入 A 相可正确动作 |
|
||||
| **P2** | 电压/频率类保护 | 过压/欠压(`UA`)、过频/低频、零序过压(`UN`) | P0 | 电压/频率越限正确动作 |
|
||||
| **P3** | 异常检测与闭锁 | L5 自检闭锁、采样通道自检;三相类(涌流/PT·CT 断线/母线接地)**建接口不使能** | P1/P2 | 自检失败闭锁;未使能元件不误动 |
|
||||
@@ -592,3 +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` 实机闭环 |
|
||||
|
||||
@@ -64,7 +64,7 @@ TARGETS = [
|
||||
# 文档中的展示顺序(与 README/AGENTS 既有一致;不在表内的任务按源码顺序追加)。
|
||||
# 不用源码顺序:freertos.c 里 timeSyncTask 定义在最前,但文档按「主任务→辅助任务」排列。
|
||||
DISPLAY_ORDER = ["defaultTask", "netTask", "ftpTask", "testTask", "uiTask",
|
||||
"timeSyncTask"]
|
||||
"timeSyncTask", "adcTask"]
|
||||
|
||||
# 各任务在文档里的「职责」描述(README 需要,AGENTS 不需要)。
|
||||
# 只影响展示文案,不参与一致性判定;未知任务回落为空。
|
||||
@@ -75,6 +75,7 @@ ROLE = {
|
||||
"testTask": "硬件测试入口",
|
||||
"uiTask": "LVGL UI 界面",
|
||||
"timeSyncTask": "墙钟时间同步",
|
||||
"adcTask": "TPAFE5160 采样(1ms 节拍 + 原子快照)",
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ ROOTS = {
|
||||
"StartUiTask": "uiTask",
|
||||
"start_test_task": "testTask",
|
||||
"time_sync_task": "timeSyncTask",
|
||||
"adc_task_func": "adcTask",
|
||||
}
|
||||
|
||||
# Runtime lines use the short labels emitted by stack_probe_poll() in freertos.c.
|
||||
@@ -55,6 +56,7 @@ RUNTIME_ALIAS = {
|
||||
"uiTask": "ui",
|
||||
"testTask": "test",
|
||||
"timeSyncTask": "timesync",
|
||||
"adcTask": "adc",
|
||||
}
|
||||
|
||||
FUNC_RE = re.compile(
|
||||
|
||||
@@ -116,13 +116,14 @@ static void start_and_clear(void) {
|
||||
s_feed_count = 0;
|
||||
}
|
||||
|
||||
/* 全员置位(默认必需掩码 0x37 = bit0|1|2|4|5) */
|
||||
/* 全员置位(默认必需掩码 0x77 = bit0|1|2|4|5|6,含 adcTask) */
|
||||
static void beat_all(void) {
|
||||
task_wd_beat(TASK_WD_DEFAULT);
|
||||
task_wd_beat(TASK_WD_NET);
|
||||
task_wd_beat(TASK_WD_FTP);
|
||||
task_wd_beat(TASK_WD_UI);
|
||||
task_wd_beat(TASK_WD_TIMESYNC);
|
||||
task_wd_beat(TASK_WD_ADC);
|
||||
}
|
||||
|
||||
/* ===================== 用例 ===================== */
|
||||
@@ -151,7 +152,7 @@ static void tc_003_all_beat_feeds(void) {
|
||||
beat_all();
|
||||
poll_advance(100);
|
||||
CHECK(s_feed_count == 1, "全员到位喂狗 1 次");
|
||||
CHECK(task_wd_last_mask() == 0x37u, "last_mask == 0x37(bit0|1|2|4|5)");
|
||||
CHECK(task_wd_last_mask() == 0x77u, "last_mask == 0x77(bit0|1|2|4|5|6)");
|
||||
}
|
||||
|
||||
static void tc_004_take_and_clear(void) {
|
||||
@@ -172,9 +173,10 @@ static void tc_005_mask_required(void) {
|
||||
task_wd_beat(TASK_WD_NET);
|
||||
task_wd_beat(TASK_WD_FTP);
|
||||
task_wd_beat(TASK_WD_TIMESYNC);
|
||||
task_wd_beat(TASK_WD_ADC);
|
||||
poll_advance(100);
|
||||
CHECK(s_feed_count == 0, "缺 UI 位 → 不喂狗");
|
||||
CHECK(task_wd_last_mask() == (0x37u & ~(1u << TASK_WD_UI)),
|
||||
CHECK(task_wd_last_mask() == (0x77u & ~(1u << TASK_WD_UI)),
|
||||
"last_mask 精确记录缺失位");
|
||||
}
|
||||
|
||||
@@ -250,7 +252,7 @@ static void tc_011_observers(void) {
|
||||
CHECK(task_wd_is_armed() == 1, "is_armed == 1(已启动)");
|
||||
beat_all();
|
||||
poll_advance(100);
|
||||
CHECK(task_wd_last_mask() == 0x37u, "last_mask 反映最近一次抽样");
|
||||
CHECK(task_wd_last_mask() == 0x77u, "last_mask 反映最近一次抽样");
|
||||
CHECK(task_wd_miss_count() == 0u, "全程达标 → miss_count == 0");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user