硬汉嵌入式论坛

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

[DSP] ADC采样+DMA传输做FFT时理论设置的采样率不对,求助哪位大佬解惑

[复制链接]

1

主题

6

回帖

9

积分

新手上路

积分
9
发表于 2023-6-26 20:49:30 | 显示全部楼层 |阅读模式
     本人想用H7一个ADC通道连续采样5K的正弦波信号,通过DMA传输采集1024个数据后做FFT,按照芯片手册上ADC的转换时间等于:采样时间+7.5周期(14位分辨率),按照这个计算出采样率后,将采集到的信号通过串口发送到MATLAB进行FFT后,发现频谱图上的频率为5.5K左右,现在怀疑是不是通过芯片手册上的公式计算出来的采样率不对,导致FFT后测得的频率不对,反复查看资料还是不知道哪里出了问题,希望大佬们指点一下!
回复

使用道具 举报

75

主题

684

回帖

909

积分

金牌会员

积分
909
发表于 2023-6-26 23:21:01 | 显示全部楼层
你数据点太少了点把
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2023-6-27 08:23:15 | 显示全部楼层
你的采样率是多少。
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2023-6-27 08:33:41 | 显示全部楼层
庄永 发表于 2023-6-26 23:21
你数据点太少了点把

采样率不高,15K多,每个周期采样3个点,总共采样1024个点后做FFT
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2023-6-27 08:40:36 | 显示全部楼层
eric2013 发表于 2023-6-27 08:23
你的采样率是多少。

我的采样率是15625,AD的时钟是64M的256分频后为250K,按照手册AD的转换总时间为:8.5周期(采样时间)+7.5周期(14位AD时的逐次逼近时间)=16个周期时钟,则250K/16=15625,这是理论的采样频率,但是做FFT后发现测得的信号频率5.5K左右,差别太大了,虽然实际频率点没有刚好落在N点的对应频率上,但是误差不应该这么大的
回复

使用道具 举报

75

主题

684

回帖

909

积分

金牌会员

积分
909
发表于 2023-6-27 14:15:50 | 显示全部楼层
wsyinghe31 发表于 2023-6-27 08:33
采样率不高,15K多,每个周期采样3个点,总共采样1024个点后做FFT

那应该还好呀,是不是信号里面噪声太大了
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2023-6-27 15:40:54 | 显示全部楼层
庄永 发表于 2023-6-27 14:15
那应该还好呀,是不是信号里面噪声太大了

噪声不大,我设置的是AD连续采样模式,DMA也是循环模式,不知道这些有没有影响
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2023-6-27 16:32:33 | 显示全部楼层
wsyinghe31 发表于 2023-6-27 08:40
我的采样率是15625,AD的时钟是64M的256分频后为250K,按照手册AD的转换总时间为:8.5周期(采样时间)+7 ...

FFT幅频特性图绘制出来,截个图分享下。你当前每个周期才3个点左右,频谱泄露应该很大。

回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2023-6-27 16:52:30 | 显示全部楼层
eric2013 发表于 2023-6-27 16:32
FFT幅频特性图绘制出来,截个图分享下。你当前每个周期才3个点左右,频谱泄露应该很大。

是的  只有3个点   频谱泄露是会比较大,但是测得的频率应该不会差这么多的,测量信号是5.1K的由信号发生器产生的正弦波信号

FFT

