解决方法:不要采用连续转换模式 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修饰
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);
}
同时也可以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);
(一)问题描述:
目前一个项目中,需要采集两路ADC的信号。为了使采集的信号稳定,笔者采用多次采集求取平均值,再加其他软件滤波方式。所以使用了ADC的循环采集和DMA传输。
想要达到的效果:
两路ADC个采集64个(2路总共128个)数据,然后使用DMA传输完成,触发中断。停止采集,等待数据处理完后再启动下一次采集。
实际效果:
采集完这128个数据,且DMA传输完成后,进入了中断。等我处理完这些数据再次开启DMA传输的时候,传输完成后对应的数据却错位了,就是两个通道的数据相互错位了。
(二)配置和使用
实际工程是使用的STM32CUBE配置生成的,配置ADC为循环扫描,连续转换模式,并且使用DMA单次传输。
相关配置
ADC配置1
ADC的DMA配置
相关程序:
1.启动ADC的DMA传输:
开启ADC转换,并且开启DMA传输。
启动ADC的DMA传输
2.DMA传输完成的中断函数
在ADC转换完这两个通道总共128个数据并且使用DMA传输时,进入该中断回调函数。
128个数据经过DMA传输完成的中断回调函数
(三)出现问题
进过上述两个过程,ADC采集的两个通道的数据保存在了adc_buf中了。
里面的数据分布应该每次都是:CH0,CH1,CH0,CH1,CH0.CH1 ..... 这样交替分布的。
但是实际情况却并不是这样,两者数据会随机错位。
(四)解决方法
在回调函数中加入如下语句,这样问题得以解决,不会再出现通道数据错位的现象了。
(五)问题分析
笔者的配置是: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]中,所以我们的数据就是这样错位了。
加入了HAL_ADC_Stop_DMA();实际上是停止了ADC的转换了,在下一次开启转换的时候,就不会出现错位的问题了。