Files
STM32F4-Base/App/algo/adc_input.h
T
wandering1 790e153cd6 fix(adc_input): 丢帧计数改按帧点数累计,与 TPAFE 侧 tgap 同单位
读码确认的口径缺陷:两片转换器的丢帧计数单位不一致——TPAFE 侧
adc_health_tpafe_gaps() 按 (d-1) 加权记「帧点数」,STM32 侧
adc_input_stm32_gaps() 每次事件只 +1 记「次数」。两者都被当作心跳字段
并排打印(adc1_gap / tgap),一次跨多帧时数值就分叉:同样丢 3 帧,
一边记 2、一边记 1。跨字段对比或做除法会得出错误结论。

选 A(改代码,真对称)而不是只改字段名:
- 单拍超一帧(d=2)时两者数值相同,历史上绝大多数样本本来就等价,
  换单位对既有判读习惯冲击很小;
- 只在一次跨 ≥2 帧时分叉,而那正是心跳日志突发期最常见的形态,
  留在文档里当"注意点"迟早还会读错一次。

改动:
- adc_input.c:s_stm32_gaps += (d - 1u)(d = seq - s_dma_seq_seen,
  顺带把已算过的差值提成局部变量 d,不再重复算一遍)
- adc_input.h / adc_input.c 函数头:单位写明「Σ 每次前进的超出部分」,
  并点名 2026-10-21 之前固件该字段是次数口径,跨版本日志不可直接对比
- 用例:原两档只跨 1 帧(前进 2 记 1),钉不出单位;补第二档——连投
  3 帧不消费(一次跨 2 帧)必须记 2 点、累计 1+2=3。补充断言沿用所属
  用例覆盖点,不另立新编号,也不在文档外复制用例号(编号门禁按文件内
  实例数比对台账豁免,多写一处即被判新债)
