chore(注释): 清掉源码里不可检索的过程编码
清掉的(读者无从解析、且所指文档已不存在) - 已删任务文档的编号:Task #32、其内部 §5 / §4.3、P1-5、P0-2、P1-4a、 "方案 a"、"Lead 批准 2026-10-12" - 正文里当代词用的文件版本号:"(v2.7 起为 AboveNormal)""已随 v2.0 事件 驱动改造删除""(v2.0:DMA 消费)""见文件头 v1.3 说明"等 → 改写成陈述现状 - 测试与脚本同类:adc_input 桩头"v2.0:DMA 模型"、stub/adc.h 的 v2.0、 check_cubemx_survival.py 段头的"2026-10-10 v2.8"、run_all_suites.py 的"方案 A" 刻意保留 - 可检索登记簿锚点:P-AUDIT 真条目(P0-1/P1-8/P2-1/P2-9/P3-11)、S6/S11、 E-31/E-44、N-18/N-23/N-32、B1/B5/B7/B8、L1-x~L5-x 功能号 - 文件头修改记录块内的 vN.M(规范 V1.0 §2.1/§2.2 要求保留该块;块内编号 在本文件内自洽可读) 顺带纠正注释与代码已经不一致的过时事实 - 仍把 TIM6 写成现行节拍源:Src/main.c 的 include 注释与回调注释、 Src/freertos.c 的 adcTask 块 → 改 TIM3;adc_input.h 修订条目里"ADC1 只认 TIM2/TIM3/TIM8 的 TRGO"不准确 → 换成指向判据(ADC采样节拍设计说明 §3.2) - App/algo/phasor.c 双区注释称"唯一消费者是 adcTask、为后续保护任务预留", 实际 protectTask 已跨上下文读(prot_elm_run -> phasor_get)→ 改为"读者跨 adcTask 心跳与 protectTask 判据两个上下文,勿改加锁、勿取消双区",并同步 修正 docs/算法/采集与算法层设计说明.md 同一句 - adc_tick_irq_notify() 的"拒绝 ISR 内计算"理由仍写"内含 2 ms 忙等"(DMA 化 后已无忙等)→ 换成三条真实理由:任务级共享数据 / 计算量 / 生成区回调 - 裸 §5(指代不明)与"规划 §1.6 / 规划 §4"昵称式 → 写成完整路径紧邻式 字节卫生(Edit 会静默剥 BOM) - App/task/ui_task.c 与 Drivers/BSP/UI/ui_net_sink.c 被剥掉 BOM 两次,均按 3 字节 EF BB BF 前缀补回并复验;全部 20 个文件 CR=0、U+FFFD=0、无行尾空白 门禁 - @build 0 错误 0 警告,且 Program Size 与清理前逐项相同 (Code=213356 RO=18580 RW=1184 ZI=131480)→ 纯注释改动、中文未被误重编码 - ui-golden 首跑红:新工作树缺被 gitignore 的黄金参考 simulator/tests/ref/ (不入库、只在主工作树生成过);从主工作树复制该基线后复跑通过 → 注释改动 零像素影响 - 全套 pre-commit 在这 20 个文件上 Passed(coding-standard / cppcheck / 6 个主机单测 / doc-links / task-table / mem-numbers / cubemx-survival / registration-check / mem-budget / font-charset / ui-golden / id-check) - id-check 可判定比例 82.71% -> 82.88%(删掉的是"形似 P-AUDIT 但查无定义"的 假锚点),悬空引用 863 -> 854
This commit is contained in:
@@ -79,16 +79,16 @@ static int s_stm32_rc; /* STM32 最近一次扫描状态码 */
|
||||
static uint32_t s_stm32_errs; /* STM32 扫描累计失败次数 */
|
||||
|
||||
/*
|
||||
* 函数功能:消费一帧 STM32 ADC1 采样(L1-3,v2.0 DMA 双缓冲版)
|
||||
* 函数功能:消费一帧 STM32 ADC1 采样(L1-3,DMA 双缓冲)
|
||||
* 入口参数:无
|
||||
* 返 回 值:0 - 取到新一帧;-2 - 本拍无新帧(TIM3 未启动 / ADC 停摆 / DMA 出错)
|
||||
* 限定条件:仅任务上下文调用;adc_input_init() 已挂好 DMA
|
||||
* 函数说明:本函数**既不触发转换也不等待转换**——转换由 TIM3 TRGO 硬件触发、由 DMA
|
||||
* 自动搬运。每拍只做"看完成计数是否前进 + 拷 9 个半字",故**零忙等**:
|
||||
* 原轮询版常态 adcp=122 µs、超时拍最坏 2~3 ms,现在两档都降到 ~1 µs 量级。
|
||||
* 单拍只剩"读一个计数 + 拷 9 个半字"→ µs 量级。
|
||||
* 读的是"上一拍刚完成的那一半"乒乓缓冲(DMA 此刻正在写另一半)→ 无撕裂。
|
||||
* ⚠ 计数未前进 = 本拍 STM32 侧**无有效数据**,必须清 s_stm32_valid,绝不
|
||||
* 沿用上一拍旧值(同 2026-10-10 修的陈旧帧缺陷口径)→ adc_input_raw()
|
||||
* 沿用上一拍旧值(半新半旧的混合帧会污染相量窗)→ adc_input_raw()
|
||||
* 返 -2 → adc_task 走既有"整帧跳过"路径;下一拍自动恢复。
|
||||
*/
|
||||
static int stm32_take(void) {
|
||||
@@ -145,8 +145,8 @@ static int stm32_take(void) {
|
||||
* 函数说明:逐条校验映射表与扫描配置是否一致——① TPAFE 源下标须落在
|
||||
* buf[0..7];② STM32 源的通道号必须出现在 k_stm32_rank_ch[] 中,
|
||||
* 否则该通道永远不会被扫描(读到的恒为陈旧值)。这是"通道宏写错 →
|
||||
* 读到另一只脚/读不到"这一 §5 警告的代码级兜底(无信号源时无法做
|
||||
* 引脚级注入验证,见 docs/硬件平台/ADC通道映射说明.md §8)。
|
||||
* 读到另一只脚/读不到"这一警告的代码级兜底(警告口径与逐通道验证方法:
|
||||
* docs/硬件平台/ADC通道映射说明.md §5、§8;台架无信号源时注入验证做不了)。
|
||||
*/
|
||||
static int map_check(void) {
|
||||
uint8_t s;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 暴露,使上层(UI / 自检 / 保护算法)**按语义取数,不写死下标**:
|
||||
* ① 语义通道映射表(L1-4)——权威口径 docs/硬件平台/ADC通道映射说明.md;
|
||||
* ② STM32 ADC1 9 通道采样(L1-3)——由 **TIM3 TRGO 硬件触发 + DMA 双缓冲
|
||||
* 搬运**(v2.0),本层只消费、不触发、不等待。
|
||||
* 搬运**,本层只消费、不触发、不等待。
|
||||
* V0.1 上 8 路电气量分属两片转换器(硬件缺陷 N-18):UA/UN/IA 走
|
||||
* TPAFE5160(16 位 / ±5 V 双极性),UB/UC/IB/IC/IN 走 STM32 ADC1
|
||||
* (12 位 / 0~3.3 V 单极性)。V0.2 改版(8 路电气量全部接 TPAFE)
|
||||
@@ -16,8 +16,9 @@
|
||||
* v1.0 2026-10-10 王建锋 创建:L1-3(STM32 ADC1 扫描)+ L1-4(语义映射)
|
||||
* v2.0 2026-10-10 王建锋 STM32 侧改 TIM3 TRGO 硬件触发 + DMA 双缓冲消费:
|
||||
* 消除逐通道轮询的 2 ms 忙等;节拍源 TIM6 -> TIM3
|
||||
* (F4 上 ADC1 只认 TIM2/TIM3/TIM8 的 TRGO,TIM6 TRGO
|
||||
* 仅接 DAC);新增 adc_input_stm32_seq()/_hw_errs()
|
||||
* (换源判据:F4 上 ADC1 收不到 TIM6/TIM7 的 TRGO,见
|
||||
* docs/子系统设计/ADC采样节拍设计说明.md §3.2);新增
|
||||
* adc_input_stm32_seq() / _hw_errs()
|
||||
*/
|
||||
|
||||
#ifndef ADC_INPUT_H
|
||||
@@ -61,7 +62,7 @@ typedef struct {
|
||||
/* STM32 ADC1 顺序扫描通道数(Rank 1..9) */
|
||||
#define ADC_INPUT_STM32_CH_NUM 9U
|
||||
|
||||
/* STM32 ADC1 最近一次取帧状态码(v2.0:DMA 消费,已无"轮询超时"这一档) */
|
||||
/* STM32 ADC1 最近一次取帧状态码(DMA 消费,已无"轮询超时"这一档) */
|
||||
#define ADC_INPUT_RC_OK (0) /* 取到新一帧 */
|
||||
#define ADC_INPUT_RC_START (-1) /* HAL_ADC_Start_DMA 挂载失败 */
|
||||
#define ADC_INPUT_RC_STALL (-2) /* 本拍无新帧(TIM3 未启动 / ADC 停摆 / DMA 出错) */
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
* ≈4 个信号周波),使窗长恰为纹波周期的整数倍 → δ(m+K)≈δ(m),残差进入
|
||||
* 0.01 Hz 量级。f_hat 用上一拍读数(收敛后误差 <0.1 Hz → K_eff 偏差 <1 拍,
|
||||
* 自洽)。
|
||||
* **精度优先于响应的显式取舍(Lead 批准 2026-10-12)**:4 周波窗换来
|
||||
* **精度优先于响应的显式取舍**:4 周波窗换来
|
||||
* 0.317→0.0101 Hz,代价是频率骤变后的窗冲刷(J4 阶跃整定 ≤120 ms,实测
|
||||
* 98 ms)。OF/UF 定时限默认 1000 ms → 测频响应占保护总动作时间 <10%;
|
||||
* 暂态假值另有 J6(跳变后 ≤60 ms 回 ±0.05 Hz)兜底。故 J4 的 120 ms 是
|
||||
|
||||
+3
-3
@@ -44,7 +44,7 @@ static const float k_fft_cos[PHASOR_N] = {
|
||||
/* ===== L2-2 相量实例表 =====
|
||||
* 参考项目为 **4 个实例**(C01 基波 I/U、C02 零序基波、C03 二次谐波、C04 五次谐波,
|
||||
* `APP/CLS100_Dsp/InstCalCell.c`)。本项目按 V0.1 **有效通道**(`UA`/`UN`/`IA`,
|
||||
* 见规划 §1.6:`UB/UC/IB/IC/IN` 无中点偏置 → 削顶不可用)展开——C01 的"I/U"
|
||||
* 见 docs/算法/继电保护功能复现规划.md §1.6:`UB/UC/IB/IC/IN` 无中点偏置 → 削顶不可用)展开——C01 的"I/U"
|
||||
* 拆为两行(IA 电流 / UA 电压),并补出 C04 的五次谐波轨(L1-9)。
|
||||
* 新增实例只需在表尾加一行,其余代码自动适配。 */
|
||||
static const phasor_inst_t k_inst[] = {
|
||||
@@ -62,8 +62,8 @@ static const phasor_inst_t k_inst[] = {
|
||||
* (单字节 store,Cortex-M 上原子),消费侧读"使用区" → 无锁、无撕裂。
|
||||
* s_use_zone 声明 volatile:阻止编译器把结果写入挪到切换之后
|
||||
* (本平台单核顺序执行,无需额外内存屏障)。
|
||||
* 今日唯一消费者是 adcTask 自身(同拍读写、实际无竞争),本机制为后续
|
||||
* 独立保护任务(L3)预留。 */
|
||||
* 写者 = adcTask(同拍);读者跨两个上下文:adcTask 心跳与 protectTask 判据
|
||||
* (prot_elm_run → phasor_get)→ 无锁读正是为后者服务,勿改成加锁或去掉双区。 */
|
||||
static phasor_t s_zone[2][PHASOR_INST_N];
|
||||
static volatile uint8_t s_use_zone;
|
||||
static uint8_t s_ready; /* 使用区是否已产出过有效结果 */
|
||||
|
||||
+1
-1
@@ -290,7 +290,7 @@ int app_main_init(void) {
|
||||
* ② 同一事件经 TRGO 硬件触发 STM32 ADC1 一轮 9 通道转换(DMA 自动搬运)。
|
||||
* ⚠ 必须在 tpafe5160_init() 成功之后启动,否则 ISR 会在驱动首帧自检
|
||||
* (E-44 有效性探针)期间乱发 CONVST。消费端 adcTask 退化为纯消费者。
|
||||
* ⚠ 节拍源 v2.0 由 TIM6 改为 **TIM3**:F4 上 ADC1 的外部触发只认
|
||||
* ⚠ 节拍源必须能触发 ADC1,故用 **TIM3**:F4 上 ADC1 的外部触发只认
|
||||
* TIM1/TIM2/TIM3/TIM4/TIM5/TIM8 的 CC 或 TRGO,**TIM6/TIM7 的 TRGO 只接
|
||||
* DAC**(查 CubeMX DB 与本仓库 stm32f4xx_hal_adc.h 的 EXTSEL 表证实)
|
||||
* → 要让两片转换器由同一个硬件事件驱动,节拍源必须换成 TIM3。 */
|
||||
|
||||
+29
-31
@@ -7,15 +7,15 @@
|
||||
* 状态说明:**B1 已落地(2026-10-10)**——本任务从空桩转为真实消费者:
|
||||
* 用 tpafe5160_snapshot() 原子取数(AGENTS 铁律),统计帧数/无新帧次数,
|
||||
* 并纳入看门狗 required_mask(TASK_WD_ADC)。
|
||||
* **采样节拍(v2.2,2026-10-10)**:由 **TIM3 更新中断(1 kHz)** 硬件触发——
|
||||
* **采样节拍**:由 **TIM3 更新中断(1 kHz)** 硬件触发——
|
||||
* ISR 内调 tpafe5160_start_conv_irq()(Src/main.c 的
|
||||
* HAL_TIM_PeriodElapsedCallback);本任务**不再自行触发**,退化为**纯消费者**。
|
||||
* **消费唤醒(v2.7,2026-10-10,Task #32 P1-5 方案 a)**:由 1 ms `osDelayUntil`
|
||||
* **消费唤醒**:由 1 ms `osDelayUntil`
|
||||
* 轮询改为 **TIM3 ISR 置位 `ADC_WAKE_FLAG` 的事件驱动**——唤醒与生产同源锁定,
|
||||
* 消除 0~1 ms 的 tick 量化相位抖动与"超拍永久落后 → 空转"风险;本任务优先级
|
||||
* 同步由 Normal 提到 **AboveNormal**(唤醒即抢占)。详见
|
||||
* docs/子系统设计/ADC采样节拍设计说明.md §6。
|
||||
* **L1 采集层(v2.3,2026-10-10)**:取数改走 App/algo/adc_input.c——
|
||||
* **L1 采集层**:取数改走 App/algo/adc_input.c——
|
||||
* 本任务每拍调 adc_input_poll()(TPAFE 快照 + STM32 ADC1 9 通道扫描),
|
||||
* 经 adc_input_raw() **按语义**读通道(L1-3/L1-4),不再直接触碰驱动缓冲。
|
||||
* V0.1 上只有 TPAFE 三路(UA/UN/IA)测量有效;本任务只取数,不做保护运算。
|
||||
@@ -49,25 +49,25 @@
|
||||
* ⚠ L1-5 通道标定未实现(缺标准源)→ 暂以**原始码值**
|
||||
* 充作工程量(系数 = 1),故相量读数只证明**链路通**,
|
||||
* 不可作幅值精度判据(同 L1-3 的替代口径)。
|
||||
* v2.5 2026-10-10 王建锋 Task #32 的 P2 测量埋点:单拍加常开耗时探针
|
||||
* v2.5 2026-10-10 王建锋 常开耗时测量埋点:单拍加探针
|
||||
* (task_prof ADC_BEAT),用于判定本任务是否超拍
|
||||
* (名义节拍 1 ms = 168000 周期)而挤占低优先级任务
|
||||
* v2.6 2026-10-10 王建锋 Task #32 的 P0 修复(两处):
|
||||
* §5 无新帧仍压环 → 改为**仅 r == 1 时**压环 + 重算
|
||||
* v2.6 2026-10-10 王建锋 两处正确性修复:
|
||||
* 无新帧仍压环 → 改为**仅 r == 1 时**压环 + 重算
|
||||
* (消除重复采样污染 20 点 DFT 窗的系统性误差);
|
||||
* §4.3 osDelayUntil 返回值被丢弃 → 落后时一次性重同步
|
||||
* osDelayUntil 返回值被丢弃 → 落后时一次性重同步
|
||||
* (原写法会永久落后 → 不再阻塞 → 空转抢占 uiTask)
|
||||
* v2.7 2026-10-10 王建锋 Task #32 P1-5 方案 a(事件驱动消费):
|
||||
* v2.7 2026-10-10 王建锋 事件驱动消费改造:
|
||||
* 消费唤醒 osDelayUntil(1ms) → osThreadFlagsWait(ADC_WAKE_FLAG,
|
||||
* osWaitForever),标志由 TIM3 ISR 经 adc_tick_irq_notify() 置位;
|
||||
* 删除 ADC_TASK_BEAT_MS 与 next(P0-2 的重同步因此不再需要);
|
||||
* 删除 ADC_TASK_BEAT_MS 与 next(上一轮加的重同步钩子因此不再需要);
|
||||
* 新增"消费者就绪"门 s_consumer_ready——TIM3 在 app_main_init()
|
||||
* 就启动,**远早于** MX_FREERTOS_Init()/osKernelStart(),
|
||||
* ISR 不得在此之前对内核动手(同 Src/main.c 里 TIM7 的
|
||||
* 2026-10-02 实测坑)。优先级 Normal → AboveNormal(见 freertos.c)
|
||||
* v2.8 2026-10-10 王建锋 节拍源 TIM6 → **TIM3**(F4 上 ADC1 的外部触发没有
|
||||
* TIM6 TRGO,只有 TIM2/TIM3/TIM8 系 → 换 TIM3 才能让
|
||||
* 两片转换器由同一硬件事件驱动);STM32 侧改 DMA 双缓冲
|
||||
* v2.8 2026-10-10 王建锋 节拍源换 TIM3(F4 上 ADC1 收不到 TIM6/TIM7 的
|
||||
* TRGO,换源判据见 docs/子系统设计/ADC采样节拍设计说明.md
|
||||
* §3.2);STM32 侧改 DMA 双缓冲
|
||||
* 消费,adc_input_poll() 不再忙等;心跳日志增
|
||||
* adc1_seq / adc1_hw(adc1_err 语义改为"本拍无新帧")
|
||||
* v2.9 2026-10-11 王建锋 L1-6 采样有效性校验:每拍调 adc_health_check()
|
||||
@@ -90,13 +90,13 @@
|
||||
#include "task_watchdog.h"
|
||||
#include "console_log.h"
|
||||
#include "sys_log.h" /* SYSLOG_SELFTEST:采样故障留痕(仅故障才写) */
|
||||
#include "task_prof.h" /* P2 常开探针:单拍耗时(Task #32) */
|
||||
#include "task_prof.h" /* 常开耗时探针:单拍耗时 */
|
||||
|
||||
#define DBG_TAG "[ADC_TASK]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
/* 心跳日志周期(ms):周期性上报帧统计,作为采集链路存活的观测面。
|
||||
* (原 ADC_TASK_BEAT_MS = 1U 的消费轮询周期已随 v2.7 事件驱动改造删除——
|
||||
* (原 ADC_TASK_BEAT_MS = 1U 的消费轮询周期已随事件驱动改造删除——
|
||||
* 消费节拍改由 TIM3 ISR 置位 ADC_WAKE_FLAG 提供,与生产同源,不再自定周期) */
|
||||
#define ADC_TASK_REPORT_MS 10000U
|
||||
|
||||
@@ -135,8 +135,8 @@ static volatile uint8_t s_consumer_ready;
|
||||
* 返 回 值:无
|
||||
* 限定条件:仅 ISR 上下文。TIM3 抢占优先级 = 6 ≥ configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
|
||||
* (=5) → osThreadFlagsSet 走 xTaskNotifyFromISR + portYIELD_FROM_ISR,合法且立即切换
|
||||
* 函数说明:Task #32 P1-5 方案 a——ISR **只发唤醒**,全部计算留在任务里(拒绝"ISR 内计算":
|
||||
* adc_input_poll() 内含 2 ms 忙等,绝不可入 ISR)。线程标志粘滞 → 单拍偶超 1 ms 时
|
||||
* 函数说明:ISR **只发唤醒**,全部计算留在任务里——"ISR 内计算"是反模式:取数与相量
|
||||
* 计算都读写任务级共享数据,且本回调属 CubeMX 生成区,重生成即丢。线程标志粘滞 → 单拍偶超 1 ms 时
|
||||
* 多个脉冲合并成一次唤醒,下一轮 adc_input_poll() 返回 r==0 记 idle,不会重复处理同一帧
|
||||
*/
|
||||
void adc_tick_irq_notify(void) {
|
||||
@@ -248,7 +248,7 @@ int adc_task_init(void) {
|
||||
* 限定条件:adc_task_init() 已调用;内核已启动
|
||||
* 函数说明:每拍采集一次(adc_input_poll():TPAFE 原子快照 + 消费一帧 STM32 ADC1 DMA 乒乓缓冲)
|
||||
* 并统计。采样节拍由 TIM3 硬件定时器提供(ISR 内触发 CONVST),本任务不再触发;
|
||||
* **本任务的唤醒同样由该 TIM3 ISR 置位 ADC_WAKE_FLAG 驱动**(v2.7 事件驱动,
|
||||
* **本任务的唤醒同样由该 TIM3 ISR 置位 ADC_WAKE_FLAG 驱动**(事件驱动,
|
||||
* 不再自定 1 ms 周期)。稳态下 consumed 每拍 +1、idle 不再增长;idle 持续增长 =
|
||||
* EXTI 未在读帧或 TIM3 未启动(异常),由周期心跳日志暴露。
|
||||
* ⚠ 若 TIM3 停摆,本任务会**永久阻塞**在 osThreadFlagsWait → TASK_WD_ADC 缺席 →
|
||||
@@ -269,8 +269,8 @@ void adc_task_func(void *arg) {
|
||||
int r;
|
||||
uint32_t now = osKernelGetTickCount(); /* 本拍时基:健康判定 + 心跳共用一份 */
|
||||
|
||||
/* P2 探针:单拍起点。名义节拍 1 ms = 168000 周期;若实测**持续**超过,
|
||||
* 本任务(v2.7 起为 osPriorityAboveNormal)会持续抢占 uiTask
|
||||
/* 探针:单拍起点。名义节拍 1 ms = 168000 周期;若实测**持续**超过,
|
||||
* 本任务(osPriorityAboveNormal)会持续抢占 uiTask
|
||||
* (osPriorityBelowNormal),是"UI 心跳缺席"的候选占用者之一 */
|
||||
task_prof_enter(TASK_PROF_ADC_BEAT);
|
||||
|
||||
@@ -278,9 +278,8 @@ void adc_task_func(void *arg) {
|
||||
* DMA 双缓冲(仅任务上下文;TPAFE 侧 1=有新帧 0=无新帧 -1=参数错)。
|
||||
* 采样节拍由 TIM3 更新事件提供(ISR 内触发 CONVST + TRGO 触发 ADC1),
|
||||
* 本任务既不触发也不等待转换。
|
||||
* P2 探针:本段单独计时。v2.0(DMA)起本段**零忙等**——原轮询版常态
|
||||
* adcp=122 us、超时拍最坏 2~3 ms(HAL_ADC_PollForConversion 是不让出的
|
||||
* 忙等),现在两档都降到 us 量级(只剩 TPAFE 快照临界区 + 拷 9 个半字)。
|
||||
* 探针:本段单独计时。本段**零忙等**(转换由 TIM3 TRGO 触发、DMA 搬运,
|
||||
* 不再有逐通道轮询超时),只剩 TPAFE 快照临界区 + 拷 9 个半字 → us 量级。
|
||||
* ⚠ adcm(整拍)的 ~2.1 ms 峰值来自每 10 s 一次的心跳日志,不是本段,勿混读 */
|
||||
task_prof_enter(TASK_PROF_ADC_POLL);
|
||||
r = adc_input_poll();
|
||||
@@ -296,13 +295,12 @@ void adc_task_func(void *arg) {
|
||||
/* 2) L2 输入 + 相量重算:把本拍 9 路语义值转浮点帧压入采样环,再重算全部
|
||||
* 相量实例(L2-6 滑动窗:每拍以"当前时刻为终止的前一周波"整窗重算)。
|
||||
*
|
||||
* ⚠ P0 修复(2026-10-10,Task #32 §5):**仅在本拍确有新帧(r == 1)时**才压环。
|
||||
* ⚠ **仅在本拍确有新帧(r == 1)时**才压环。
|
||||
* 原实现在 r == 0(TPAFE 无新帧)时**仍然**压环 + phasor_run(),只有 r == -1
|
||||
* 才跳过 —— 于是把**上一拍的重复采样值**塞进 20 点 DFT 窗,等效采样间隔被拉长。
|
||||
* 证据是日志里的恒等式 `ring = frames + idle`(09:36:21: 9957+44=10001 ✓;
|
||||
* 09:36:31: 19352+649=20001 ✓)。本例 idle 占 3.2% → 窗长从 20.0 ms 漂到约
|
||||
* 20.6 ms → 对 50 Hz 信号相当于约 3% 的频率失配 → 幅值/相位**系统性**误差
|
||||
* (不是随机噪声)。修好后 `ring` 只在真实新帧上增长(ring == frames)。
|
||||
* 量级参考(台架曾测得 idle 占 3.2%):窗长从 20.0 ms 漂到约 20.6 ms → 对 50 Hz
|
||||
* 相当于约 3% 频率失配 → 幅值/相位**系统性**误差(不是随机噪声)。
|
||||
* 回归判据 = 恒等式 `ring == frames`(只有真新帧才入环)。
|
||||
*
|
||||
* 任一通道读不到(尚未首次成功)→ 本拍**整帧跳过**:不向窗内注入 0 点
|
||||
* (单个 0 点会显著污染 20 点窗),并计入 skip 观测。 */
|
||||
@@ -398,7 +396,7 @@ void adc_task_func(void *arg) {
|
||||
{
|
||||
if ((int32_t)(now - report_at) >= 0) {
|
||||
if (dbg_console_writer_ready() != 0u) {
|
||||
/* STM32 侧观测量(v2.0 DMA 版),四类各有独立成因:
|
||||
/* STM32 侧观测量(DMA 版),四类各有独立成因:
|
||||
* adc1_rc = 最近一拍取帧状态(0 OK / -2 本拍无新帧)
|
||||
* adc1_seq = DMA 整帧完成计数(正常时 ≈ seq,恒定小偏移)
|
||||
* adc1_gap = 丢帧:seq 一次前进 >1 → 本任务超拍(单拍 > 1 ms)
|
||||
@@ -429,16 +427,16 @@ void adc_task_func(void *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 7) 等下一次节拍唤醒(v2.7 事件驱动,Task #32 P1-5 方案 a)
|
||||
/* 7) 等下一次节拍唤醒(事件驱动)
|
||||
* 原实现是 osDelayUntil(next += 1ms):把消费唤醒**钉在 FreeRTOS tick(1 ms)边界**
|
||||
* → 与 TIM3 生产之间有 0~1 ms 随机相位抖动(日志里的 idle 正是这么来的),
|
||||
* 且一旦超拍,next 就永久落后 → 任务不再阻塞 → 空转抢占低优先级 uiTask
|
||||
* (P0-2 修的正是它)。现在唤醒与生产**同源**:TIM3 ISR 触发 CONVST 后置位
|
||||
* (空转抢占低优先级任务正是这么发生的)。现在唤醒与生产**同源**:TIM3 ISR 触发 CONVST 后置位
|
||||
* ADC_WAKE_FLAG,本任务被唤醒的延迟 = ISR + 调度(µs 级;本任务已提至
|
||||
* AboveNormal → 立即抢占),无 tick 量化、无累积漂移,也就不再需要重同步钩子。
|
||||
* 标志是命令位(等待即消费)→ osFlagsWaitAny,不加 osFlagsNoClear;
|
||||
* osWaitForever 无超时 = 刻意的 fail-safe(TIM3 停摆 → 无心跳 → IWDG 复位)。 */
|
||||
task_prof_exit(TASK_PROF_ADC_BEAT); /* P2 探针:单拍耗时结算(不含等待) */
|
||||
task_prof_exit(TASK_PROF_ADC_BEAT); /* 探针:单拍耗时结算(不含等待) */
|
||||
(void)osThreadFlagsWait(ADC_WAKE_FLAG, osFlagsWaitAny, osWaitForever);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
* 创建日期:2026-07-19
|
||||
* 修改记录:
|
||||
* v1.0 2026-07-19 王建锋 创建初始版本
|
||||
* v1.1 2026-10-10 王建锋 Task #32 P1-5 方案 a:新增 ADC_WAKE_FLAG 与
|
||||
* v1.1 2026-10-10 王建锋 新增 ADC_WAKE_FLAG 与
|
||||
* adc_tick_irq_notify()——消费节拍由 osDelayUntil(1ms)
|
||||
* 轮询改为 TIM3 ISR 事件驱动唤醒
|
||||
*/
|
||||
@@ -21,7 +21,7 @@ extern "C" {
|
||||
int adc_task_init(void);
|
||||
void adc_task_func(void *arg);
|
||||
|
||||
/* Task #32 P1-5(方案 a,2026-10-10):事件驱动消费。
|
||||
/* 事件驱动消费的唤醒标志。
|
||||
* TIM3 1 kHz 更新中断触发 CONVST 后,用本标志唤醒 adcTask 消费一拍。
|
||||
* 线程标志在此是**命令位**(等待即消费),不是状态位 → 用 osFlagsWaitAny,
|
||||
* 不加 osFlagsNoClear(AGENTS「就绪屏障位必须 osFlagsNoClear」只约束状态位) */
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* FTP 文件操作与 syslog/配置的卷访问自此串行化
|
||||
* (2026-10-02 台架:并发 FTL 写 → journal 竞争 →
|
||||
* 本任务主循环喂狗点饥饿 → IWDG 误复位)
|
||||
* v1.2 2026-10-10 王建锋 Task #32 的 P2 测量接线:主循环周期上报各任务最坏
|
||||
* v1.2 2026-10-10 王建锋 任务耗时测量接线:主循环周期上报各任务最坏
|
||||
* 耗时(task_prof_report),并在**心跳位图出现 1→0 边沿**
|
||||
* 的瞬间留一份现场快照(task_prof_report_raw,裸 UART);
|
||||
* 另给控制台排空与 syslog 落盘各加一个耗时探针
|
||||
@@ -44,7 +44,7 @@
|
||||
#define DBG_LINE_BUF_MAX 128U
|
||||
#include "dbg_log.h"
|
||||
#include "task_watchdog.h"
|
||||
#include "task_prof.h" /* P2 测量:各任务最坏耗时上报(Task #32) */
|
||||
#include "task_prof.h" /* 各任务最坏耗时上报 */
|
||||
#include "vol_lock.h"
|
||||
|
||||
/* 任务句柄与属性块(CubeMX 生成全局,定义于 Src/freertos.c):
|
||||
@@ -199,7 +199,7 @@ void default_task_func(void *argument) {
|
||||
task_wd_seg(TASK_WD_SEG_POLL);
|
||||
/* 心跳抽样与喂狗判定(内部节流至 100ms;全员到位才喂,否则累计停喂) */
|
||||
task_wd_poll();
|
||||
/* P2 测量(Task #32):某位由"到过"变为"缺席"的瞬间留一份现场快照。
|
||||
/* 耗时测量:某位由"到过"变为"缺席"的瞬间留一份现场快照。
|
||||
* 走裸 UART 直发——缺席窗口内环形缓冲可能积压,这两行必须出去。
|
||||
*
|
||||
* ⚠ 判据用**位图边沿**,不能用 miss 累计数:`task_wd_miss_count()` 返回的是
|
||||
@@ -299,7 +299,7 @@ void default_task_func(void *argument) {
|
||||
/* 栈水位观测:首次 5s 后报告,此后每 2s 采样、出现更深峰值才打印 */
|
||||
task_wd_seg(TASK_WD_SEG_STACK);
|
||||
stack_probe_poll();
|
||||
/* P2 测量(Task #32):各任务最坏耗时 / 次数 / "仍在段内"快照。
|
||||
/* 各任务最坏耗时 / 次数 / "仍在段内"快照上报。
|
||||
* 内部节流(首次 5s,此后每 2s);判据:
|
||||
* uisn 持续增长 → uiTask 卡在 ui_net_sink_poll 的往返里(阻塞)
|
||||
* uipn 持续增长而 uisn 为 0 → 被调度饿死(本轮迟迟跑不完)
|
||||
|
||||
+2
-2
@@ -18,7 +18,7 @@
|
||||
* freertos.c USER CODE 区重复创建已删除
|
||||
* v1.7 2026-10-02 王建锋 P1-8:初始组网失败/重建失败 → 自检记录 + 30s 周期重试
|
||||
* (原实现:初始失败 = netTask 无限驻留;重建失败 = 静默丢配置)
|
||||
* v1.8 2026-10-10 王建锋 Task #32 的 P2 测量埋点:net_poll() 单独计时——
|
||||
* v1.8 2026-10-10 王建锋 任务耗时测量埋点:net_poll() 单独计时——
|
||||
* 本任务每 ~1ms 分派一次消息队列,若驱动轮询被拉长,
|
||||
* 其它任务(尤其 UI 的 net_accept 往返)的等待随之拉长
|
||||
*/
|
||||
@@ -34,7 +34,7 @@
|
||||
#include "sys_log.h"
|
||||
#include "test_config.h" /* 测试模式宏(ENABLE_HW_LAYER_TESTS);产品构建全未定义,无作用 */
|
||||
#include "task_watchdog.h"
|
||||
#include "task_prof.h" /* P2 探针:net_poll 耗时(Task #32) */
|
||||
#include "task_prof.h" /* 探针:net_poll 耗时 */
|
||||
|
||||
#define DBG_TAG "[NET_TASK]"
|
||||
#include "dbg_log.h"
|
||||
|
||||
+5
-5
@@ -6,11 +6,11 @@
|
||||
* 创建日期:2026-08-30
|
||||
* 修改记录:
|
||||
* v1.1 2026-09-14 王建锋 新增待机显示页初始化(ui_standby_init,空闲 60s 切入)
|
||||
* v1.2 2026-10-10 王建锋 Task #32 的 P2 测量埋点:主循环加常开探针
|
||||
* v1.2 2026-10-10 王建锋 任务耗时测量埋点:主循环加常开探针
|
||||
* (循环周期 / 单轮工作耗时 / ui_net_sink_poll 往返),
|
||||
* 用于把"心跳缺席"拆成 饿死 / 阻塞在往返 / 自身拖长
|
||||
* 三种互斥机理(判读见 docs/子系统设计/看门狗设计说明.md §11.4)
|
||||
* v1.3 2026-10-10 王建锋 Task #32 的 P1-4a(解耦心跳,看门狗设计说明 §11.3):把 task_wd_beat
|
||||
* v1.3 2026-10-10 王建锋 解耦心跳(docs/子系统设计/看门狗设计说明.md §11.3):把 task_wd_beat
|
||||
* (TASK_WD_UI) 提到 ui_net_sink_poll() **之前**。原写法心跳
|
||||
* 在推流往返之后 → 心跳周期 = 渲染 + 一次 netTask 往返 + 10ms,
|
||||
* 实测 uiw≈uis≈50ms(心跳被 netTask 往返主导),心跳实际测的是
|
||||
@@ -128,7 +128,7 @@ void ui_task_func(void *argument) {
|
||||
uint8_t tm_loop_valid = 0U;
|
||||
#endif
|
||||
|
||||
/* P2 常开探针(Task #32):TEST_LATENCY_PROBE 只在 CH395F 套件构建下打开,
|
||||
/* 常开探针:TEST_LATENCY_PROBE 只在 CH395F 套件构建下打开,
|
||||
* 且样本消费者是 testTask(产品构建里不跑)→ 产品构建拿不到任何 UI 周期数据。
|
||||
* 故此处独立埋点,恒定生效、只写本模块的静态计数,由 defaultTask 周期上报。 */
|
||||
|
||||
@@ -151,12 +151,12 @@ void ui_task_func(void *argument) {
|
||||
tm_loop_valid = 1U;
|
||||
#endif
|
||||
ui_port_step(UI_TASK_TICK_MS);
|
||||
/* 心跳**先于**推流往返发出(P1-4a,看门狗设计说明 §11.3):UI 心跳测的是
|
||||
/* 心跳**先于**推流往返发出(判读口径 docs/子系统设计/看门狗设计说明.md §11.3):UI 心跳测的是
|
||||
* "UI 自身被调度到了",而非"netTask 回执快慢"。原写法心跳在 sink 之后,
|
||||
* 致实测 uiw≈uis≈50ms(心跳被 netTask 往返主导)。提到往返之前后,
|
||||
* 即使往返偶发变慢,心跳也不被其拖垮。
|
||||
* ⚠ 若往返**永久**阻塞(xTaskNotifyWait portMAX_DELAY 不返回),本改只能发
|
||||
* 一次心跳,救不了 → 彻底解耦须走事件驱动 accept,见文件头 v1.3 说明。 */
|
||||
* 一次心跳,救不了 → 彻底解耦须走事件驱动 accept,见文件头修改记录 v1.3。 */
|
||||
task_wd_beat(TASK_WD_UI);
|
||||
/* 推流轮询段单独 enter/exit:它内部经 net_accept → net_wait_result 走到
|
||||
* xTaskNotifyWait(portMAX_DELAY) 的**无限期阻塞**。若 uiTask 永久卡在这里,
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-10
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-10 王建锋 创建(Task #32 的 P2 测量埋点)
|
||||
* v1.0 2026-10-10 王建锋 创建:常开任务耗时探针
|
||||
*
|
||||
* 设计依据:docs/子系统设计/看门狗设计说明.md §11.4(探针字段语义与实测基线)
|
||||
*/
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* 作者:王建锋
|
||||
* 创建日期:2026-10-10
|
||||
* 修改记录:
|
||||
* v1.0 2026-10-10 王建锋 创建(Task #32 的 P2 测量埋点)
|
||||
* v1.0 2026-10-10 王建锋 创建:常开任务耗时探针
|
||||
*
|
||||
* 设计背景(docs/子系统设计/看门狗设计说明.md §11.4):
|
||||
* uiTask 偶发心跳缺席导致 IWDG 复位,但"占用者"无法从既有日志判定。
|
||||
|
||||
Reference in New Issue
Block a user