STM32F429三重ADC同步模式DMA配置故障排查求助
问题:STM32F429三重ADC同步+定时器触发+DMA传输异常
需求目标
- 使用STM32F429I-DISC开发板+STM32CubeIDE,实现定时器以X频率触发ADC1/2/3工作在三重常规同步模式,转换结果通过DMA传输至变量。
异常现象
仅出现两种异常:
- 调试会话启动时仅转换一次(触发一次ADC回调),之后不再转换;
- DMA转换完成中断无限触发,阻塞整个应用。
已尝试的配置及结果
- 配置1:软件触发(替代定时器);ADC1/2/3设为三重常规同步模式;开启Continuous mode(连续模式)、DMA Continuous Requests(DMA连续请求);DMA设为循环模式;ADC时钟预分频至约90kHz;系统时钟约144MHz。
- 结果:代码因DMA中断无限触发卡死;禁用DMA中断后可运行,但仅能获取初始化时引脚电压,修改引脚电压后缓冲区无变化。
- 配置2:与配置1相同,额外开启Scan(扫描)模式,每个ADC多次转换对应通道(如3次)。
- 结果:与配置1一致。
- 配置3:定时器触发ADC(触发输出事件,上升沿);定时器时钟约50kHz;ADC设为三重常规同步模式;禁用Scan、Continuous、Discontinuous(间断)模式;禁用DMA连续请求;ADC时钟设为约72MHz;DMA设为循环模式。
- 结果:仅调试启动时触发一次ADC回调,之后不再触发。
- 配置4:与配置3相同,在回调函数中调用
HAL_ADCEx_MultiModeStop_DMA和HAL_ADCEx_MultiModeStart_DMA重新初始化转换(因DDS=0)。- 结果:无变化。
- 配置5:与配置3相同,开启DMA连续请求(DDS=1)。
- 结果:ADC回调无限触发,初始化后阻塞程序。
还尝试将DMA循环模式改为普通模式等变体,均未成功。
核心疑问
- 关于DMA Continuous Requests(DDS标志):开启后,是即使无新转换也持续生成DMA请求(传输旧值),还是仅在有新转换时生成请求?禁用后,是否每次回调都需停止ADC/DMA并重新触发?
- 使用定时器触发时,注释掉定时器初始化仍能触发首次ADC回调,说明触发源可能是
HAL_ADCEx_MultiModeStart_DMA()而非定时器,是否使用了错误的初始化函数?(注:定时器本身工作正常,启用定时器中断并通过_IT()初始化时,定时器中断回调可正常触发) - 配置1中已开启连续模式,禁用所有中断后,ADC和DMA应在后台持续转换并以循环方式将新数据传输至内存,通过FreeRTOS任务轮询缓冲区变量或调用
HAL_ADCEx_MultiModeGetValue()应能获取最新值,但实际仅能获取启动时的初始值。
代码相关细节
- 代码由STM32CubeIDE/MX生成,仅添加必要初始化用户代码。
- 外设初始化顺序:
MX_GPIO_Init(); MX_DMA_Init(); MX_CRC_Init(); MX_I2C3_Init(); MX_SPI5_Init(); MX_FMC_Init(); MX_LTDC_Init(); MX_DMA2D_Init(); MX_ADC2_Init(); MX_ADC3_Init(); MX_ADC1_Init(); MX_USB_OTG_HS_HCD_Init(); MX_TIM8_Init(); - ADC2和ADC3通过
HAL_ADC_Start()初始化,ADC1通过HAL_ADCEx_MultiModeStart_DMA()初始化;已尝试DMA数据宽度为半字或字,HAL_ADCEx_MultiModeStart_DMA()的缓冲区长度设为1、3、10等。 - 定时器通过
HAL_TIM_Base_Start_IT()或HAL_TIM_Base_Start()初始化。 - ADC回调函数为重定义的弱函数
HAL_ADC_ConvCpltCallback()。 - 已尝试NVIC中定时器、ADC、DMA中断的所有启用/禁用组合。
排查思路与解决方案建议
- DDS标志的正确理解:根据RM0090手册,DDS(DMA Disable Selection)位用于控制ADC在单次转换结束后是否自动禁用DMA请求。当DDS=0(开启DMA连续请求),每次转换完成后都会生成DMA请求,且ADC不会自动关闭DMA请求;当DDS=1(禁用DMA连续请求),单次转换完成后ADC会禁用DMA请求,需重新触发ADC才能生成新的DMA请求。注意:DDS仅控制ADC是否持续生成DMA请求,只有当有新的转换完成时才会触发DMA传输,不会传输旧值。
- 定时器触发的正确配置:
- 确保ADC的触发源配置为定时器的TRGO事件(如TIM8的TRGO),在CubeMX中需将ADC1的Trigger Source设为
Timer X Trigger Out event,且触发极性设为上升沿。 - 首次转换由
HAL_ADCEx_MultiModeStart_DMA()触发是正常的,因为该函数会启动ADC并触发一次转换;后续转换需依赖定时器的TRGO事件,需检查定时器的TRGO配置是否正确(如TIM8的CR2寄存器中MMS位设置为触发输出事件)。 - 调整初始化顺序:将
MX_TIM8_Init()移至ADC初始化之前,确保定时器先配置完成,再启动ADC。
- 确保ADC的触发源配置为定时器的TRGO事件(如TIM8的TRGO),在CubeMX中需将ADC1的Trigger Source设为
- 连续模式+DMA循环模式的问题排查:
- 配置1中禁用DMA中断后,需确认ADC是否真的在连续转换:可通过查看ADC的SR寄存器的EOC位是否持续置位,或用示波器观察ADC的转换完成引脚(若有)。
- 检查DMA配置:确保DMA方向为外设到内存,循环模式开启,数据宽度与ADC转换结果宽度匹配(ADC为12位,通常设为半字),缓冲区长度正确(三重同步模式下,每次转换传输3个数据:ADC1、ADC2、ADC3各一个,缓冲区长度应设为3的倍数)。
- 确认ADC连续模式是否真的开启:在CubeMX中,需确保每个ADC的Continuous Conversion Mode都设为Enabled,三重模式下ADC1为主控,需重点检查ADC1的配置。
- 回调函数与DMA中断的处理:
- 使用DMA循环模式时,若开启DMA完成中断,会在每次传输完成后触发中断,若未正确处理(如清除中断标志)会导致无限触发。此时应禁用DMA完成中断,或确认HAL库在回调函数中已自动清除中断标志。
- 若使用非循环模式(普通模式),每次转换完成后需重新启动ADC和DMA,但定时器触发场景下,应使用循环模式配合DDS=0,实现自动连续转换。
内容的提问来源于stack exchange,提问作者FELIPE_RIBAS
相关产品推荐
相关产品推荐

