AT32(六)TMR输出时钟和DMA请求实现两片AD9220同步采样

前言

有个小项目需要用到两片AD9220——10MSPS并口12位ADC——做同步采样,想到AT32F435可以通过定时器实现让DMA按照特定频率从GPIO数据寄存器搬运数据到内存,于是把这个想法实现一下。

软件/硬件环境

  • VScode ( EIDE + Cortex Debug )
  • Open On-Chip Debugger 0.11.0+dev-snapshot
  • arm-none-eabi-gcc.exe (GNU Arm Embedded Toolchain 10.3-2021.10) 10.3.1 20210824 (release) 
  • Python 3.7.8 64bit (需要库:matplotlib, numpy, serial, time)
  • AT32F435RGT7系统板 & ATLink
  • AD9220采样板x2

  AD9220采样板(1/2)

功能描述

同步采样实现基础

AD9220需要占空比约50%的10MHz时钟信号驱动,一次采样开始到下一个数据接收时间间隔低至8ns。

 AD9220时序要求 

AD9220的输入级是一个采样保持放大器(SHA),如果两片AD9220用同一个时钟驱动,则可以实现同步采样。因此将AT32某个时钟通道配置成PWM输出模式,将其引脚同时与两片AD9220时钟引脚连接即可。

  • 时钟部分:这里使用TMR3的CH3作为时钟输出,对应的引脚为PB0,复用方式为MUX2。

这里还有一个小问题:AT32F435主频为288MHz,通过8M晶振经过主时钟PLL得到。此频率直接/或经过2分配作为AHB和APB时钟。然而TMR作为APB外设,没有锁相环功能,其时钟只能由APB时钟分配得到。不可能由288MHz产生10MHz的PWM频率。

因此只能痛失3%性能,把主频降频到280MHz。需要配置PLL相关寄存器将倍频系数将72改为70。此时:

TMR PWM频率 =

8M x 70(PLL倍频系数) / 2(PLL分频系数) / 1(APB分频系数) / 28(TMR计数阈值) = 10 M

为了满足AD9220时序,把TMR通道的计数阈值设置为TMR计数阈值的一半左右,即可输出占空比约50%的PWM。

TMR通道配置的细节可以参考 AT32(四):TMR——定时器、PWM输出与捕获_1S2H的博客-CSDN博客https://blog.csdn.net/m0_46882426/article/details/127068726?spm=1001.2014.3001.5501

这里配置为TMR_OUTPUT_CONTROL_PWM_MODE_A模式,idle_state为低电平,有效电平为高电平。 

  • GPIO部分:并口12位ADC在与单片机GPIO连接时,注意LSB连接GPIO引脚号小的,MSB连接GPIO引脚号大的,并且最好使用同一个GPIO端口上的连续、相邻的12个引脚。这是因为读GPIO数据寄存器的值,到实际有意义的12bit数据,还有一个必不可少的数据处理过程。

这里为了方便数据处理过程,第一片AD9220从LSB到MSB依序连接PB4~PB15;第二片AD9220从LSB到MSB依序连接PC0~PC11。这样,在得到GPIO数据寄存器值后,只需要将其逻辑右移4位(第一片)或者“按位与”0x0FFF(第二片)即可。

  • DMA部分:DMA的通道需要一个请求信号告诉它什么时候该搬运一次。这个请求由TMR通道比较事件发出。在TMR通道输出模式下,每当TMR计数值大于等于通道设定值时发生该通道的比较事件。PWM_MODE_A模式下,比较事件发生的同时TMR通道电平将产生通道输出的下降沿,变为低电平。

这样,就实现了DMA在TMR通道输出时钟的下降沿完成对AD9220返回数据的搬运,与AD9220要求的时序一致。

初始化过程

按照上文的描述分别初始化单片机的GPIO,TMR,DMA。

其中,只有DMA需要配置中断。即一轮同步采样完成后需要做的处理工作。并且由于同步采样的原因,只需为其中一个DMA通道配置。中断函数完成以下工作:

  • 关闭定时器时钟(虽然不怕费电,但10MHz还是有点吵的)
  • 对数组数据进行处理,只保留12bit有效数据(移位或者按位与)

为了方便移植,我的中断函数名使用连接符##的宏定义来与启动文件中的ISR名称对接。

