前言

本实验是高速AD/DA验证实验,将使用高速DA芯片实现数模转换,产生正弦波模拟电压信号,并通过高速AD芯片将模拟信号转换成数字信号。本实验用到的硬件是黑金AX7020开发板和与其配套的ADDA模块——AN108。


一、ADDA模块介绍

本实验中使用的ADDA模块型号为AN108,该模块如下图所示。
在这里插入图片描述
其中,ADC的最大采样率为32MHz,精度为8位,DAC的最大采样率为125MHz,精度也为8位。
该ADDA模块不管是AD IN口还是DA OUT口都是通过BNC接口与外界连接的。
AN108的硬件结构图如下图所示。
在这里插入图片描述
DA电路由高速DA芯片AD9708、7阶巴特沃斯低通滤波器、幅度调节电路和信号输出接口组成。高速DA芯片AD9708是8位,125MSPS的DA转换芯片,内置1.2V参考电压,差分电流输出。AD9708芯片差分输出以后,为了防止噪声干扰,电路中接入了7阶巴特沃斯低通滤波器,其带宽为40MHz。在滤波器之后,连接了2片高性能的145MHz带宽的运放AD8056,以实现差分变单端、幅度调节等功能,从而使得整个电路性能得到最大限度的提升,幅度调节使用的是5K的电位器,因此最终的输出范围是-5V—5V,即10Vpp。
需要注意的是,由于电路器的精度不是很精确,最终的输出有一定误差,有可能波形幅度不能达到10Vpp,也有可能出现波形削顶等问题,这些都属正常情况。
AD电路由高速AD芯片AD9280、衰减电路和信号输入接口组成。高速DA芯片AD9280是8位,32MSPS的AD转换芯片。在信号进入芯片AD9280之前,使用一片AD8056芯片构建衰减电路,接口的输入范围是-5V至5V,通过衰减电路以后,输入范围满足AD芯片的输入范围,即0~2V,相应的转换公式如下。
在这里插入图片描述
黑金7020开发板与ADDA模块的连接如下图所示,开发板排针的1脚2脚和39脚40脚都在开发板上标出来了,ADDA模块的1脚2脚也在ADDA模块上标注出来了,由于AN108是34脚,而开发板的排针是40脚,因此要注意不要插反,先将ADDA模块的1脚2脚和开发板的1脚2脚口对齐,再依次从上至下插入即可。
请添加图片描述


二、添加ROM IP核

这部分的细节可以参考博文:ZYNQ之FPGA 片内ROM读写测试实验
首先创建一个名为adda_test的工程,新工程汇总的界面如下图所示,点击Finish即可完成创建。
在这里插入图片描述
在本次实验中,将正弦波的波形数据存储在ROM中,这是因为实验中并不需要写数据(如果需要,就要用RAM),然后通过读取ROM中的数据,继而发送给DA转换芯片即可。
首先打开波形数据生成器,选择数据长度为256,数据位宽为8,选择正弦波生成,然后点击保存。
在这里插入图片描述
将该文件最好保存在工程目录下,选择保存的格式为.coe。
如果没有波形数据生成器,可以点此下载
接着来创建ROM IP核,将其命名为rom_256x8b,各栏目的设置如下图所示。
Basic栏目设置。
在这里插入图片描述
Port A Options栏目设置。
在这里插入图片描述
Other Options栏目下,选择加载初始文件,就是上面保存的.coe文件。
在这里插入图片描述


三、添加ILA IP核

ILA下各栏目的设置如下图所示。
这里设置两个探针,分别用来监测ad的数据和da的数据。
在这里插入图片描述
探针位数的设置如下图所示。
在这里插入图片描述


四、编写测试程序

新建名为adda_test的Verilog文件,依次按照下图中标注的序号进行即可。
在这里插入图片描述
在新建好的adda_test.v文件中写入如下代码。