FFT
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2023-6-27 17:06:17 | 显示全部楼层
eric2013 发表于 2023-6-27 16:32
FFT幅频特性图绘制出来,截个图分享下。你当前每个周期才3个点左右,频谱泄露应该很大。

                __HAL_RCC_GPIOB_CLK_ENABLE();
                __HAL_RCC_GPIOC_CLK_ENABLE();
       
                __HAL_RCC_ADC12_CLK_ENABLE();           //使能ADC1/2时钟
       
       

       
       
       
         GPIO_Initure.Pin = GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4;   
        GPIO_Initure.Mode = GPIO_MODE_ANALOG;      //模拟
        GPIO_Initure.Pull = GPIO_NOPULL;          //不带上下拉   
         HAL_GPIO_Init(GPIOC,&GPIO_Initure);       //初始化
       
       
         GPIO_Initure.Pin = GPIO_PIN_1;   
        GPIO_Initure.Mode = GPIO_MODE_ANALOG;      //模拟
        GPIO_Initure.Pull = GPIO_NOPULL;          //不带上下拉   
         HAL_GPIO_Init(GPIOB,&GPIO_Initure);       //初始化


       
                RCC->AHB1RSTR|=1<<5;                   //ADC1/2复位
                RCC->AHB1RSTR&=~(1<<5);                //复位结束       
                RCC->D3CCIPR&=~(3<<16);                //ADCSEL[1:0]清零
                RCC->D3CCIPR|=2<<16;                //ADCSEL[1:0]=2,per_ck作为ADC时钟源,默认选择hsi_ker_ck作为per_ck,频率:64Mhz
                ADC12_COMMON->CCR|= (11<<18);        //PRESC[3:0],输入时钟256分频,即adc_ker_ck=per_ck/256=64/256=250k(不能超过36Mhz)
               
                ADC1->CR=0;                                   //CR寄存器清零,DEEPPWD清零,从深度睡眠唤醒.
                ADC1->CR|=1<<28;                          //ADVREGEN=1,使能ADC稳压器
                delay_ms(10);                                //等待稳压器启动完成,约10us,这里延时大一点,没关系.
                ADC1->CR|= 0<<8;                          //BOOST=0,       
                ADC1->CFGR |= (1<<13);                //循环转换模式
                ADC1->CFGR|=1<<12;                        //OVRMOD=1,复写模式(DR寄存器可被复写)       
                ADC1->CFGR&=~(3<<10);                //EXTEN[1:0]=0,软件触发
                ADC1->CFGR&=~(7<<2);                //RES[2:0]位清零  16位AD
                ADC1->CFGR|=1<<2;                        //RES[2:0]=1,14位分辨率(0,16位;1,14位;2,12位;3,10位;4,8位.)
                ADC1->CFGR|=3<<0;     //使能DMA循环模式
               

                ADC1->CFGR2&=~((u32)15<<28);//LSHIFT[3:0]=0,不左移,数据右对齐.
                ADC1->CFGR2&=~((u32)0X3FF<<16);//OSR[9:0]=0,不使用过采样
               
               
                ADC1->CR&=~((u32)1<<30);        //ADCALDIF=0,校准单端转换通道
                ADC1->CR|=1<<16;                        //ADCALLIN=1,线性校准
                ADC1->CR|=(u32)1<<31;                //开启校准
                while(ADC1->CR&((u32)1<<31));//等待校准完成
                 
                ADC1->SQR1&=~(0XF<<0);                //L[3:0]清零
                ADC1->SQR1|=0<<0;                     //L[3:0]=0,1个转换在规则序列中 也就是只转换规则序列1
               
                //设置通道4的采样时间
                ADC1->SMPR1 &=~(7<<(12));        //通道采样时间清空          
                //ADC1->SMPR1 |= (6 << 12);                 //通道4 8.5个周期,提高采样时间可以提高精确度                8.5 + 7.5 = 16
                ADC1->SMPR1 |= (2 << 12);                 //通道4 8.5个周期,提高采样时间可以提高精确度                8.5 + 7.5 = 16
                ADC1->CR|=1<<0;                                   //开启AD转换器       

                delay_ms(20);
                ADC1->PCSEL|=1<<4;                        //ADC转换通道预选择 ADC12_INP4
          //设置转换序列                           
          ADC1->SQR1&=~(0X1F<<6*1);        //规则序列1通道清零
          ADC1->SQR1|= 4<<6*1;                  //设置规则序列1的转换通道为ch
               
          ADC1->CR|=1<<2;                       //启动规则转换通道


        RCC->AHB1ENR|=1<<1;                        //DMA2时钟使能  
        RCC->D3AMR|=1<<0;                        //DMAMUX时钟使能
       
        while(DMA2_Stream6->CR&0X01);//等待DMA2_Stream6可配置
        DMAMUX1_Channel14->CCR=9;        //DMA2_Stream6的通道选择: 9,即AD1对应的通道
                                                               
       
        DMA2->HIFCR|=0X3D<<16;                //清空通道6上所有中断标志
        DMA2_Stream6->FCR=0X0000021;//设置为默认值       
       
        DMA2_Stream6->PAR=(u32)&ADC1->DR;//外设地址为:ADC1->DR
        DMA2_Stream6->M0AR=(u32)buf0;//内存1地址
        DMA2_Stream6->NDTR=num;                //暂时设置长度为
        DMA2_Stream6->CR=0;                          //先全部复位CR寄存器值  
        DMA2_Stream6->CR|=0<<6;                //外设到存储器模式
        DMA2_Stream6->CR|=1<<8;                //循环模式
        DMA2_Stream6->CR|=0<<9;                //外设非增量模式
        DMA2_Stream6->CR|=1<<10;        //存储器增量模式
        DMA2_Stream6->CR|=(u16)width<<11;//外设数据长度:16位/32位
        DMA2_Stream6->CR|=(u16)width<<13;//存储器数据长度:16位/32位
        DMA2_Stream6->CR|=1<<16;        //中等优先级
        DMA2_Stream6->CR|=0<<18;        //非双缓冲模式
        DMA2_Stream6->CR|=0<<21;        //外设突发单次传输
        DMA2_Stream6->CR|=0<<23;        //存储器突发单次传输
        DMA2_Stream6->CR|=0<<25;       

        DMA2_Stream6->FCR&=~(1<<2);        //不使用FIFO模式
        DMA2_Stream6->FCR&=~(3<<0);        //无FIFO 设置
       
        DMA2_Stream6->CR|=1<<4;                //开启传输完成中断

        MY_NVIC_Init(0,0,DMA2_Stream6_IRQn,2);       


