硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5348|回复: 12
收起左侧

[ADC] ADC过采样 使用DMA 遇到数据不准的问题

[复制链接]

18

主题

321

回帖

375

积分

高级会员

积分
375
发表于 2019-11-16 09:32:37 | 显示全部楼层 |阅读模式
不使用DMA及过采样 实际测得电压2.5V,使用万用表测量该值准确,ADC基准电压3.3V.贴上DMA及ADC采样的代码,只测量了一个通道。
  1. uint16_t ADCxValues[1];

  2. uint16_t get_adc(void)
  3. {
  4.     SCB_InvalidateDCache_by_Addr((uint32_t *)ADCxValues,  sizeof(ADCxValues));
  5.     return ADCxValues[0];           //返回最近一次ADC1规则组的转换结果
  6. }

  7. int rt_hw_adc_init(void)
  8. {
  9.     DMA_Handle.Instance                     = DMA1_Stream5;                  //使用的DMA1 Stream5
  10.     DMA_Handle.Init.Request                 = DMA_REQUEST_ADC1;              //请求类型采用DMA_REQUEST_ADC1
  11.     DMA_Handle.Init.Direction               = DMA_PERIPH_TO_MEMORY;          //传输方向是从外设到存储器
  12.     DMA_Handle.Init.PeriphInc               = DMA_PINC_DISABLE;              //外设地址自增禁止
  13.     DMA_Handle.Init.MemInc                  = DMA_MINC_ENABLE;               //存储器地址自增使能
  14.     DMA_Handle.Init.PeriphDataAlignment     = DMA_PDATAALIGN_HALFWORD;       //外设数据传输位宽选择半字,即16bit
  15.     DMA_Handle.Init.MemDataAlignment        = DMA_MDATAALIGN_HALFWORD;       //存储器数据传输位宽选择半字,即16bit
  16.     DMA_Handle.Init.Mode                    = DMA_CIRCULAR;                  //循环模式
  17.     DMA_Handle.Init.Priority                = DMA_PRIORITY_LOW;              //优先级低
  18.     DMA_Handle.Init.FIFOMode                = DMA_FIFOMODE_DISABLE;          //禁止FIFO
  19.     DMA_Handle.Init.FIFOThreshold           = DMA_FIFO_THRESHOLD_FULL;       //禁止FIFO此位不起作用,用于设置阀值
  20.     DMA_Handle.Init.MemBurst                = DMA_MBURST_SINGLE;             //禁止FIFO此位不起作用,用于存储器突发
  21.     DMA_Handle.Init.PeriphBurst             = DMA_PBURST_SINGLE;             //禁止FIFO此位不起作用,用于外设突发

  22.     HAL_DMA_Init(&DMA_Handle);
  23.    
  24.     __HAL_LINKDMA(&ADC1_Handler, DMA_Handle, DMA_Handle);
  25.    
  26.     ADC1_Handler.Instance                   =  ADC1;
  27.     ADC1_Handler.Init.ClockPrescaler        =  ADC_CLOCK_ASYNC_DIV6;         //6分频
  28.     ADC1_Handler.Init.Resolution            =  ADC_RESOLUTION_16B;           //16位模式
  29.     ADC1_Handler.Init.ScanConvMode          =  ADC_SCAN_DISABLE;             //非扫描模式
  30.     ADC1_Handler.Init.EOCSelection          =  ADC_EOC_SINGLE_CONV;          //关闭EOC中断
  31.     ADC1_Handler.Init.LowPowerAutoWait      =  DISABLE;                      //自动低功耗关闭
  32.     ADC1_Handler.Init.ContinuousConvMode    =  ENABLE;                       //连续转换
  33.     ADC1_Handler.Init.NbrOfConversion       =  1;                            //1个转换在规则序列中 也就是只转换规则序列1
  34.     ADC1_Handler.Init.DiscontinuousConvMode =  DISABLE;                      //禁止不连续采样模式
  35.     ADC1_Handler.Init.NbrOfDiscConversion   =  0;                            //不连续采样通道数为0
  36.     ADC1_Handler.Init.ExternalTrigConv      =  ADC_SOFTWARE_START;           //软件触发
  37.     ADC1_Handler.Init.ExternalTrigConvEdge  =  ADC_EXTERNALTRIGCONVEDGE_NONE;//使用软件触发
  38.     ADC1_Handler.Init.Overrun               =  ADC_OVR_DATA_OVERWRITTEN;     //有新的数据的死后直接覆盖掉旧数据
  39.     ADC1_Handler.Init.OversamplingMode      =  ENABLE;                       //过采样
  40.     ADC1_Handler.Init.Oversampling.Ratio    =  15;                           //15+1倍过采样
  41.     ADC1_Handler.Init.Oversampling.RightBitShift         = ADC_RIGHTBITSHIFT_4; //数据右移4bit
  42.     ADC1_Handler.Init.Oversampling.TriggeredMode         = ADC_TRIGGEREDMODE_SINGLE_TRIGGER;
  43.     ADC1_Handler.Init.Oversampling.OversamplingStopReset = ADC_REGOVERSAMPLING_CONTINUED_MODE;
  44.     ADC1_Handler.Init.ConversionDataManagement=ADC_CONVERSIONDATA_DMA_CIRCULAR;//DMA循环模式接收ADC转换的数据
  45.     HAL_ADC_Init(&ADC1_Handler);                                             //初始化

  46.     HAL_ADCEx_Calibration_Start(&ADC1_Handler,ADC_CALIB_OFFSET,ADC_SINGLE_ENDED); //ADC校准
  47.    
  48.     ADC1_ChanConf.Channel                   = ADC_CHANNEL_5;                      //通道
  49.     ADC1_ChanConf.Rank                      = ADC_REGULAR_RANK_1;                 //1个序列
  50.     ADC1_ChanConf.SamplingTime              = ADC_SAMPLETIME_810CYCLES_5;         //采样时间
  51.     ADC1_ChanConf.SingleDiff                = ADC_SINGLE_ENDED;                   //单边采集
  52.     ADC1_ChanConf.OffsetNumber              = ADC_OFFSET_NONE;            
  53.     ADC1_ChanConf.Offset                    = 0;
  54.     ADC1_ChanConf.OffsetRightShift          = DISABLE;
  55.     ADC1_ChanConf.OffsetSignedSaturation    = DISABLE;
  56.     HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);                          //通道配置
  57.    
  58.     HAL_ADC_Start_DMA(&ADC1_Handler, (uint32_t *)ADCxValues, 1);
  59.    
  60.     return RT_EOK;
  61. }
