adc_input: 失败拍清 s_stm32_valid,杜绝超时沿用上一拍旧值(单测 70->79)

缺陷(真机实测发现):本层只有一份 s_stm32_raw[],有效标志此前只在成功时
置 1、失败时从不清零 -> 超时拍消费侧照样取数、照样压入采样环(且超时前
几个 Rank 已写本拍新值、后面几个是上一拍旧值 = 半新半旧混合帧),直接污
染 20 点 DFT 相量窗;adc_input_poll() 返回值只由 TPAFE 决定,s_frames_skip
也抓不到它。

修复:stm32_scan() 两条失败支路(HAL_ADC_Start 失败 / 轮询超时)都清
s_stm32_valid -> 本拍 adc_input_raw() 对 STM32 语义通道返 -2 -> adc_task
走既有 skip 整帧跳过路径;下一拍扫描成功自动置回 1(自愈)。

测试:新增 TC-AI-070..078(70 -> 79 用例)。旧用例 TC-AI-034/039b 都是
init 后立刻失败(valid 本就是 0),照不出成功过之后再失败这条路径,故新
用例先成功一拍进入有效态再注入失败。**反向验证已做**:把支路改回旧行为 ->
TC-AI-039b/073/074 立即 FAIL(76/79),证明用例有效。

验证:主机单测 79/79 PASS;@build 0 错 0 警(Code 256868 -> 256872);
@test PASS(本轮无超时:adc1_err=0、skip=0、idle=0、frames=20001);
18 钩子全绿。文档同步 4 处(停摆分析 4.4 / ADC采样节拍 10.4 / ADC输入层
单测说明 / test-host README)。

遗留:2 ms 忙等本身未消(硬化 2 = DMA,方案 B2 待 CubeMX 配置)。
This commit is contained in:
2026-10-10 23:08:01 +08:00
parent 9231a3c22c
commit dd8210867a
7 changed files with 89 additions and 13 deletions
+14
View File
@@ -65,11 +65,17 @@ static uint32_t s_stm32_errs; /* STM32 扫描累计失败次数 */
* DISABLE),按 Rank 顺序逐通道轮询 EOC 并读 DR,结果按 ADC1 通道号
* 存入 s_stm32_raw[]。EOCSelection=SINGLE_CONV 且未用 DMA → 每个通道
* 产生一次 EOC,可逐通道轮询(见 HAL_ADC_PollForConversion 说明)。
* 两条失败支路(启动失败 / 轮询超时)**都会清 s_stm32_valid**:本拍
* STM32 侧判为无有效数据,绝不沿用上一拍旧值(详见支路内注释)。
* 超时在**首个**失败通道处即 Stop+return,不轮询剩余通道 → 单拍耗时
* 上界 = 一次超时(≈2~3 ms,HAL_GetTick 1 ms 粒度),不是 9 次。
*/
static int stm32_scan(void) {
uint8_t i;
if (HAL_ADC_Start(&hadc1) != HAL_OK) {
/* 失败拍必须清有效标志,见下方超时分支说明(同一语义) */
s_stm32_valid = 0u;
s_stm32_rc = ADC_INPUT_RC_START;
s_stm32_errs++;
return ADC_INPUT_RC_START;
@@ -78,6 +84,14 @@ static int stm32_scan(void) {
for (i = 0u; i < ADC_INPUT_STM32_CH_NUM; i++) {
if (HAL_ADC_PollForConversion(&hadc1, ADC_INPUT_POLL_TIMEOUT_MS) != HAL_OK) {
(void)HAL_ADC_Stop(&hadc1);
/* ⚠ 失败拍**不得**沿用上一拍的旧值:本层只有一份 s_stm32_raw[],
* 超时前几个 Rank 已写入**本拍新值**、后面几个还是**上一拍旧值** →
* 若保持 s_stm32_valid=1,消费侧会拿到"半新半旧"的混合帧并照样压入
* 采样环(adc_input_poll() 的返回值只由 TPAFE 决定,s_frames_skip
* 也抓不到它),直接污染 20 点 DFT 相量窗。清标志后 adc_input_raw()
* 对 STM32 语义通道返 -2 → adc_task 走既有的"整帧跳过"路径。
* 下一拍扫描成功会重新置 1(自愈),无需额外恢复动作。 */
s_stm32_valid = 0u;
s_stm32_rc = ADC_INPUT_RC_TIMEOUT;
s_stm32_errs++;
return ADC_INPUT_RC_TIMEOUT;