这是AD和DMA设置代码

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106660
QQ
发表于 2023-6-27 17:21:48 | 显示全部楼层
wsyinghe31 发表于 2023-6-27 16:52
是的  只有3个点   频谱泄露是会比较大,但是测得的频率应该不会差这么多的,测量信号是5.1K的由信号发生 ...

改一下
采用定时器触发ADC + DMA采集,每个周期有100个采样点,采集1024,让波形的频率是你FFT频域最小分辨率的整数倍,这样测试就非常准了。
回复

使用道具 举报

1

主题

6

回帖

9

积分

新手上路

积分
9
 楼主| 发表于 2023-6-27 17:47:03 | 显示全部楼层
eric2013 发表于 2023-6-27 17:21
改一下
采用定时器触发ADC + DMA采集,每个周期有100个采样点,采集1024,让波形的频率是你FFT频域最小 ...

谢谢您的建议,但是现在这种做法偏差有400HZ左右,我怀疑是不是我哪里设置有问题,是想找到问题点出在哪里,按照H7手册上的ADC转换时间公式计算的采样频率是不是准确的?ADC连续采样模式是不是按照这个采样频率均匀时间采样的?DMA的传输会不会影响到ADC的采样时间?感觉比较迷惑!
回复

使用道具 举报

75

主题

684

回帖

909

积分

金牌会员

积分
909
发表于 2023-6-27 21:49:00 | 显示全部楼层
wsyinghe31 发表于 2023-6-27 17:47
谢谢您的建议,但是现在这种做法偏差有400HZ左右,我怀疑是不是我哪里设置有问题,是想找到问题点出在哪 ...

1、排查一下时钟准不准
2、排查一下是不是信号就是5.5K的
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-29 00:29 , Processed in 0.203036 second(s), 29 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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