但不幸的是有一天 DMAx_Channeln_IRQHanlder()的 "Channel" 被我误作全大写,导致程序在使能中断后片刻就进入一个名叫XMC_IRQHandler的中断中,十分奇妙。此bug耽误了我几天时间,最后迫不得已,使用gcc的预处理命令:

gcc -E -C -xc -std=gnu11 -I.eide/deps -Ilibraries/drivers/inc -Ilibraries/cmsis/cm4/core_support -Ilibraries/cmsis/cm4/device_support -IUsrProject -D_DEBUG -DAT32F435RGT7 -DUSE_STDPERIPH_DRIVER -DUNICODE -D_UNICODE -Ofast -Wall -g -ffunction-sections -fdata-sections -o ./build/Debug/UsrProject/AD9220/AD9220.o -MMD ./UsrProject/AD9220/AD9220.c

检查宏展开后的中间产物才de出此bug。

开始采样

简单来说,这一步只需要打开TMR通道的输出使能,然后一切就都可以运作了。但是实际上这样做还有点问题。

如下图,黄色(C1)为TMR通道输出的时钟信号,蓝色(C3)为输入到ADC的模拟信号。

 先初始化TMR通道值,使能TMR,最后开启TMR通道输出,会提前产生一个不规则的时钟沿

这是因为定时器硬件其实一直在实现“通道值比较”的功能,只要指定了通道值,就会立即产生一个对应的输出,和你有没有使能定时器无关。

所以我将设置TMR通道值的函数放到最后开始采样这一步,而在初始化TMR等外设时就将定时器和TMR通道使能。此时结果如下,似乎避免了时钟问题

 然而在后续的实践中发现问题并没有解决。使用串口输出数据,用python绘图(只画了一片AD9220的数据,数据大小理论值0~0xFFF,长度4096个)如下:

 先使能定时器,最后设置通道值虽然解决了实际时钟时序,但疑似出现提前采样的问题

我的疑惑:

已经可以确定时钟信号绝对没有问题——没有误产生提前的上升沿。

那么,没有时钟,ADC不可能工作,理论上DMA即便提前开始工作,也不可能得到如上图所示的前4个异常但有规律的采样值。

我先怀疑是DMA提前工作的问题。因为TMR初始化的过程中也可能产生通道比较事件,进而发送DMA请求。但我试过很多方法,包括在初始化TMR后清除所有相关的标志位;以及把DMA通道使能放到最后开启,这样DMA即便收到请求也无法提前工作——然而都失败了,仍然有3~4个像是提前采样得到的数据点。

后来几天仔细看了AD9220的手册,发现这种ADC有一个叫做Pipeline Delay (Latency)的参数,也就是说上文时序图中>8ns的延时并不是真正的数据转换时间,AD9220的Latency是3个时钟周期,和这里的现象基本吻合。因此我猜测是因为AD9220的digital logic里有若干层并口的触发器用来暂存数据。如果有大佬知道原因欢迎留言~

这种奇怪的时序问题不影响测直流,实测直流非常稳定:

  找时序问题的过程...把DMA通道使能放到最后,用直流测试,没有发现问题

当时仍然怀疑是使能顺序的问题,改用了很多不同的顺序,都无法解决问题。下图是先使能TMR和DMA最后使能DMA MUX功能并指定TMR通道值,用低频三角波测试的结果。

 

找时序问题的过程...程序中外设使能顺序改来改去,前4个坏点总是存在

总之,这个问题最后也没有解决,只能通过舍弃来避免。目前只能认为是AD9220数据输出机制的问题。

输出数据

功能:轮询检测PD2连接的按键是否按下,当按下(PD2检测到一次低电平)后,依次输出DMA数据buffer中的内容(注意,程序执行到这里时早就执行过DMA的中断服务程序,buffer数组中的数据已经处理妥当了)。

此功能用来给python画图用。

通过Python实现对串口数据的接收并绘制波形

打开串口,接收缓冲区中的数据,用matplotlib绘图。

import matplotlib.pyplot as plt
import numpy as np
import serial # 注意需要安装 pyserial 而非 serial
import time

portx = "COM4"  # COM2口用来读数
N_sample=4096

