查看: 3724|回复: 1

NUCLEO-F767ZI】最强3ADC交替采样+DMA(5.4MSa/s)

[复制链接]
  • TA的每日心情
    开心
    2016-9-21 20:33
  • 签到天数: 29 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2016-8-5 12:22:50 | 显示全部楼层 |阅读模式
    分享到:
    一通道3ADC交替采样+DMA传输数据  速度高达 5.4MSa/s这是我见过的最强MCU自带ADC了。
    NUCLEO-F767ZI自带3个ADC ,在系统时钟216MHZ 的情况下 ADC时钟 4分频 的到27MHZ的时钟ADCCLK=PCLK2/4=108/4=27MHZ
    交替模式下 2个ADC 转换之间的延迟是5个时钟周期
    总体的转化周期是15/3=5个周期
    ADC 时钟是27MHZ
    所以  采样率是27/5=5.4MSa/s

    QQ截图20160805105806.png
    QQ截图20160805110226.png

    F767手册上介绍
    QQ截图20160805104150.png
    F767是带有3个12位的ADC,它有高达19多路复用的通道,使它可以测量来自16个外部源的信号,两个内部来源。
    下面介绍一下一通道的3ADC交替采样的原理

    在多重 ADC 模式下,通过 ADC1 主器件到 ADC2 和 ADC3 从器件的交替触发或同时触发来
    启动转换,具体取决于 ADC_CCR 寄存器中的 MULTI[4:0] 位所选的模式
    注: 在多重 ADC  模式下,配置外部事件触发转换时,应用必须设置为仅主器件触发而禁止从器件
    触发,以防止出现意外触发而启动不需要的从转换。
    可实现以下四种模式:
    注入同步模式
    常规同步模式
    交替模式
    交替触发模式
    也可按以下方式组合使用上述模式:
    注入同步模式 + 常规同步模式
    常规同步模式 + 交替触发模式

    三重 ADC  模式
    出现外部触发之后:
    ADC1 立即启动
    经过几个 ADC 时钟周期延迟后 ADC2 启动
    在 ADC2 转换经过几个 ADC 时钟周期的延迟后 ADC3 启动
    交替模式下 2 个转换之间的最小延迟通过 ADC_CCR 寄存器中的 DELAY 位进行配置。但是,
    如果某个 ADC 的互补 ADC 仍在对其输入进行采样,则该 ADC 无法启动转换(在给定时间
    内,只有一个 ADC 能够对输入信号采样)。在这种情况下,延迟时间为采样时间 + 2 个 ADC
    时钟周期。例如,如果这三个 ADC 的 DELAY = 5 个时钟周期,且采样时间为 15 个时钟周
    期,则 ADC1、ADC2 和 ADC3 之间的转换延迟为 17 个时钟周期。
    如果 ADC1、ADC2 和 ADC3 上的 CONT 位均置 1,则这些 ADC 所选常规通道会连续进行
    转换。
    注: 如果转换序列中断(例如 DMA  传输结束时),则必须首先通过在独立模式下进行配置来将多
    重 ADC  定序器复位(位 DUAL[4:0] = 00000 ),然后才可以对交替模式进行编程。
    在此模式下,每当出现 2 个可用数据项时,就会生成一个 DMA 传输请求(如果 ADC_CCR
    寄存器中的 DMA[1:0] 位等于 0b10)。此请求首先会将存储在 ADC_CDR 32 位寄存器低位
    半字中的第一批转换数据传输到 SRAM,然后将存储在 ADC_CDR 高位半字中的第二批转换
    数据传输到 SRAM。具体顺序如下:
    第 1 个请求:ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]
    第 2 个请求:ADC_CDR[31:0] = ADC1_DR[15:0] | ADC3_DR[15:0]
    第 3 个请求:ADC_CDR[31:0] = ADC3_DR[15:0] | ADC2_DR[15:0]
    第 4 个请求:ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]
    QQ截图20160805104904.png
    简要:
    AD 转换包括采样阶段和转换阶段,在采样阶段才对通道数据进行采集;而在转换阶
    段只是将采集到的数据进行转换为数字量输出,此刻通道数据变化不会改变转换结果。独
    立模式的 ADC采集需要在一个通道采集并且转换完成后才会进行下一个通道的采集。双
    重或者三重 ADC的机制使用两个或以上 ADC同时采样两个或以上不同通道的数据或者使
    用两个或以上 ADC交叉采集同一通道的数据。双重或者三重 ADC模式较独立模式一个最
    大的优势就是转换速度快。
           介绍三重 ADC交替模式,三重 ADC交替模式是针对同一通道的使用三个 ADC
    交叉采集,就是在 ADC1 采样完等几个时钟周期后 ADC2 开始采样,此时 ADC1处在转换
    阶段,当 ADC2 采样完成再等几个时钟周期后 ADC3就进行采样此时 ADC1 和 ADC2 处在
    转换阶段,如果 ADC3 采样完成并且 ADC1已经转换完成那么就可以准备下一轮的循环,
    这样充分利用转换阶段时间达到增快采样速度的效果。AD 转换过程见图 30-6,利用 ADC
    的转换阶段时间另外一个 ADC 进行采样,而不用像独立模式必须等待采样和转换结束后
    才进行下一次采样及转换。
    -----------------------------------多重 ADC 模式下的 DMA 请求(我选用DMA模式2)-------------------------------
    DMA  模式 2:每发送一个 DMA 请求(两个数据项可用),就会以字的形式传输表
    示两个 ADC 转换数据项的两个半字。
    在双重 ADC 模式下,发出第一个请求时会传输 ADC2 和 ADC1 的数据(ADC2 数
    据占用高位半字,ADC1 数据占用低位半字),依此类推。
    在三重 ADC 模式下,将生成三个 DMA 请求:发出第一个请求时,会传输 ADC2 和
    ADC1 的数据(ADC2 数据占用高位半字,ADC1 数据占用低位半字)。发出第二
    个请求时,会传输 ADC1 和 ADC3 的数据(ADC1 数据占用高位半字,ADC3 数
    据占用地位半字)。发出第三个请求时,会传输 ADC3 和 ADC2 的数据(ADC3
    占用高位半字,ADC2 数据占用地位半字),依此类推。
    DMA 模式 2 用于交替模式和常规同步模式(仅适用于双重 ADC 模式)。
    示例:
    a)  双重交替模式:每当有 2 个数据项可用时,就会生成一个 DMA 请求:
    第 1 个请求:ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]
    第 2 个请求:ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]
    b)  三重交替模式:每当有 2 个数据项可用时,就会生成一个 DMA 请求
    第 1 个请求:ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]
    第 2 个请求:ADC_CDR[31:0] = ADC1_DR[15:0] | ADC3_DR[15:0]
    第 3 个请求:ADC_CDR[31:0] = ADC3_DR[15:0] | ADC2_DR[15:0]
    第 4 个请求:ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]

    在F767的datasheetz中介绍 GPIO PC2 是ADC1 ADC2 ADC3的第12通道
    这里我选用GPIO PC2口
    QQ截图20160805104639.png
    DMA2数据流0 通道 0
    QQ截图20160805104543.png
    QQ截图20160805104602.png


    下面开始配置了
    代码:
    ADC配置:
    1. #include "sys.h"
    2. #include "adc.h"

    3.         ADC_HandleTypeDef ADC1_Handler ;
    4.         ADC_HandleTypeDef ADC2_Handler ;
    5.         ADC_HandleTypeDef ADC3_Handler ;

    6. extern uint32_t ADC123_Buff[3];

    7. int i=0;
    8. //ADC底层驱动,引脚配置,时钟使能
    9. //此函数会被HAL_ADC_Init()调用

    10. void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
    11. {
    12.    GPIO_InitTypeDef   GPIO_InitStruct;
    13.    DMA_HandleTypeDef  hdma_adc;
    14.   __HAL_RCC_GPIOC_CLK_ENABLE();//开启GPIOC的时钟
    15.   __HAL_RCC_ADC1_CLK_ENABLE();//开启ADC 1 2 3 的时钟
    16.   __HAL_RCC_ADC2_CLK_ENABLE();
    17.   __HAL_RCC_ADC3_CLK_ENABLE();
    18.   __HAL_RCC_DMA2_CLK_ENABLE(); //开启DMA的时钟

    19.   //设置GPIOC2 模拟输入
    20.   GPIO_InitStruct.Pin = GPIO_PIN_2;
    21.   GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    22.   GPIO_InitStruct.Pull = GPIO_NOPULL;//不上拉也不下拉
    23.   HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    24.         

    25.    //配置DMA
    26.   hdma_adc.Instance = DMA2_Stream0;//   数据流 0 通道 0
    27.   hdma_adc.Init.Channel = DMA_CHANNEL_0;
    28.   hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;//外设到寄存器
    29.   hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;//外设地址非增量
    30.   hdma_adc.Init.MemInc = DMA_MINC_ENABLE;//内存地址递增
    31.   hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;// 32位
    32.   hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; //32位
    33.   hdma_adc.Init.Mode = DMA_CIRCULAR; //循环模式
    34.   hdma_adc.Init.Priority = DMA_PRIORITY_HIGH; //优先级高
    35.   hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE; //关闭FIFO
    36.   hdma_adc.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
    37.   hdma_adc.Init.MemBurst = DMA_MBURST_SINGLE; //单次突发
    38.   hdma_adc.Init.PeriphBurst = DMA_PBURST_SINGLE; //单次突发

    39.   HAL_DMA_Init(&hdma_adc);
    40.         
    41.   __HAL_LINKDMA(hadc, DMA_Handle, hdma_adc);

    42.   /* NVIC配置DMA传输完成中断 */
    43.   HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
    44.   HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);        
    45. }




    46. void ADC123_Config(void)
    47. {
    48.   ADC_ChannelConfTypeDef sConfig; //ADC 通道的
    49.   ADC_MultiModeTypeDef   mode; //ADC 模式的选择

    50.   /*##-1- Configure the ADC2 peripheral ######################################*/
    51.   ADC3_Handler.Instance          = ADC3;
    52.   ADC3_Handler.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;  // 108/4 = 27 MHZ
    53.   ADC3_Handler.Init.ScanConvMode = DISABLE; //关闭扫描模式
    54.   ADC3_Handler.Init.ContinuousConvMode = ENABLE; //使能连续转换模式
    55.   ADC3_Handler.Init.DiscontinuousConvMode = DISABLE;
    56.   ADC3_Handler.Init.NbrOfDiscConversion = 0; //第0个转换 通道0 的
    57.   ADC3_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; //用软件触发
    58.   ADC3_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START ; //软件触发
    59.   ADC3_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //数据右对齐
    60.   ADC3_Handler.Init.NbrOfConversion = 1; //连续采样 通道数为 1
    61.   ADC3_Handler.Init.DMAContinuousRequests = DISABLE;
    62.   ADC3_Handler.Init.EOCSelection = DISABLE;

    63.   if (HAL_ADC_Init(&ADC3_Handler) != HAL_OK)
    64.   {
    65.     /* Initialization Error */
    66.     Error_Handler();
    67.   }

    68.   /*##-2- Configure ADC3 regular channel #####################################*/
    69.   sConfig.Channel = ADC_CHANNEL_12;
    70.   sConfig.Rank = 1;
    71.   sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
    72.   sConfig.Offset = 0;

    73.   if(HAL_ADC_ConfigChannel(&ADC3_Handler, &sConfig) != HAL_OK)
    74.   {
    75.     /* Channel Configuration Error */
    76.     Error_Handler();
    77.   }

    78.   /*##-3- Configure the ADC2 peripheral ######################################*/
    79.   ADC2_Handler.Instance          = ADC2;

    80.   ADC2_Handler.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
    81.   ADC2_Handler.Init.ScanConvMode = DISABLE;
    82.   ADC2_Handler.Init.ContinuousConvMode = ENABLE;
    83.   ADC2_Handler.Init.DiscontinuousConvMode = DISABLE;
    84.   ADC2_Handler.Init.NbrOfDiscConversion = 0;
    85.   ADC2_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    86.   ADC2_Handler.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
    87.   ADC2_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    88.   ADC2_Handler.Init.NbrOfConversion = 1;
    89.   ADC2_Handler.Init.DMAContinuousRequests = DISABLE;
    90.   ADC2_Handler.Init.EOCSelection = DISABLE;

    91.   if (HAL_ADC_Init(&ADC2_Handler) != HAL_OK)
    92.   {
    93.     /* Initialization Error */
    94.     Error_Handler();
    95.   }

    96.   /*##-4- Configure ADC2 regular channel #####################################*/
    97.   sConfig.Channel = ADC_CHANNEL_12;
    98.   sConfig.Rank = 1;
    99.   sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
    100.   sConfig.Offset = 0;

    101.   if (HAL_ADC_ConfigChannel(&ADC2_Handler, &sConfig) != HAL_OK)
    102.   {
    103.     /* Channel Configuration Error */
    104.     Error_Handler();
    105.   }

    106.   /*##-5- Configure the ADC1 peripheral ######################################*/
    107.   ADC1_Handler.Instance          = ADC1;

    108.   ADC1_Handler.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV4;
    109.   ADC1_Handler.Init.ScanConvMode = DISABLE;
    110.   ADC1_Handler.Init.ContinuousConvMode = ENABLE;
    111.   ADC1_Handler.Init.DiscontinuousConvMode = DISABLE;
    112.   ADC1_Handler.Init.NbrOfDiscConversion = 0;
    113.   ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    114.   ADC1_Handler.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1;
    115.   ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    116.   ADC1_Handler.Init.NbrOfConversion = 1;
    117.   ADC1_Handler.Init.DMAContinuousRequests = ENABLE;
    118.   ADC1_Handler.Init.EOCSelection = DISABLE;
    119.   

    120.   if (HAL_ADC_Init(&ADC1_Handler) != HAL_OK)
    121.   {
    122.     /* Initialization Error */
    123.     Error_Handler();
    124.   }

    125.   /*##-6- Configure ADC1 regular channel #####################################*/
    126.   if (HAL_ADC_ConfigChannel(&ADC1_Handler, &sConfig) != HAL_OK)
    127.   {
    128.     /* Channel Configuration Error */
    129.     Error_Handler();
    130.   }

    131.   /*##-7- Configure Multimode ################################################*/
    132.   mode.Mode = ADC_TRIPLEMODE_INTERL; //三重交替模式
    133.   mode.DMAAccessMode = ADC_DMAACCESSMODE_2; //DMA模式2
    134.   mode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES; //两个ADC采样的间隔是5时钟间隔
    135.   if (HAL_ADCEx_MultiModeConfigChannel(&ADC1_Handler, &mode) != HAL_OK)
    136.   {
    137.     /* Multimode Configuration Error */
    138.     Error_Handler();
    139.   }        
    140. }

    141. void DMA2_Stream0_IRQHandler (void)  
    142. {  
    143.   if(DMA2->LISR & 0x00000010) //完成中断
    144.   {  
    145.      DMA2->LIFCR |= 0x00000010;  
    146.          for(i=0;i<1024;i++)
    147.                 {
    148.                         printf("ADC:%f V   ",(float)(uint16_t)ADC123_Buff[i]*(3.3/4096));
    149.                 }
    150.   }        
    151. }  

    复制代码
    main:
    1. #include "sys.h"
    2. #include "led.h"
    3. #include "uart.h"
    4. #include "adc.h"
    5. extern UART_HandleTypeDef UART3_Handler;
    6. extern ADC_HandleTypeDef ADC1_Handler ;
    7. extern ADC_HandleTypeDef ADC2_Handler ;
    8. extern ADC_HandleTypeDef ADC3_Handler ;
    9. uint32_t ADC123_Buff[1024];
    10. int main(void)
    11. {
    12.         double data;
    13.   int len,i=0;
    14.   MPU_Config();
    15.   CPU_CACHE_Enable();
    16.   HAL_Init();
    17.   SystemClock_Config();
    18.         Led_Init();
    19.   uart_init(9600);
    20.         ADC123_Config();
    21.   HAL_ADC_Start(&ADC3_Handler);
    22.         HAL_ADC_Start(&ADC2_Handler);
    23.         HAL_ADCEx_MultiModeStart_DMA(&ADC1_Handler, (uint32_t *)ADC123_Buff, 1024);
    24.   while (1)
    25.   {        
    26. }
    27. }
    复制代码
    下面是串口输出的:

    20160805095808.png

    一通道3ADC交替采样+DMA传输数据  速度高达 5.4MSa/s这是我见过的最强MCU自带ADC了。

    回复

    使用道具 举报

  • TA的每日心情

    2021-12-11 14:10
  • 签到天数: 173 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2016-8-5 12:48:48 | 显示全部楼层
    这个ADC比较猛啊!
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-25 06:50 , Processed in 0.126425 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.