fix(adc): 挂 DMA 前关闭 ADC,消除乒乓缓冲 +2 格相位旋转

问题:ADC1 在 MX_ADC1_Init() 里使能,而 DMA 在 app_main_init() 步骤
4b 才挂载,中间隔着 GD5F 全片 BBT 扫描(数秒)。台架同一次开机内用
无 DMA 单通道逐路取真值、与 DMA 路径对照,得 9/9 完美置换:乒乓缓冲
从 rank 3 开始搬,槽 i 装的是 rank ((i+1) mod 9)+1,整体错开 2 格。
表象是"接地 AIN2、UB 却读到别的通道的值",极易误判为映射表写错或
注入点标签不对。

修法:新增 adc1_disable()(Src/adc.c 的 USER CODE BEGIN 1),在
app_main_init() 步骤 4b-pre 调用,把 ADC 置为关闭态,使能动作交给
HAL_ADC_Start_DMA() 内部完成(它自己 __HAL_ADC_ENABLE + 等 Tstab
约 20 us,紧接着开 CR2.DMA 并启流),使能与搬运之间不留可观测间隔。
顺序不可调换:本调用必须严格早于 adc_input_init()。

台架验证:在 MX_ADC1_Init() 末尾关闭 4/4 次、在 4b-pre 调本 API
3/3 次,均 UB=0;同开机对照差值 <=4 码(修前 7/7 次 UB=783~786)。

文档:ADC采样节拍设计说明.md 新增 4.5 节(9 行证据表、判据陷阱、
根因与修法)与设计铁律第 8 条。

台账:Flash 261,764 -> 261,928 B(+164,新增函数),RAM 无变化;
CubeMX 存活审计基线重建(adc1-calibration-impl / adc1-dma-link
两项漂移均属本次有意改动,锚点已逐条复核在位)。
This commit is contained in:
2026-10-27 20:42:06 +08:00
parent e6d3e5a1be
commit 1166ab1c2e
7 changed files with 112 additions and 5 deletions
+19
View File
@@ -17,6 +17,7 @@
#include "stm32f4xx_it.h" /* fault_handler_enable() */
#include "usart.h" /* huart5 */
#include "tim.h" /* htim3:1 kHz 采样节拍(TIM3 更新中断触发 CONVST + TRGO 触发 ADC1) */
#include "adc.h" /* adc1_disable():挂 DMA 前把 ADC 关掉,让 Start_DMA 自己使能 */
#include "rs485.h"
#include "sd2506.h"
#include "boot_stats.h" /* 开机账本:上电次数(RTC 用户 SRAM)+ 本次复位原因快照(道G task-12) */
@@ -220,6 +221,24 @@ int app_main_init(void) {
syslog_post(SYSLOG_SELFTEST, "ADC fault");
}
/* 4b-pre) 挂 DMA 之前**先把 ADC 关掉**,让使能动作由 HAL_ADC_Start_DMA 内部完成
* (它自己 __HAL_ADC_ENABLE + 等 Tstab ~20 µs,然后紧接着开 CR2.DMA 并启流)。
*
* 为什么必须这样做:MX_ADC1_Init() 在 main() 里就调用了,而挂 DMA 在这里,
* 中间隔着 GD5F 全片 BBT 扫描(数秒)。台架实测(同一次开机内用无 DMA 单通道
* 探针取真值对照,9/9 完美置换):**ADC 使能后闲置数秒才挂 DMA,DMA 乒乓缓冲
* 会整体 +2 格旋转** —— 槽 i 装的是 rank ((i+1) mod 9)+1,9 路通道按 rank 序
* 整体错开 2 位。表象是"接地 AIN2、UB 却读到别的通道的值",极易被误判成
* 映射表写错或夹子位置不对。
* 把使能与挂 DMA 压到同一时刻后旋转消失(台架 4/4 次,同开机对照差值 ≤4 码)。
* 证据与复现方法见 docs/子系统设计/ADC采样节拍设计说明.md §4.5。
*
* ⚠ 顺序不可调换:本调用必须严格早于下面的 adc_input_init()。
* 若 ADC 在本步之后仍处于使能态,旋转会重新出现。 */
if (adc1_disable() != 0) {
DBG_ERROR("ADC1 disable before DMA arm: TIMEOUT");
}
/* 4b) ADC 输入层(L1)初始化:清原始码值缓冲与统计 + **语义映射表自洽性自检**
* (映射指向了不会被扫描的通道 → 返回 -1,避免"读到恒为陈旧值"的静默错)
* + 挂载一次 STM32 ADC1 的 DMA(失败返回 -2)。