OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 19653|回复: 15

关于ADC——DMA采集数据错位

[复制链接]

8

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
78
金钱
78
注册时间
2012-6-14
在线时间
0 小时
发表于 2012-7-28 21:36:26 | 显示全部楼层 |阅读模式
在论坛上看到好多人都表示ADC——DMA采集数据回来后数据错位了。

刚才发现,我的代码如果在DMA使能了时钟后面加一个小延时的话,就会发生这样的情况。
然后我把那个小延时去掉后发现数据就正常了,正在纠结的人可以看下自己DMA初始化函数前面是不是有个小延时了。
为什么会这样呢?


PS:我要在DMA初始化函数前加个小延时是因为刚才看到原子哥说库函数某个版本的函数有个小bug,加了小延时可以消除。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
43
金钱
43
注册时间
2019-10-25
在线时间
9 小时
发表于 2020-4-30 14:18:39 | 显示全部楼层
对于这个问题,我使用的是STM32G0,使用的是LL库,配置如下可正确使用
       
        LL_ADC_StartCalibration(ADC1);
        while( LL_ADC_IsCalibrationOnGoing(ADC1));
        LL_ADC_Enable(ADC1);
        LL_ADC_REG_StartConversion(ADC1);
        //这个使能过程是根据HAL库的使能过程总结而来
        LL_DMA_SetDataLength(DMA1,LL_DMA_CHANNEL_1,3);  //这个是关键,不能放到adc校准前面,即使把后面几条语句放到后面,这条语句不放到ADC使能后面都会错位
        LL_DMA_SetPeriphAddress(DMA1,LL_DMA_CHANNEL_1,LL_ADC_DMA_GetRegAddr(ADC1,LL_ADC_DMA_REG_REGULAR_DATA));
        LL_DMA_SetMemoryAddress(DMA1,LL_DMA_CHANNEL_1,(uint32_t)&AdcConvData_Tab);
        LL_DMA_EnableChannel(DMA1,LL_DMA_CHANNEL_1);
       
回复 支持 1 反对 0

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165464
金钱
165464
注册时间
2010-12-1
在线时间
2115 小时
发表于 2012-7-28 23:10:35 | 显示全部楼层
回复【楼主位】2253367:
---------------------------------
没这么邪门吧.那个延时是要加的,我现在是加1ms,你的加多少??
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

8

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
78
金钱
78
注册时间
2012-6-14
在线时间
0 小时
 楼主| 发表于 2012-7-29 00:22:06 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
我加了10ms,确实发现是这样额..
然后其实我不加延时暂时也没有发现有什么问题啊
回复 支持 反对

使用道具 举报

2

主题

1439

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
2215
金钱
2215
注册时间
2010-12-16
在线时间
192 小时
发表于 2012-7-29 01:19:19 | 显示全部楼层
先使能DMA,再使能ADC就没有问题.

错位的原因是ADC开启后,没有及时使能DMA,到DMA使能时ADC已经转换过若干个值,与设计产生偏差.
技术讨论请发帖 , 需要我回复请点左下的 < 回复 > 让系统通知我 . 本人不通过其他方式返回任何参数.
回复 支持 反对

使用道具 举报

8

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
78
金钱
78
注册时间
2012-6-14
在线时间
0 小时
 楼主| 发表于 2012-7-29 10:03:05 | 显示全部楼层
回复【4楼】shihantu:

---------------------------------
对的,确实先初始化DMA然后再初始化ADC就没问题了。
回复 支持 反对

使用道具 举报

4

主题

44

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2014-11-18
在线时间
0 小时
发表于 2015-1-22 16:23:37 | 显示全部楼层
困扰我数日的问题。。。原来是  初始化顺序啊= =  头发都抓掉不少
我是伸手党 ←_←
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
6
金钱
6
注册时间
2016-2-8
在线时间
1 小时
发表于 2016-2-8 23:00:03 | 显示全部楼层
刚刚解决了这个问题,解决之前也百度到这了,但是上面说的貌似都不能根本解决,注册个号说下我的办法吧
我是双adc-dma采集,发现少了adc1的第一个数据,看内存的时候是直接把数组名字复制到地址栏里,然后我直接输入内存地址往数组的前面又看了几个字节,发现adc1的第一个数跑到数组头再前面两个字节处了,然后又观察了一下发现其实就是个对齐问题,双adc是要用到adc1的dr的全部32位,所以dma需要4字节对齐,在dma目标数组的前面加上“__align(4)”,问题解决
上面几楼说的方法也能解决,我猜是改了代码,造成目标数组位置变动,正好变到了对齐的位置,不过也只是猜测,总之我上面说的算是一种解决办法
回复 支持 反对

使用道具 举报