//本代码来自正点原子
`timescale 1ns / 1ps

module adda_test(
    input                 sys_clk     ,  //系统时钟
    input                 sys_rst_n   ,  //系统复位,低电平有效
    //DA芯片接口
    output                da_clk      ,  //DA(AD9708)驱动时钟,最大支持125Mhz时钟
    output    [7:0]       da_data     ,  //输出给DA的数据
    //AD芯片接口
    input     [7:0]       ad_data     ,  //AD输入数据
    //模拟输入电压超出量程标志(本次试验未用到)
    //input                 ad_otr      ,  //0:在量程范围 1:超出量程
    output                ad_clk         //AD(AD9280)驱动时钟,最大支持32Mhz时钟 
);

//wire define 
wire      [7:0]    rd_addr;              //ROM读地址
wire      [7:0]    rd_data;              //ROM读出的数据

//DA数据发送
da_wave_send u_da_wave_send(
    .clk         (sys_clk), 
    .rst_n       (sys_rst_n),
    .rd_data     (rd_data),
    .rd_addr     (rd_addr),
    .da_clk      (da_clk),  
    .da_data     (da_data)
    );

//ROM存储波形
rom_256x8b  u_rom_256x8b (
  .clka  (sys_clk),    // input wire clka
  .addra (rd_addr),    // input wire [7 : 0] addra
  .douta (rd_data)     // output wire [7 : 0] douta
);

//AD数据接收
ad_wave_rec u_ad_wave_rec(
    .clk         (sys_clk),
    .rst_n       (sys_rst_n),
    .ad_data     (ad_data),
   // .ad_otr      (ad_otr),
    .ad_clk      (ad_clk)
    );    

//ILA采集AD数据
ila_0  ila_0 (
    .clk         (ad_clk ), // input wire clk
	.probe0      (da_data), // input wire [7:0]  probe0  
    .probe1      (ad_data)  // input wire [7:0]  probe0  
);
endmodule

同样的方法新建名为da_wave_send.v的文件并写入如下代码。

//本代码来自正点原子
module da_wave_send(
    input                 clk    ,  //时钟
    input                 rst_n  ,  //复位信号,低电平有效    
    input        [7:0]    rd_data,  //ROM读出的数据
    output  reg  [7:0]    rd_addr,  //读ROM地址
    //DA芯片接口
    output                da_clk ,  //DA(AD9708)驱动时钟,最大支持125Mhz时钟
    output       [7:0]    da_data   //输出给DA的数据  
    );

//parameter 频率调节控制
parameter  FREQ_ADJ = 8'd5;  //频率调节,FREQ_ADJ的值越大,最终输出的频率越低,范围0~255

//reg define
reg    [7:0]    freq_cnt  ;  //频率调节计数器

//数据rd_data是在clk的上升沿更新的,所以DA芯片在clk的下降沿锁存数据是稳定的时刻
//而DA实际上在da_clk的上升沿锁存数据,所以时钟取反,这样clk的下降沿相当于da_clk的上升沿
assign  da_clk = ~clk;       
assign  da_data = rd_data;   //将读到的ROM数据赋值给DA数据端口

//频率调节计数器
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        freq_cnt <= 8'd0;
    else if(freq_cnt == FREQ_ADJ)    
        freq_cnt <= 8'd0;
    else         
        freq_cnt <= freq_cnt + 8'd1;
end

//读ROM地址
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        rd_addr <= 8'd0;
    else begin
        if(freq_cnt == FREQ_ADJ) begin
            rd_addr <= rd_addr + 8'd1;
        end    
    end            
end

endmodule

再新建名为ad_wave_rec.v的文件并写入如下代码。

//本代码来自正点原子
module ad_wave_rec(
    input                 clk         ,  //时钟
    input                 rst_n       ,  //复位信号,低电平有效
    
    input         [7:0]   ad_data     ,  //AD输入数据
    //模拟输入电压超出量程标志(本次试验未用到)
    input                 ad_otr      ,  //0:在量程范围 1:超出量程
    output   reg          ad_clk         //AD(AD9280)驱动时钟,最大支持32Mhz时钟
);

//时钟分频(2分频,时钟频率为25Mhz),产生AD时钟
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        ad_clk <= 1'b0;
    else 
        ad_clk <= ~ad_clk; 
end    

endmodule

到这里,本实验的测试代码就添加完成了。
一开始打算使用PLL来输出ad和da的时钟,但是在程序中应用时出错了,报错信息如下。

INFO: [Labtools 27-1434] Device xc7z020 (JTAG device index = 1) is programmed with a design that has no supported debug core(s) in it.
WARNING: [Labtools 27-3361] The debug hub core was not detected.
Resolution:

  1. Make sure the clock connected to the debug hub (dbg_hub) core is a free running clock and is active.
  2. Make sure the BSCAN_SWITCH_USER_MASK device property in Vivado Hardware Manager reflects the user scan chain setting in the design and refresh the device. To determine the user scan chain setting in the design, open the implemented design and use ‘get_property C_USER_SCAN_CHAIN [get_debug_cores dbg_hub]’.
    For more details on setting the scan chain property, consult the Vivado Debug and Programming User Guide (UG908).
    WARNING: [Labtools 27-3413] Dropping logic core with cellname:‘ila_0’ at location ‘uuid_D7F66BBC62045AEA8C9B20B797086963’ from probes file, since it cannot be found on the programmed device.

出现这个问题的原因是在ILA中使用了通过PLL生成的时钟。
所以就添加了另外两个模块da_wave_send和ad_wave_rec,这两个模块中主要还是对时钟的设置。da_wave_send中将时钟进行了翻转,同时设置读ROM的地址;ad_wave_rec中将系统时钟进行二分频,得到25MHz时钟,即ad_clk。


五、管脚分配

ADDA模块——AN108的34针排布的原理图如下。
在这里插入图片描述
黑金开发板的J11扩展口原理图如下。
在这里插入图片描述
其中,J11扩展口所对应的引脚号如下表所示。

J11管脚信号名称ZYNQ引脚名ZYNQ引脚号
PIN1GND--
PIN2+5V--
PIN3EX_IO2_1NIO_L6N_T0_35F17
PIN4EX_IO2_1PIO_L6P_T0_35F16
PIN5EX_IO2_2NIO_L15N_T2_35F20
PIN6EX_IO2_2PIO_L15P_T2_35F19
PIN7EX_IO2_3NIO_L18N_T2_35G20
PIN8EX_IO2_3PIO_L18P_T2_35G19
PIN9EX_IO2_4NIO_L14N_T2_35H18
PIN10EX_IO2_4PIO_L14P_T2_35J18
PIN11EX_IO2_5NIO_L9N_T1_35L20
PIN12EX_IO2_5PIO_L9P_T1_35L19
PIN13EX_IO2_6NIO_L7N_T1_35M20
PIN14EX_IO2_6PIO_L7P_T1_35M19
PIN15EX_IO2_7NIO_L12N_T1_35K18
PIN16EX_IO2_7PIO_L12P_T1_35K17
PIN17EX_IO2_8NIO_L10N_T1_35J19
PIN18EX_IO2_8PIO_L10P_T1_35K19
PIN19EX_IO2_9NIO_L17N_T2_35H20
PIN20EX_IO2_9PIO_L17P_T2_35J20
PIN21EX_IO2_10NIO_L11N_T1_35L17
PIN22EX_IO2_10PIO_L11P_T1_35L16
PIN23EX_IO2_11NIO_L8N_T1_35M18
PIN24EX_IO2_11PIO_L8P_T1_35M17
PIN25EX_IO2_12NIO_L4N_T0_35D20
PIN26EX_IO2_12PIO_L4P_T0_35D19
PIN27EX_IO2_13NIO_L5N_T0_35E19
PIN28EX_IO2_13PIO_L5P_T0_35E18
PIN29EX_IO2_14NIO_L16N_T2_35G18
PIN30EX_IO2_14PIO_L16P_T2_35G17
PIN31EX_IO2_15NIO_L13N_T2_35H17
PIN32EX_IO2_15PIO_L13P_T2_35H16
PIN33EX_IO2_16NIO_L19N_T3_35G15
PIN34EX_IO2_16PIO_L19P_T3_35H15
PIN35EX_IO2_17NIO_L20N_T3_35J14
PIN36EX_IO2_17PIO_L20P_T3_35K14
PIN37GND--
PIN38GND--
PIN39+3.3V--
PIN40+3.3V--

具体的引脚分配见下表。

名称引脚号
sys_clkU18
da_clkF20
da_0M20
da_1L19
da_2L20
da_3J18
da_4H18
da_5G19
da_6G20
da_7F19
ad_clkG18
ad_0L17
ad_1L16
ad_2M18
ad_3M17
ad_4D20
ad_5D19
ad_6E19
ad_7E18

根据上面表中的对应关系,打开管脚配置页面依次设置即可。
在这里插入图片描述


六、连接开发板测试

连接开发板,点击Generate Bitstream生成比特流文件,将其下载到开发板上,在ILA窗口运行后得到如下图所示的正弦波。
在这里插入图片描述
由上图可以看到,输入的ad_data数据是正弦波的波形,说明该实验验证成功了。
如果设置的ILA采样深度太小,得到的波形就是这样的。
在这里插入图片描述
所以在ILA中设置采样深度时要设置合理,设置的太大,需要耗费的资源也越多。
在这里插入图片描述
按理说这里的数模转换波形需要用示波器测量,具体的测量方法是将示波器带夹子的一端连接开发板的GND端(开发板上任意的GND均可),然后将示波器另一端探针接到DA通道上,这里由于条件限制就利用ILA代替了示波器,其输出也是正弦波。


总结

以上就是ZYNQ之高速AD/DA验证实验的所有内容了,该实验与ROM读写测试实验有一定的相似之处,同时也是在其基础上进行更复杂的实验,本实验需要注意的是ADDA模块在插入开发板时不要插反,同时在管脚分配时也要注意不要出错。
本文参考资料:
正点原子–course_s1_ZYNQ那些事儿-FPGA实验篇V1.06.pdf
ALINX黑金AX7020开发板用户手册V2.2.pdf
领航者ZYNQ之FPGA开发指南_V2.0 .pdf

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