裸机环境下STM32F407使用DMA读取单ADC多通道失败问题
问题排查结果
不需要额外加周期性调用触发ADC读取,你开了连续转换模式后ADC会自动循环转换,sensor_val不更新、回调不触发是代码里多处配置错误导致的,具体问题点和修正方式如下:
- GPIO模拟模式配置错误
代码里GPIOA->MODER |= set(m,(2));、GPIOB->MODER |= set(m,(2));存在两个问题:一是m未定义,二是ADC模拟输入要求对应引脚的MODER位设为0b11(3),不是2。修正代码如下:// PA1 配置为模拟模式 GPIOA->MODER &= ~(0b11 << 2); GPIOA->MODER |= (0b11 << 2); // PB1 配置为模拟模式 GPIOB->MODER &= ~(0b11 << 2); GPIOB->MODER |= (0b11 << 2); - DMA中断标志操作寄存器错误
你使用的是DMA2_Stream0,清中断标志时写的是DMA1->LIFCR,这是DMA1的寄存器,DMA2的中断标志要操作DMA2->LIFCR,否则传输完成标志无法清除,中断服务函数不会正常触发。 - ADC采样时间配置通道错误
你使用的是通道1(PA1)和通道9(PB1),但代码里给通道0写了采样时间配置,通道1的采样时间保持默认的3周期,对于电位器这类高阻抗输入来说采样时间不足,会导致采样值不准甚至无法采样。把ADC_SMPR2_SMP0_Pos改成ADC_SMPR2_SMP1_Pos即可。 - DMA数据宽度未配置
代码里清除了DMA_SxCR_MSIZE、DMA_SxCR_PSIZE位后没有重新赋值,默认是8位传输宽度,但ADC的DR寄存器有效数据是16位,存储变量是32位,宽度不匹配会导致传输数据错误。需要在DMA的CR配置里补充:set(1, DMA_SxCR_PSIZE_Pos) | // 外设数据宽度16位,匹配ADC_DR set(2, DMA_SxCR_MSIZE_Pos) | // 内存数据宽度32位,匹配uint32_t类型 - 初始化顺序错误
你当前的顺序是:初始化DMA→初始化ADC→启动转换。正确顺序应该是先完成ADC所有配置、给ADC上电(置ADON位后需等待至少3us稳定时间),再初始化DMA,最后启动ADC转换。同时ADC_CR2的DMA位、DDS位(DMA连续请求,保证多通道循环转换时每次转换完成都发DMA请求)要在ADC上电前配置完成。 - 多余配置误导
代码里打开了ADC的EOCIE(转换完成中断),但没有配置ADC1的NVIC中断、也没有写ADC中断服务函数,这个配置不会直接导致DMA失效,但会产生挂起的无用中断,建议关闭,仅用DMA传输完成中断即可。另外代码里!! Enable DMA1 Stream 6的注释是笔误,实际操作的是DMA2_Stream0,建议修正避免后续调试误导。
验证方法
修改完成后可以通过三个点快速确认功能正常:
- 调试模式下查看ADC1->SR的ADONS位为1,确认ADC正常上电
- 启动转换后查看DMA2_Stream0->NDTR寄存器,循环模式下传输完2个数据后会自动重载为2
- 直接查看内存中
sensor_val数组的值,旋转电位器时值应在0~4095范围内变化,不需要等回调触发就能看到值更新。
内容的提问来源于stack exchange,提问作者mgmussi
相关产品推荐
相关产品推荐