1

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
95
金钱
95
注册时间
2016-7-5
在线时间
22 小时
发表于 2016-7-12 13:04:15 | 显示全部楼层
本帖最后由 flyinggirlxhx 于 2016-7-12 13:05 编辑

http://blog.sina.com.cn/s/blog_542bad910101h5jy.html
这个帖子里重点讲解了为什么会数据错位,并且怎么处理。亲测有效!

要注意在初始化时将DMA_Cmd(DMA1_Channel1, ENABLE);放置到ADC_SoftwareStartConvCmd(ADC1, ENABLE);前面。

原因是:如果在初始化AD的时候DMA被触发了一次,但是此时并没有采样,但是DMA目的地址已经发生了自加,
当你采样第一路的时候,数据却填充到了第二路。

校准AD的时候会触发DMA导致通道错位,因此校准AD基准前不要启用DMA
回复 支持 反对

使用道具 举报

1

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
95
金钱
95
注册时间
2016-7-5
在线时间
22 小时
发表于 2016-7-12 13:07:06 | 显示全部楼层
http://blog.sina.com.cn/s/blog_542bad910101h5jy.html
这个帖子里重点讲解了为什么会数据错位,并且怎么处理。亲测有效!

要注意在初始化时将DMA_Cmd(DMA1_Channel1, ENABLE);放置到ADC_SoftwareStartConvCmd(ADC1, ENABLE);前面。

原因是:如果在初始化AD的时候DMA被触发了一次,但是此时并没有采样,但是DMA目的地址已经发生了自加,
当你采样第一路的时候,数据却填充到了第二路。

校准AD的时候会触发DMA导致通道错位,因此校准AD基准前不要启用DMA
回复 支持 反对

使用道具 举报

0

主题

25

帖子

0

精华

新手入门

积分
13
金钱
13
注册时间
2016-3-6
在线时间
43 小时
发表于 2016-9-10 09:28:21 | 显示全部楼层
本帖最后由 sweetstandard 于 2016-9-10 09:35 编辑

我也遇到了这样的问题,解决方法是:DMA工作在循环模式。具体如下:
======================================
寄存器方式:

void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx)
{




//DMA_CHx->CCR|=0<<5;  //非循环模式,这种模式下就错位。
   DMA_CHx->CCR|=1<<5;  //循环模式




}
=================================
库函数方式:

void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx)
{




//DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //正常缓存模式,这种模式下就错位。
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//循环模式。        




}
================================

事在人为,顺势而为。
回复 支持 反对

使用道具 举报

42

主题

141

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
342
金钱
342
注册时间
2015-5-26
在线时间
49 小时
发表于 2017-4-7 20:33:43 | 显示全部楼层
谢谢大家,mark一下
回复 支持 反对

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
发表于 2017-5-4 09:33:17 | 显示全部楼层
sweetstandard 发表于 2016-9-10 09:28
我也遇到了这样的问题,解决方法是:DMA工作在循环模式。具体如下:
=================================== ...

你这种修改方式不实用啊,应该还不是问题的本质吧。那要是在只能用正常模式下(不用循环模式),岂不是就一直错位下去啊?
回复 支持 反对

使用道具 举报

2

主题

17

帖子

0

精华

初级会员

Rank: 2

积分
59
金钱
59
注册时间
2018-6-25
在线时间
11 小时
发表于 2018-11-27 21:48:25 | 显示全部楼层
MARK   MARK
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2020-7-15
在线时间
0 小时
发表于 2020-7-15 17:06:53 | 显示全部楼层
本帖最后由 saoqiboy567 于 2020-7-16 10:31 编辑
2860qq 发表于 2020-4-30 14:18
对于这个问题,我使用的是STM32G0,使用的是LL库,配置如下可正确使用
        
        LL_ADC_StartCalibration(ADC1) ...

你这个不会卡死在while里面吗
并且你总结的函数库里也没有呀
???
是因为板子型号不同吗?
回复 支持 反对

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
43
金钱
43
注册时间
2019-10-25
在线时间
9 小时
发表于 2022-8-10 13:48:17 | 显示全部楼层
本帖最后由 2860qq 于 2022-8-10 13:53 编辑
saoqiboy567 发表于 2020-7-15 17:06
你这个不会卡死在while里面吗
并且你总结的函数库里也没有呀
???
卡死不会。
上面这是LL库的,根据HAL库的使能顺序来使能的。HAL库操作如下:
MX_DMA_Init();
MX_ADC1_Init();/* Run the ADC calibration */
HAL_ADCEx_Calibration_Start(&hadc1);
       
/* Start ADC conversion */
HAL_ADC_Start_DMA(&hadc1, &AdDma[0], AdcNum);


如果使用stop模式,需要在DMA扫描完毕时关闭ADC,在定时器中再开启ADC,以防止stop模式退出后DMA无法对齐的问题。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-4-26 20:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表