- 文档同步:ADC采样节拍设计说明 §8/§9 字段口径与稳态基线、采集与算法
  层设计说明 §3/§4、采样有效性校验设计说明 §6.2/§10/§11(并把"两车道
  单位不同"从观测盲区降级为"历史日志口径差异")、ADC输入层单元测试
  说明用例表该行;两张配图生成器文案同步

实测:
- @build 0 错 0 警;Program Size 与上一提交**逐字节相同**(Code=213520
  RW=1184 ZI=131504)——编译器早已为半区推导算过同一差值并复用,
  故本次净增 0 B,不产生新的台账漂移
- 主机单测:ADC 输入层 103/103、ADC 有效性 45/45
- stack_report:adcTask 1320 B / protectTask 872 B 均不变
- 字节卫生:BOM 无 / CR 0 / U+FFFD 0 / 文件尾换行齐
- id-check:Passed(曾因新增用例号实例触发"台账之外 +2",已按不复制
  用例号的方式消除,未动 id_known_backlog.json 台账)

gate: only mem-budget/mem-numbers pending lead ledger backfill
pre-commit run --all-files 失败仅这两条,漂移量来自上一条提交 6f90600
(+96 B Code / +24 B ZI);本条自身 0 B。按并行分支约定本分支不跑
--write,台账由 Lead 合并后统一回填。
2026-10-22 00:43:32 +08:00

169 lines
7.6 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称:ADC 输入层(L1 采集与预处理)
* 模块功能:把两片转换器的原始码值按**语义**(UA/UB/UC/UN/IA/IB/IC/IN/温度)统一
* 暴露,使上层(UI / 自检 / 保护算法)**按语义取数,不写死下标**:
* ① 语义通道映射表(L1-4)——权威口径 docs/硬件平台/ADC通道映射说明.md;
* ② STM32 ADC1 9 通道采样(L1-3)——由 **TIM3 TRGO 硬件触发 + DMA 双缓冲
* 搬运**,本层只消费、不触发、不等待。
* 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)
* 只改映射表内容,本层 API 与上层语义不动。
* 适用平台:STM32F407ZGTx + TPAFE5160
* 作者:王建锋
* 创建日期:2026-10-10
* 修改记录:
* 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 收不到 TIM6/TIM7 的 TRGO,见
* docs/子系统设计/ADC采样节拍设计说明.md §3.2);新增
* adc_input_stm32_seq() / _hw_errs()
* v2.1 2026-10-21 王建锋 adc_input_stm32_gaps() 单位由「次数」改为「帧点数」,
* 与判定层 adc_health_tpafe_gaps() 同单位
*/
#ifndef ADC_INPUT_H
#define ADC_INPUT_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* 语义通道(V0.1:8 路电气量 + 温度)。枚举值即语义编号,顺序不得随意变更;
* 备用通道(RESERVED)不接入语义,故不在此枚举内。 */
typedef enum {
ADC_SEM_UA = 0, /* A 相电压(TPAFE) */
ADC_SEM_UB, /* B 相电压(STM32) */
ADC_SEM_UC, /* C 相电压(STM32) */
ADC_SEM_UN, /* 零线电压(TPAFE) */
ADC_SEM_IA, /* A 相电流(TPAFE) */
ADC_SEM_IB, /* B 相电流(STM32) */
ADC_SEM_IC, /* C 相电流(STM32) */
ADC_SEM_IN, /* 零线电流(STM32) */
ADC_SEM_TEMP, /* 温度(STM32,V_ZL2) */
ADC_SEM_COUNT /* 语义通道数(哨兵) */
} adc_semantic_t;
/* 数据来源:V0.1 的 8 路电气量分属两片转换器(N-18) */
typedef enum {
ADC_SRC_TPAFE = 0, /* TPAFE5160:16 位、±5 V 双极性、8 通道同步 */
ADC_SRC_STM32 /* STM32 ADC1:12 位、0~3.3 V 单极性、9 通道顺序扫描 */
} adc_source_t;
/* 语义通道 → 物理通道描述 */
typedef struct {
adc_source_t source; /* 数据来源 */
uint8_t index; /* TPAFE 源:驱动 buf 下标 0..7;STM32 源:ADC1 通道号 0..15 */
} adc_channel_desc_t;
/* TPAFE5160 一帧通道数(= 驱动 buf 长度) */
#define ADC_INPUT_TPAFE_CH_NUM 8U
/* STM32 ADC1 顺序扫描通道数(Rank 1..9) */
#define ADC_INPUT_STM32_CH_NUM 9U
/* 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 出错) */
#define ADC_INPUT_RC_NOT_RUN (-3) /* 尚未取过帧 */
/*
* 函数功能:ADC 输入层初始化
* 入口参数:无
* 返 回 值:0 - 成功;-1 - 语义映射表自检失败(映射指向了不会被扫描的通道);
* -2 - STM32 ADC1 的 DMA 挂载失败
* 限定条件:内核启动前调用(无 RTOS 依赖);STM32 ADC1 外设已由 MX_ADC1_Init 配好
* 函数说明:清缓冲与统计 + 映射表自洽性自检 + 挂载一次 ADC1 DMA(此后转换由
* TIM3 TRGO 硬件触发、DMA 自动搬运)。须在启动采样节拍之前调用。
*/
int adc_input_init(void);
/*
* 函数功能:采集一拍(TPAFE 原子快照 + 消费一帧 STM32 ADC1 DMA 采样)
* 入口参数:无
* 返 回 值:TPAFE 快照结果(1=有新帧 0=无新帧 -1=参数错);STM32 侧状态另见
* adc_input_stm32_rc() / adc_input_stm32_seq()
* 限定条件:仅**任务上下文**调用(TPAFE 快照走临界区)
* 函数说明:本函数只搬运原始码值,不做标定/运算;STM32 侧**零忙等**(不触发、
* 不等待转换)。STM32 侧无新帧不阻断 TPAFE 快照,也不影响返回值语义。
* ⚠ STM32 侧数据滞后 1 拍(乒乓双缓冲固有延迟,9 路一致)。
*/
int adc_input_poll(void);
/*
* 函数功能:取语义通道的物理描述
* 入口参数:ch - 语义通道
* 返 回 值:指向静态描述表的指针;ch 越界返回 NULL
* 限定条件:无
* 函数说明:供自检注入 / UI 通道序等需要"语义 → 物理通道"映射的场景使用。
*/
const adc_channel_desc_t *adc_input_desc(adc_semantic_t ch);
/*
* 函数功能:读取语义通道的原始码值(未标定)
* 入口参数:ch - 语义通道
* out - 输出原始码值(TPAFE 侧为 16 位二进制补码;STM32 侧为 0..4095)
* 返 回 值:0 - 成功;-1 - 参数错;-2 - 该来源当前无有效数据
* 限定条件:无
* 函数说明:消费侧取数的唯一入口(按语义,不写死下标)。取数前须先成功
* adc_input_poll() 一次。
*/
int adc_input_raw(adc_semantic_t ch, int32_t *out);
/*
* 函数功能:读取 STM32 ADC1 最近一次取帧状态码
* 入口参数:无
* 返 回 值:ADC_INPUT_RC_xxx
* 限定条件:无
* 函数说明:供心跳日志 / 自检观测 STM32 侧健康度。
*/
int adc_input_stm32_rc(void);
/*
* 函数功能:读取 STM32 ADC1 停摆故障累计次数
* 入口参数:无
* 返 回 值:DMA 挂载失败次数 + "连续 >=2 拍无新帧"的次数
* 限定条件:无
* 函数说明:单调递增,供心跳日志观测。单拍无新帧(消费者相位伪影)不计入。
*/
uint32_t adc_input_stm32_errs(void);
/*
* 函数功能:读取 STM32 ADC1 累计丢帧点数
* 入口参数:无
* 返 回 值:Σ(完成计数每次前进的超出部分),即没被消费就被覆盖掉的帧数
* 限定条件:无
* 函数说明:与 errs 分开——gap = 消费者超拍(单拍耗时 > 1 ms),
* err = 节拍源/ DMA 停摆。两类故障处置不同,混在一起就查不了。
* 单位与判定层 adc_health_tpafe_gaps() 一致(帧点数),心跳里可直接对比;
* 2026-10-21 之前的固件该字段是"次数"口径。
*/
uint32_t adc_input_stm32_gaps(void);
/*
* 函数功能:读取 STM32 ADC1 的 DMA 整帧完成计数
* 入口参数:无
* 返 回 值:DMA 半区/整区完成中断的累计次数(正常时每拍 +1)
* 限定条件:无
* 函数说明:与 tpafe5160_frame_seq() 对称的 STM32 侧"节拍是否还在喂数据"观测量。
*/
uint32_t adc_input_stm32_seq(void);
/*
* 函数功能:读取 STM32 ADC1 的 HAL 层错误回调累计次数
* 入口参数:无
* 返 回 值:HAL_ADC_ErrorCallback 触发次数(DMA 传输错误等)
* 限定条件:无
* 函数说明:与 adc_input_stm32_errs() 分开计数,用于区分"节拍源停了"与"DMA 出错"。
*/
uint32_t adc_input_stm32_hw_errs(void);
#ifdef __cplusplus
}
#endif
#endif /* ADC_INPUT_H */