前言
有个小项目需要用到两片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个值应舍弃