x=np.arange(N_sample)

 
# 设置并打开串口
ser = serial.Serial(portx, 115200, timeout=5, parity=serial.PARITY_NONE, stopbits=1)  
ser.flushInput()  # 清空缓冲区
if ser.isOpen():  # 判断串口是否打开
    print("open success")
    while ser.inWaiting() == 0: # 等待数据
        None
    line=ser.readline()
    print(line)
    time.sleep(4.3)
    rx_long_array = ser.readline().decode("utf-8")
    # rx_long_array = ser.read(ser.in_waiting).decode("utf-8")
    print(rx_long_array)
    rx_long_array=rx_long_array.replace('\r', '').replace('\n', '').replace(' ','').replace('\b','')
    array=np.array(list(map(int,rx_long_array[:-1].split(','))))

    fig=plt.figure()
    ax=fig.gca()
    ax.plot(x,array[0:N_sample],'-o',linewidth=0.5,markersize=1.5,color='#1f77b4')
    ax.plot(x,array[N_sample:],'-o',linewidth=0.5,markersize=1.5,color='#ff7f0e')

    plt.show()


ser.close()  

代码实现

  • main.c
    /**
      **************************************************************************
      * @file     main.c
      * @version  v2.1.0
      * @date     2022-08-16
      * @brief    main program
      **************************************************************************
      *                       Copyright notice & Disclaimer
      *
      * The software Board Support Package (BSP) that is made available to
      * download from Artery official website is the copyrighted work of Artery.
      * Artery authorizes customers to use, copy, and distribute the BSP
      * software and its related documentation for the purpose of design and
      * development in conjunction with Artery microcontrollers. Use of the
      * software is governed by this copyright notice and the following disclaimer.
      *
      * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
      * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
      * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
      * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
      * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
      * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
      *
      **************************************************************************
      */
    
    #include "at32f435_437_clock.h"
    
    #include "systick.h"
    #include "usart.h"
    #include "AD9220/AD9220.h"
    
    /**
     * @brief  main function.
     * @param  none
     * @retval none
     */
    
    
    int main(void)
    {
        system_clock_config();
        delay_init();
    
    	// LED init
        gpio_init_type gpio_init_struct;
        crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
        gpio_default_para_init(&gpio_init_struct);
        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
        gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
        gpio_init_struct.gpio_mode           = GPIO_MODE_OUTPUT;
        gpio_init_struct.gpio_pins           = GPIO_PINS_2;
        gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
        gpio_init(GPIOD, &gpio_init_struct);
    
    	// //USART init
        uart_print_init(115200);
        
        printf("UART initialized successfully!\r\n");
    
        // =============================> AD9220 Test <=============================
    
        AD9220_sample_clk_init();
        // tmr_flag_clear(AD9220_TMRx, AD9220_TMR_FLAG);
        AD9220_NO1_init(AD9220_NO1_Pin_LSB_USE_x);
        AD9220_NO2_init(AD9220_NO2_Pin_LSB_USE_x);
        AD9220_sample_start();
        
        while (1)
        {
            print_buffer();
        }
    }

  • AD9220.c
    #include "AD9220.h"
    #include "systick.h"
    #include "stdio.h"
    
    
    uint16_t AD9220_NO1_buffer[AD9220_BUFFER_SIZE];// 注意,前4个值需要舍弃
    uint16_t AD9220_NO2_buffer[AD9220_BUFFER_SIZE];// 注意,前4个值需要舍弃
    
    /**
      * @brief  初始化GPIO引脚。目前只包含12个数据引脚和1个时钟引脚。注意,12个数据引脚必须来自同一个GPIO端口,并且是相邻且有序的。
      * @param  Pin_LSB_num : 指定AD9220的LSB连接第几号(从0计数)引脚。然后程序将初始化从该引脚Pin_LSB_num开始到(Pin_LSB_num+11)号的共12个数据引脚
      * @retval none
      */
    void AD9220_NO1_init(uint8_t Pin_LSB_num)
    {
        crm_periph_clock_enable(AD9220_NO1_DATA_GPIO_CRM_CLK, TRUE);
    
        gpio_init_type gpio_init_struct;
        gpio_default_para_init(&gpio_init_struct);
    
        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
        gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
        gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
        gpio_init_struct.gpio_pins = 0x0FFF<<Pin_LSB_num;
        gpio_init_struct.gpio_pull = GPIO_PULL_UP;
        gpio_init(AD9220_NO1_DATA_GPIOx, &gpio_init_struct);
    
    
        crm_periph_clock_enable(AD9220_NO1_DMAx_CRM_CLK, TRUE);
    
        dma_init_type dma_init_struct;
        dma_default_para_init(&dma_init_struct);
        
        dma_reset(AD9220_NO1_DMAx_Cn);
        dma_init_struct.buffer_size = AD9220_BUFFER_SIZE;
        dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
        dma_init_struct.memory_base_addr = (uint32_t)AD9220_NO1_buffer;
        dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
        dma_init_struct.memory_inc_enable = TRUE;
        dma_init_struct.peripheral_base_addr = (uint32_t)&AD9220_NO1_DATA_GPIOx->idt;
        dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
        dma_init_struct.peripheral_inc_enable = FALSE;
        dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
        dma_init_struct.loop_mode_enable = FALSE;
        dma_init(AD9220_NO1_DMAx_Cn, &dma_init_struct);
    
        // 一轮采样完成后产生中断
        dma_interrupt_enable(AD9220_NO1_DMAx_Cn, DMA_FDT_INT, TRUE);
        /* DMA中断设置 */
        nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
        nvic_irq_enable(AD9220_NO1_DMAx_Cn_IRQn, 1, 0);
    
        // 每当定时器产生通道事件,DMA搬运
        dmamux_init(AD9220_NO1_DMAxMUX_Cn, AD9220_NO1_DMAMUX_DMAREQ_ID);
        /* AD9220_TMRx dmamux function enable */
        dmamux_enable(AD9220_NO1_DMAx, TRUE); 
        /* enable dma channel */
        dma_channel_enable(AD9220_NO1_DMAx_Cn, TRUE);
    }
    
    
    
    void AD9220_NO2_init(uint8_t Pin_LSB_num)
    {
        crm_periph_clock_enable(AD9220_NO2_DATA_GPIO_CRM_CLK, TRUE);
    
        gpio_init_type gpio_init_struct;
        gpio_default_para_init(&gpio_init_struct);
    
        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
        gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
        gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
        gpio_init_struct.gpio_pins = 0x0FFF<<Pin_LSB_num;
        gpio_init_struct.gpio_pull = GPIO_PULL_UP;
        gpio_init(AD9220_NO2_DATA_GPIOx, &gpio_init_struct);
    
    
        crm_periph_clock_enable(AD9220_NO2_DMAx_CRM_CLK, TRUE);
    
        dma_init_type dma_init_struct;
        dma_default_para_init(&dma_init_struct);
        
        dma_reset(AD9220_NO2_DMAx_Cn);
        dma_init_struct.buffer_size = AD9220_BUFFER_SIZE;
        dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
        dma_init_struct.memory_base_addr = (uint32_t)AD9220_NO2_buffer;
        dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_HALFWORD;
        dma_init_struct.memory_inc_enable = TRUE;
        dma_init_struct.peripheral_base_addr = (uint32_t)&AD9220_NO2_DATA_GPIOx->idt;
        dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_HALFWORD;
        dma_init_struct.peripheral_inc_enable = FALSE;
        dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
        dma_init_struct.loop_mode_enable = FALSE;
        dma_init(AD9220_NO2_DMAx_Cn, &dma_init_struct);
    
        // // 一轮采样完成后产生中断
        // dma_interrupt_enable(AD9220_NO2_DMAx_Cn, DMA_FDT_INT, TRUE);
        // /* DMA中断设置 */
        // nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
        // nvic_irq_enable(AD9220_NO2_DMAx_Cn_IRQn, 1, 0); 同步采样,只用第一片的中断就够了
    
        // 每当定时器产生通道事件,DMA搬运
        dmamux_init(AD9220_NO2_DMAxMUX_Cn, AD9220_NO2_DMAMUX_DMAREQ_ID);
        /* AD9220_TMRx dmamux function enable */
        dmamux_enable(AD9220_NO2_DMAx, TRUE); 
        /* enable dma channel */
        dma_channel_enable(AD9220_NO2_DMAx_Cn, TRUE);
    }
    
    
    void AD9220_sample_clk_init(void)
    {
        crm_periph_clock_enable(AD9220_CLK_GPIO_CRM_CLK, TRUE);
    
        gpio_init_type gpio_init_struct;
        gpio_default_para_init(&gpio_init_struct);
        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
        gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
        gpio_init_struct.gpio_pins = AD9220_Pin_CLK;
        gpio_init(AD9220_CLK_GPIOx, &gpio_init_struct);
    
        gpio_pin_mux_config(AD9220_CLK_GPIOx, AD9220_Pin_CLK_SOURCE, AD9220_Pin_CLK_MUX_NUM);
    
        crm_periph_clock_enable(AD9220_TMRx_CRM_CLK, TRUE);
        /* 根据apb1频率计算出定时器计数周期,使PWM频率为10MHz作为ADC时钟 */
        // crm_clocks_freq_type crm_clocks_freq_struct = {0};
        // crm_clocks_freq_get(&crm_clocks_freq_struct);
        tmr_cnt_dir_set(AD9220_TMRx, TMR_COUNT_UP);
    
        /* channel configuration in output mode */
    	tmr_output_config_type  tmr_output_struct;
        tmr_output_default_para_init(&tmr_output_struct);
        tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
        tmr_output_struct.oc_output_state = TRUE;// 开启通道输出
        tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
        tmr_output_struct.oc_idle_state = 0;
        tmr_output_channel_config(AD9220_TMRx, AD9220_TMR_SELECT_CH_n, &tmr_output_struct);
    
        /* enable tmr ch dma request */
        tmr_dma_request_enable(AD9220_TMRx, AD9220_TMR_DMA_REQUET, TRUE);
    
    	// tmr_interrupt_enable(AD9220_TMRx, AD9220_TMR_INT, TRUE); 通道不需要产生中断,DMA会自动识别请求
    
        /* enable AD9220_TMRx */
        tmr_counter_enable(AD9220_TMRx, TRUE);
    
        tmr_channel_enable(AD9220_TMRx, AD9220_TMR_SELECT_CH_n, TRUE);
    }
    
    /**
     * @brief  开启AD9220时钟开始(同步)采样。此后的 N_sample / 10MHz 的时间内,由定时器产生DMA请求将GPIO上的数据搬运到缓冲区。
     * @param  none
     * @retval none
     */
    void AD9220_sample_start(void)
    {
        // 由于主频设置为280MHz,APB为140MHz,直接14分频即可
        AD9220_TMRx->pr=28-1;
    	// 占空比接近55%
        tmr_channel_value_set(AD9220_TMRx, AD9220_TMR_SELECT_CH_n, 15);
    }
    
    
    void print_buffer(void)
    {
    	gpio_init_type gpio_init_struct;
        gpio_default_para_init(&gpio_init_struct);
        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
        gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
        gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;
        gpio_init_struct.gpio_pins           = GPIO_PINS_2;
        gpio_init_struct.gpio_pull           = GPIO_PULL_UP;
        gpio_init(GPIOD, &gpio_init_struct);
    
    	while (gpio_input_data_bit_read(GPIOD,GPIO_PINS_2)==1)
    	{
    		/* code */
    	}
    
    	printf("Buffer AD9220_buffer[%d] content:\n\r",AD9220_BUFFER_SIZE);
    	for(int i =0;i<AD9220_BUFFER_SIZE;i++)
    	{
    		printf("%d,",(AD9220_NO1_buffer[i]>>4));
    	}
    	for(int i =0;i<AD9220_BUFFER_SIZE;i++)
    	{
    		printf("%d,",(AD9220_NO2_buffer[i] & 0x0FFF));
    	}
    	printf("\b \n\r");
    }
    
    /**
     * @brief  一轮采样完成的中断服务程序
     * @param  none
     * @retval none
     */
    void AD9220_NO1_DMAx_Cn_IRQHanlder(void)
    {
    	if(dma_flag_get(AD9220_NO1_DMAx_FDTn_FLAG)==1)
    	{
    		dma_flag_clear(AD9220_NO1_DMAx_FDTn_FLAG);
            // crm_periph_clock_enable(AD9220_DMAx_CRM_CLK, FALSE);
            tmr_counter_enable(AD9220_TMRx, FALSE);
    	}
    }
    
    

  • AD9220.h
    /* Define to prevent recursive inclusion -------------------------------------*/
    #ifndef __AD9220_H
    #define __AD9220_H
    
    #include "at32f435_437.h"
    
    // 连续采样点数
    #define AD9220_N_samples          4096
    // 剔除开始采样时由DMA请求时序问题造成的4个坏点
    #define AD9220_BUFFER_SIZE        AD9220_N_samples + 4
    
    // #define __cplusplus
    
    #ifndef __cplusplus
    /* C */
    
    /* includes ------------------------------------------------------------------*/
    /* typedef ---------------------------------------------------------*/
    
    /* macro ---------------------------------------------------------*/
    #define _LV_CONCAT(x, y)                     x##y
    #define LV_CONCAT(x, y)                      _LV_CONCAT(x, y)
    
    #define _LV_CONCAT3(x, y, z)                 x##y##z
    #define LV_CONCAT3(x, y, z)                  _LV_CONCAT3(x, y, z)
    
    #define _LV_CONCAT4(x, y, z, v)              x##y##z##v
    #define LV_CONCAT4(x, y, z, v)               _LV_CONCAT4(x, y, z, v)
    
    #define _LV_CONCAT5(x, y, z, v, u)           x##y##z##v##u
    #define LV_CONCAT5(x, y, z, v, u)            _LV_CONCAT5(x, y, z, v, u)
    
    #define MAKE_GPIOx(x)                        LV_CONCAT(GPIO, x)
    #define MAKE_TMRx(x)                         LV_CONCAT(TMR, x)
    #define MAKE_DMAx(x)                         LV_CONCAT(DMA, x)
    
    #define MAKE_CRM_GPIOx_PERIPH_CLOCK(x)       LV_CONCAT3(CRM_GPIO, x, _PERIPH_CLOCK)
    #define MAKE_CRM_TMRx_PERIPH_CLOCK(x)        LV_CONCAT3(CRM_TMR, x, _PERIPH_CLOCK)
    #define MAKE_CRM_DMAx_PERIPH_CLOCK(x)        LV_CONCAT3(CRM_DMA, x, _PERIPH_CLOCK)
    
    #define MAKE_GPIO_PINS_x(x)                  LV_CONCAT(GPIO_PINS_, x)
    #define MAKE_GPIO_PINS_SOURCEx(x)           LV_CONCAT(GPIO_PINS_SOURCE, x)
    #define MAKE_GPIO_MUX_x(x)                   LV_CONCAT(GPIO_MUX_, x)
    
    #define MAKE_TMR_SELECT_CHANNEL_n(n)         LV_CONCAT(TMR_SELECT_CHANNEL_, n)
    #define MAKE_TMR_Cn_INT(n)                   LV_CONCAT3(TMR_C, n, _INT)
    #define MAKE_TMR_Cn_FLAG(n)                  LV_CONCAT3(TMR_C, n, _FLAG)
    #define MAKE_TMR_Cn_DMA_REQUEST(n)           LV_CONCAT3(TMR_C, n, _DMA_REQUEST)
    
    #define MAKE_DMAx_CHANNELn(x, n)             LV_CONCAT4(DMA, x, _CHANNEL, n)
    #define MAKE_DMAx_CHANNELn_IRQn(x, n)        LV_CONCAT5(DMA, x, _Channel, n, _IRQn)
    #define MAKE_DMAx_CHANNELn_IRQHandler(x, n)  LV_CONCAT5(DMA, x, _Channel, n, _IRQHandler)
    #define MAKE_DMAx_FDTn_FLAG(x, n)            LV_CONCAT5(DMA, x, _FDT, n, _FLAG)
    #define MAKE_DMAxMUX_CHANNELn(x, n)          LV_CONCAT4(DMA, x, MUX_CHANNEL, n)
    #define MAKE_DMAMUX_DMAREQ_ID_TMRx_CHn(x, n) LV_CONCAT4(DMAMUX_DMAREQ_ID_TMR, x, _CH, n)
    
    
    // =========================> 第1片 AD9220 <=========================
    
    #define AD9220_NO1_DATA_GPIO_USE_x   B
    #define AD9220_NO1_Pin_LSB_USE_x     4
    
    #define AD9220_NO1_DMA_USE_x          1
    #define AD9220_NO1_DMAx_CHANNEL_USE_n 1
    
    // =========================> 第2片 AD9220 <=========================
    
    #define AD9220_NO2_DATA_GPIO_USE_x   C
    #define AD9220_NO2_Pin_LSB_USE_x     0
    
    #define AD9220_NO2_DMA_USE_x          1
    #define AD9220_NO2_DMAx_CHANNEL_USE_n 2
    
    // ==========================> AD9220 CLK TMR <==========================
    
    #define AD9220_CLK_GPIO_USE_x    B
    #define AD9220_Pin_CLK_USE_x     0
    #define AD9220_Pin_CLK_MUX_USE_x 2
    
    #define AD9220_TMR_USE_x         3
    #define AD9220_TMR_CHANNEL_USE_n 3
    // ======================================================================
    
    
    
    // 第一片AD9220驱动的GPIO,DMA 相关宏自动定义
    // GPIO
    #define AD9220_NO1_DATA_GPIOx        MAKE_GPIOx(AD9220_NO1_DATA_GPIO_USE_x)
    #define AD9220_NO1_DATA_GPIO_CRM_CLK MAKE_CRM_GPIOx_PERIPH_CLOCK(AD9220_NO1_DATA_GPIO_USE_x)
    // DMA
    #define AD9220_NO1_DMAx         MAKE_DMAx(AD9220_NO1_DMA_USE_x)
    #define AD9220_NO1_DMAx_CRM_CLK MAKE_CRM_DMAx_PERIPH_CLOCK(AD9220_NO1_DMA_USE_x)
    // DMA 通道
    #define AD9220_NO1_DMAx_Cn MAKE_DMAx_CHANNELn(AD9220_NO1_DMA_USE_x, AD9220_NO1_DMAx_CHANNEL_USE_n)
    // DMA 通道中断
    #define AD9220_NO1_DMAx_Cn_IRQn       MAKE_DMAx_CHANNELn_IRQn(AD9220_NO1_DMA_USE_x, AD9220_NO1_DMAx_CHANNEL_USE_n)
    #define AD9220_NO1_DMAx_Cn_IRQHanlder MAKE_DMAx_CHANNELn_IRQHandler(AD9220_NO1_DMA_USE_x, AD9220_NO1_DMAx_CHANNEL_USE_n)
    #define AD9220_NO1_DMAx_FDTn_FLAG     MAKE_DMAx_FDTn_FLAG(AD9220_NO1_DMA_USE_x, AD9220_NO1_DMAx_CHANNEL_USE_n)
    // DMA 通道 MUX 源
    #define AD9220_NO1_DMAxMUX_Cn       MAKE_DMAxMUX_CHANNELn(AD9220_NO1_DMA_USE_x, AD9220_NO1_DMAx_CHANNEL_USE_n)
    #define AD9220_NO1_DMAMUX_DMAREQ_ID MAKE_DMAMUX_DMAREQ_ID_TMRx_CHn(AD9220_TMR_USE_x, AD9220_TMR_CHANNEL_USE_n)
    
    
    // 第二片AD9220驱动的GPIO,DMA 相关宏自动定义
    // GPIO
    #define AD9220_NO2_DATA_GPIOx        MAKE_GPIOx(AD9220_NO2_DATA_GPIO_USE_x)
    #define AD9220_NO2_DATA_GPIO_CRM_CLK MAKE_CRM_GPIOx_PERIPH_CLOCK(AD9220_NO2_DATA_GPIO_USE_x)
    // DMA
    #define AD9220_NO2_DMAx         MAKE_DMAx(AD9220_NO2_DMA_USE_x)
    #define AD9220_NO2_DMAx_CRM_CLK MAKE_CRM_DMAx_PERIPH_CLOCK(AD9220_NO2_DMA_USE_x)
    // DMA 通道
    #define AD9220_NO2_DMAx_Cn MAKE_DMAx_CHANNELn(AD9220_NO2_DMA_USE_x, AD9220_NO2_DMAx_CHANNEL_USE_n)
    // DMA 通道中断
    #define AD9220_NO2_DMAx_Cn_IRQn       MAKE_DMAx_CHANNELn_IRQn(AD9220_NO2_DMA_USE_x, AD9220_NO2_DMAx_CHANNEL_USE_n)
    #define AD9220_NO2_DMAx_Cn_IRQHanlder MAKE_DMAx_CHANNELn_IRQHandler(AD9220_NO2_DMA_USE_x, AD9220_NO2_DMAx_CHANNEL_USE_n)
    #define AD9220_NO2_DMAx_FDTn_FLAG     MAKE_DMAx_FDTn_FLAG(AD9220_NO2_DMA_USE_x, AD9220_NO2_DMAx_CHANNEL_USE_n)
    // DMA 通道 MUX 源
    #define AD9220_NO2_DMAxMUX_Cn       MAKE_DMAxMUX_CHANNELn(AD9220_NO2_DMA_USE_x, AD9220_NO2_DMAx_CHANNEL_USE_n)
    #define AD9220_NO2_DMAMUX_DMAREQ_ID MAKE_DMAMUX_DMAREQ_ID_TMRx_CHn(AD9220_TMR_USE_x, AD9220_TMR_CHANNEL_USE_n)
    
    // ADC驱动时钟的宏定义
    // CLK pin GPIO
    #define AD9220_CLK_GPIOx         MAKE_GPIOx(AD9220_CLK_GPIO_USE_x)
    #define AD9220_CLK_GPIO_CRM_CLK  MAKE_CRM_GPIOx_PERIPH_CLOCK(AD9220_CLK_GPIO_USE_x)
    // CLK pin
    #define AD9220_Pin_CLK           MAKE_GPIO_PINS_x(AD9220_Pin_CLK_USE_x)
    #define AD9220_Pin_CLK_SOURCE    MAKE_GPIO_PINS_SOURCEx(AD9220_Pin_CLK_USE_x)
    #define AD9220_Pin_CLK_MUX_NUM   MAKE_GPIO_MUX_x(AD9220_Pin_CLK_MUX_USE_x) // TMR3 C3 MUX2
    // TMR
    #define AD9220_TMRx_CRM_CLK    MAKE_CRM_TMRx_PERIPH_CLOCK(AD9220_TMR_USE_x)
    #define AD9220_TMRx            MAKE_TMRx(AD9220_TMR_USE_x)
    // TMR 通道
    #define AD9220_TMR_SELECT_CH_n MAKE_TMR_SELECT_CHANNEL_n(AD9220_TMR_CHANNEL_USE_n)
    #define AD9220_TMR_INT         MAKE_TMR_Cn_INT(AD9220_TMR_CHANNEL_USE_n)
    #define AD9220_TMR_FLAG        MAKE_TMR_Cn_FLAG(AD9220_TMR_CHANNEL_USE_n)
    #define AD9220_TMR_DMA_REQUET  MAKE_TMR_Cn_DMA_REQUEST(AD9220_TMR_CHANNEL_USE_n)
    
    /* function ------------------------------------------------------------------*/
    void AD9220_NO1_init(uint8_t Pin_LSB_num);
    void AD9220_NO2_init(uint8_t Pin_LSB_num);
    void AD9220_sample_clk_init(void);
    void AD9220_sample_start(void);
    
    void print_buffer(void);
    
    
    #else // use C++
    
    typedef struct {
        gpio_type *data_gpio_port;
        uint16_t data_pin_LSB;
        gpio_type *clk_gpio_port;
        uint16_t clk_pin;
        gpio_mux_sel_type clk_pin_mux_num;
    } AD9220_io_port_t;
    
    typedef struct {
        tmr_type *tmr
            uint32_t tmr_periph_clk;
    
    } AD9220_trm_t;
    
    typedef struct {
        dma_type *dma;
        uint32_t dma_periph_clk;
        gpio_mux_sel_type clk_pin_mux_num;
    } AD9220_DMA_t;
    
    class AD9220_t : public Key
    {
    public:
        AD9220_t(AD9220_io_port_t data_port, AD9220_tmr_t clk, uint16_t clk_pin, ) private:
    }
    
    #endif // use C
    
    #endif

实现效果

 两路AD9220对同一个1MHz 2.8Vpp正弦波同步采样的结果,前4个值应舍弃

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值