打印
[其他ST产品]

STM32的ADC多路采集 DMA传输 数据错位

[复制链接]
603|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
AD, ADC, DM, DMA, ST
解决方法:不要采用连续转换模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;

需要时才实施转换    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
转换后取消转换        ADC_SoftwareStartConvCmd(ADC1, DISABLE);

经过测试能够解决stm32 adc dma多通道采样 数据错位.

DMA为循环模式更改为非循环模式,将开启DMA传输和开启ADC规则转换这两句话单独拿出。
每一次DMA传输都在特定条件下,由我们自己开启。在每一次DMA传输完成进入中断之前 都将AD转换器和DMA传输关闭,切换通道完成之后都重新开启AD转换和DMA传输关闭,确保不会发生错位现象。

1) ADC多通道采集:(多通道采集必须用扫描模式,扫描模式时规则组的通道共用一个寄存器,so必须用DMA传输;为防止数据错位,不能用连续模式,而应在查询或中断中先关闭ADC转换,再开启ADC转换)so应采用扫描、非连续的方式、DMA正常模式,DMA的EOC中断或查询;

上述的配置下,ADC运行流程如下:

每个规则通道采集之后,每个ADC_DR会更新,这个更新会启动一次DMA,同时会产生EOC,然后DMA会传输此数据,DMA的传输会清除EOC标志,然后DMA的传输量计数器--,so,每一组规则通道转换完成后也不会产生EOC(详情看英文版STM32手册V15版本-Page220,而非V9版本),so利用这个EOC产生ADC中断或查询时,标志位已为RESET,so根本就办不到,但可利用DMA正常模式,DMA_EOC标志被置位在中断或查询中ADC转换先关闭,对应的DMACmd关闭,然后重新写入DMA的传输数据量CNDTR,再打开DMACmd,再清除DMA标志位,再打开ADC转换,同时,存储模拟量的变量或数组需要用volatile修饰

使用特权

评论回复
沙发
一点点0321|  楼主 | 2023-12-19 23:26 | 只看该作者
DMA查询的代码如下
if(DMA_GetFlagStatus(DMA1_FLAG_TC1)!=RESET)       //ÅжÏͨµÀ1´«ÊäÍê³É

{

ADC_SoftwareStartConvCmd(ADC1,DISABLE);

DMA_Cmd(DMA1_Channel1,DISABLE);

  DMA_SetCurrDataCounter(ADC1_DMA_CHANNLE,ADC1_DMA_BUFFER_SIZE);    DMA_Cmd(DMA1_Channel1,ENABLE);

DMA_ClearFlag(DMA1_FLAG_TC1);//

ADC_SoftwareStartConvCmd(ADC1,ENABLE);

}

使用特权

评论回复
板凳
一点点0321|  楼主 | 2023-12-19 23:27 | 只看该作者
同时也可以ADC1、ADC3同时使用,ADC3利用PF6-9,可复用为Channel4-7,要为扫描模式,非连续模式;代码如下:

ADC_InitStructure.ADC_NbrOfChannel = 4;
ADC_Init(ADC3, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC3,ADC_Channel_4, 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC3,ADC_Channel_5, 2, ADC_SampleTime_239Cycles5 );           
ADC_RegularChannelConfig(ADC3,ADC_Channel_6, 3, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC3,ADC_Channel_7, 4, ADC_SampleTime_239Cycles5 );
ADC_DMACmd(ADC3, ENABLE);
ADC_Cmd(ADC3,ENABLE);   
ADC_ResetCalibration(ADC3);      
while(ADC_GetResetCalibrationStatus(ADC3));   
ADC_StartCalibration(ADC3);
while(ADC_GetCalibrationStatus(ADC3));     
ADC_SoftwareStartConvCmd(ADC3, ENABLE);  

使用特权

评论回复
地板
一点点0321|  楼主 | 2023-12-19 23:27 | 只看该作者
同时也可以ADC1、ADC3同时使用,ADC3利用PF6-9,可复用为Channel4-7,要为扫描模式,非连续模式;代码如下:

ADC_InitStructure.ADC_NbrOfChannel = 4;
ADC_Init(ADC3, &ADC_InitStructure);
ADC_RegularChannelConfig(ADC3,ADC_Channel_4, 1, ADC_SampleTime_239Cycles5);
ADC_RegularChannelConfig(ADC3,ADC_Channel_5, 2, ADC_SampleTime_239Cycles5 );           
ADC_RegularChannelConfig(ADC3,ADC_Channel_6, 3, ADC_SampleTime_239Cycles5 );
ADC_RegularChannelConfig(ADC3,ADC_Channel_7, 4, ADC_SampleTime_239Cycles5 );
ADC_DMACmd(ADC3, ENABLE);
ADC_Cmd(ADC3,ENABLE);   
ADC_ResetCalibration(ADC3);      
while(ADC_GetResetCalibrationStatus(ADC3));   
ADC_StartCalibration(ADC3);
while(ADC_GetCalibrationStatus(ADC3));     
ADC_SoftwareStartConvCmd(ADC3, ENABLE);  

使用特权

评论回复
5
一点点0321|  楼主 | 2023-12-19 23:27 | 只看该作者
(一)问题描述:
目前一个项目中,需要采集两路ADC的信号。为了使采集的信号稳定,笔者采用多次采集求取平均值,再加其他软件滤波方式。所以使用了ADC的循环采集和DMA传输。

想要达到的效果:

两路ADC个采集64个(2路总共128个)数据,然后使用DMA传输完成,触发中断。停止采集,等待数据处理完后再启动下一次采集。

实际效果:

采集完这128个数据,且DMA传输完成后,进入了中断。等我处理完这些数据再次开启DMA传输的时候,传输完成后对应的数据却错位了,就是两个通道的数据相互错位了。

使用特权

评论回复
6
一点点0321|  楼主 | 2023-12-19 23:28 | 只看该作者
(二)配置和使用
实际工程是使用的STM32CUBE配置生成的,配置ADC为循环扫描,连续转换模式,并且使用DMA单次传输。

相关配置

使用特权

评论回复
7
一点点0321|  楼主 | 2023-12-19 23:28 | 只看该作者
ADC配置1


ADC的DMA配置

使用特权

评论回复
8
一点点0321|  楼主 | 2023-12-19 23:29 | 只看该作者
相关程序:
1.启动ADC的DMA传输:
开启ADC转换,并且开启DMA传输。

启动ADC的DMA传输

使用特权

评论回复
9
一点点0321|  楼主 | 2023-12-19 23:30 | 只看该作者
2.DMA传输完成的中断函数
在ADC转换完这两个通道总共128个数据并且使用DMA传输时,进入该中断回调函数。


128个数据经过DMA传输完成的中断回调函数

使用特权

评论回复
10
一点点0321|  楼主 | 2023-12-19 23:30 | 只看该作者
(三)出现问题
进过上述两个过程,ADC采集的两个通道的数据保存在了adc_buf中了。

里面的数据分布应该每次都是:CH0,CH1,CH0,CH1,CH0.CH1 ..... 这样交替分布的。

但是实际情况却并不是这样,两者数据会随机错位。

使用特权

评论回复
11
一点点0321|  楼主 | 2023-12-19 23:30 | 只看该作者
(四)解决方法
在回调函数中加入如下语句,这样问题得以解决,不会再出现通道数据错位的现象了。

使用特权

评论回复
12
一点点0321|  楼主 | 2023-12-19 23:30 | 只看该作者
(五)问题分析
笔者的配置是:ADC循环转换,DMA单次传输(传输指定的数据量,触发中断会就不再启动DMA传输了)。

在使用的时候,先使用HAL_ADC_Start_DMA();函数去开启ADC转和DMA的单次传输。

当DMA传输完成后,因为是单次转换,如需继续转换,那么还需要使用HAL_ADC_Start_DMA();再次开启传输才行。这里就会有一个问题,DMA传输的确是停止了,但是ADC是循环转换,ADC仍然在转换,当我处理完数据以后使用HAL_ADC_Start_DMA();再次开启传输时候,这个时候对应ADC转换完成的数据,具体是哪一个通道的其实是随机的,但是DMA还是会把这个数据传输到adc_buf[0]中,所以我们的数据就是这样错位了。

使用特权

评论回复
13
一点点0321|  楼主 | 2023-12-19 23:31 | 只看该作者
加入了HAL_ADC_Stop_DMA();实际上是停止了ADC的转换了,在下一次开启转换的时候,就不会出现错位的问题了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

55

主题

396

帖子

0

粉丝