复制代码
ad_vol = get_adc()/65536.0*3.3
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107027
QQ
发表于 2019-11-16 09:36:24 | 显示全部楼层
参考我的吧,没问题

STM32H7的ADC过采样功能立竿见影,效果的确不错
http://www.armbbs.cn/forum.php?m ... 1362&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

18

主题

321

回帖

375

积分

高级会员

积分
375
 楼主| 发表于 2019-11-16 09:40:48 | 显示全部楼层
eric2013 发表于 2019-11-16 09:36
参考我的吧,没问题

STM32H7的ADC过采样功能立竿见影,效果的确不错

就是参考的您的啊,测量出电压是2.22V
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107027
QQ
发表于 2019-11-16 09:45:15 | 显示全部楼层
王海靖 发表于 2019-11-16 09:40
就是参考的您的啊,测量出电压是2.22V

我们V7板子测试没问题,完全正确。
回复

使用道具 举报

18

主题

321

回帖

375

积分

高级会员

积分
375
 楼主| 发表于 2019-11-16 14:05:28 | 显示全部楼层
eric2013 发表于 2019-11-16 09:45
我们V7板子测试没问题,完全正确。

硬汉老大,你的例子确认没错,但是注释有错啊,允许我做一个悲伤的表情。
  1.     AdcHandle.Init.ClockPrescaler        = ADC_CLOCK_ASYNC_DIV8;          /* 采用PLL异步时钟,8分频,即72MHz/8 = 36MHz */
复制代码
你这明明是9MHz啊,哪里是36M 啊,我把频率降低一点就好了。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107027
QQ
发表于 2019-11-16 14:09:45 | 显示全部楼层
王海靖 发表于 2019-11-16 14:05
硬汉老大,你的例子确认没错,但是注释有错啊,允许我做一个悲伤的表情。
你这明明是9MHz啊,哪里是36M  ...

72/8 明显不等于36嘛。。。
回复

使用道具 举报

13

主题

223

回帖

262

积分

高级会员

积分
262
发表于 2019-11-16 15:21:48 | 显示全部楼层
王海靖 发表于 2019-11-16 14:05
硬汉老大,你的例子确认没错,但是注释有错啊,允许我做一个悲伤的表情。
你这明明是9MHz啊,哪里是36M  ...

我也也到你这个问题了,定时器160K驱动adc采样,使用16位过采样,2.5V电压采集过来换算只有2.33V,你频率降到多少了?
回复

使用道具 举报

18

主题

321

回帖

375

积分

高级会员

积分
375
 楼主| 发表于 2019-11-16 18:56:29 | 显示全部楼层
miaoqiongb 发表于 2019-11-16 15:21
我也也到你这个问题了,定时器160K驱动adc采样,使用16位过采样,2.5V电压采集过来换算只有2.33V,你频率 ...

PLL2 200M 32分频
回复

使用道具 举报

13

主题

223

回帖

262

积分

高级会员

积分
262
发表于 2019-11-18 12:59:53 | 显示全部楼层
eric2013 发表于 2019-11-16 14:09
72/8 明显不等于36嘛。。。

硬汉是不是H750不支持定时器触发过采样?我现在用16位过采样,定时器设置位10K*16=160K,采集的2.5V电压实际换算只有2.33V,ADC使用的是ADC_CLOCK_SOURCE_AHB时钟,4分频即200MHz/4=50MHZ,如果我把过采样关闭,电压可以达到2.5V?
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107027
QQ
发表于 2019-11-18 13:20:04 | 显示全部楼层
miaoqiongb 发表于 2019-11-18 12:59
硬汉是不是H750不支持定时器触发过采样?我现在用16位过采样,定时器设置位10K*16=160K,采集的2.5V电压 ...

H743和H750的ADC一样,没有区别。
回复

使用道具 举报

13

主题

223

回帖

262

积分

高级会员

积分
262
发表于 2019-12-21 13:02:05 | 显示全部楼层

你的采样速度是多少?
回复

使用道具 举报

8

主题

50

回帖

79

积分

初级会员

积分
79
发表于 2023-2-26 21:15:28 | 显示全部楼层
eric2013 发表于 2019-11-18 13:20
H743和H750的ADC一样,没有区别。

我觉得这个问题可能主要是问定时器触发转换模式下,能不能过采样,能的话是应该将定时器触发频率提高到原有频率乘以过采样率吗,还是保持不变即可,这个问题也是我遇到的问题。。。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107027
QQ
发表于 2023-2-28 10:09:25 | 显示全部楼层
wling597074509 发表于 2023-2-26 21:15
我觉得这个问题可能主要是问定时器触发转换模式下,能不能过采样,能的话是应该将定时器触发频率提高到原 ...

对,有这种问题,触发速度不能超过总的采样时间,
回复

使用道具 举报

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

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-14 13:55 , Processed in 0.186428 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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