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:
@@ -261,6 +261,8 @@ void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
|
||||
#define ADC1_CAL_TIMEOUT_MS (10U)
|
||||
/* ADON 0→1 后的稳定等待(µs),同 HAL 的 ADC_STAB_DELAY_US 口径 */
|
||||
#define ADC1_STAB_DELAY_US (20U)
|
||||
/* 关闭等待上限(ms)。ADON 由硬件清零,实测在数十 ns 内完成;10 ms 是十万倍余量 */
|
||||
#define ADC1_OFF_TIMEOUT_MS (10U)
|
||||
|
||||
/*
|
||||
* 函数功能:ADC1 上电自校准(等价于 HAL_ADCEx_Calibration_Start,本仓库 HAL 无此函数)
|
||||
@@ -311,5 +313,38 @@ int adc1_calibrate(void)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 函数功能:关闭 ADC1(清 CR2.ADON 并等硬件清零生效)
|
||||
* 入口参数:无
|
||||
* 返 回 值:0 - 已关闭;-1 - 等待超时(ADON 未清零)
|
||||
* 限定条件:任何上下文均可(只碰 ADC1 寄存器与 HAL_GetTick);须在挂 DMA 之前调用
|
||||
* 函数说明:**本函数的存在只为把"使能 ADC"推迟到挂 DMA 的同一刻。**
|
||||
* MX_ADC1_Init() 在 main() 里调用,而挂 DMA 在 app_main_init 步骤 4b,
|
||||
* 中间隔着 GD5F 全片 BBT 扫描(数秒)。台架实测(同一次开机内用无 DMA
|
||||
* 单通道探针取真值对照,9/9 完美置换):ADC 使能后闲置数秒才挂 DMA,
|
||||
* DMA 乒乓缓冲会整体 +2 格旋转 —— 槽 i 装的是 rank ((i+1) mod 9)+1,
|
||||
* 即 9 路通道按 rank 序整体错开 2 位,表现为"接地 AIN2、UB 却读到别的
|
||||
* 通道的值"这种看似映射表写错的现象。
|
||||
* 调用本函数后 ADC 处于关闭态,HAL_ADC_Start_DMA 内部会自己
|
||||
* __HAL_ADC_ENABLE + 等 Tstab(~20 µs),然后紧接着开 CR2.DMA 并启流,
|
||||
* 使能与搬运之间不再有可观测的间隔 → 旋转消失(台架 4/4 次,差值 ≤4 码)。
|
||||
* 证据、复现方法与机制分析见 docs/子系统设计/ADC采样节拍设计说明.md §4.5。
|
||||
*/
|
||||
int adc1_disable(void)
|
||||
{
|
||||
uint32_t tickstart;
|
||||
|
||||
CLEAR_BIT(ADC1->CR2, ADC_CR2_ADON);
|
||||
tickstart = HAL_GetTick();
|
||||
while ((ADC1->CR2 & ADC_CR2_ADON) != 0U)
|
||||
{
|
||||
if ((HAL_GetTick() - tickstart) > ADC1_OFF_TIMEOUT_MS)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* USER CODE END 1 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user