FPGA实验二:ADDA测试

基于实验一DDS IP 数字波形合成设计完成ADDA测试,关于实验一可参考上一篇文章DDS的理解及IP核的使用_Laid-back guy的博客

实验内容参考Zynq FPGA实验_DUWT实验的博客

目录

实验内容:

ADDA模块

程序设计

​Matlab分析验证 

问题总结

参考资料

实验内容:

  1. 注意,AN108是34针的插头,注意其插装位置,1脚和zynq底板对齐,不要插错
  2. 黑金AN108的低通滤波器通带为0-20MHz左右
  3. 基于“DDS IP 数字波形合成DAC ” 实验方案,使用50MHz时钟频率,使用DAC输出正弦波。
  4. 把DAC输出模拟信号自环给ADC的输入
  5. 使用MMCM分频,给ADC提供25MHz采样时钟
  6. 使用ILA捕获ADC的输出数据,不少于2048样点。
  7. 使用Matlab分析ADC数据频谱
  8. 用VIO更改频率字,生成1MHz和3MHz的正弦信号,用Matlab分析ILA数据验证频谱正确。

ADDA模块

ADDA,包含ADC与DAC(Analog to Digital Converter/ Digital to Analog Converter,即模数转换器/数模转换器),能实现模拟到数字再到模拟信号的转换过程。

本实验采用的是ALINX的AN108,包含一块高速DA转换芯片AD9708,转换位数为8位,最大转换速度为125MSPS以及一块高速AD转换芯片,转换位数为8位,最大转换速度为32MSPS

AN108的实物图及结构图如下

其中7阶巴特沃斯低通滤波器的带宽为40Mhz,幅度调节的输出范围为-5~5V(10Vpp) ,其中实物图中右侧黑色旋钮为滑动变阻器节输出的电压范围,推荐通过调节滑动变阻器,使输出的电压范围在-5V至+5V之间

衰减电路的转换公式为V_{AD}=\frac{1}{5}V_{IN}+1,将-5~5V的输入电压转换为0~2V的输出电压送入高速AD芯片

程序设计

根据实验二的要求,利用实验一设计的DDS模块输出1Mhz/3Mhz正弦波并将其送入DAC进行DA转换得模拟信号,将模拟信号自环给ADC进行AD转换得到该程序输出的数字信号。

根据上述要求,可以设计出如下ADDA测试的系统框图

顶层模块的RTL图如下

 

 代码如下:

`timescale 1ns / 1ps
module adda_test(
    input   sys_clk,
    input   rst_n,
    //DA芯片接口
    output                da_clk,  //DA(AD9708)驱动时钟,最大支持125Mhz时钟
    output    [7:0]       da_data,  //输出给DA的数据
    //AD芯片接口
    //input                 ad_otr      ,  //0:在量程范围 1:超出量程
    input     [7:0]       ad_data,  //AD输入数据
    output                ad_clk         //AD(AD9280)驱动时钟,最大支持32Mhz时钟 
    );
// -----------0、时钟控制模块-----------// 
//PLL IP核例化
wire    clk_out1;
wire    clk_out2;
clk_wiz_0  clk_wiz_0_inst(
    // Clock out ports
    .clk_out1(clk_out1),     // 给DAC提供50MHz采样时钟
    .clk_out2(clk_out2),     // 给ADC提供25MHz采样时钟
    // Status and control signals
    .reset(~rst_n), // input reset
   // Clock in ports
    .clk_in1(sys_clk));      // input clk_in1    
// -----------1、DDS模块-----------// 
wire    [1:0]   key_PINC;
vio_0 vio_0_inst (
  .clk(sys_clk),                // input wire clk
  .probe_out0(key_PINC)  // output wire [1 : 0] probe_out0
);

wire    [15:0]  Fword;
Fword_set   Fword_set_inst(
     .clk       (sys_clk),
     .rst_n     (rst_n),
     .key_PINC  (key_PINC),
     .Fword     (Fword)
);
//DDS IP核例化
wire [0:0]   fre_ctrl_word_en  ;    
//output
wire [0:0]   m_axis_data_tvalid    ;
wire [7:0]  m_axis_data_tdata     ;
wire [0:0]   m_axis_phase_tvalid   ;
wire [15:0]  m_axis_phase_tdata    ;

assign fre_ctrl_word_en=1'b1;

dds_compiler_0 dds_compiler_0_inst (
  .aclk(clk_out1),                                  // input wire aclk
  .s_axis_config_tvalid(fre_ctrl_word_en),  // input wire s_axis_config_tvalid
  .s_axis_config_tdata(Fword),    // input wire [15 : 0] s_axis_config_tdata
  .m_axis_data_tvalid(m_axis_data_tvalid),      // output wire m_axis_data_tvalid
  .m_axis_data_tdata(m_axis_data_tdata),        // output wire [7 : 0] m_axis_data_tdata
  .m_axis_phase_tvalid(m_axis_phase_tvalid),    // output wire m_axis_phase_tvalid
  .m_axis_phase_tdata(m_axis_phase_tdata)      // output wire [15 : 0] m_axis_phase_tdata
);

// -----------2、AD9708-----------// 
AD9708 AD9708_inst(
    .clk         (clk_out1), 
    .rst_n       (rst_n),
    .data_in     (m_axis_data_tdata),
    .da_clk      (da_clk),  
    .da_data     (da_data)
    );
// -----------3、AD9708-----------// 
AD9280 AD9280_inst(
    .clk         (clk_out2), 
    .rst_n       (rst_n),
    .ad_clk      (ad_clk),  
    .ad_data     (ad_data)
    );

// -----------4、ILA模块---------// 
//ILA IP核例化
ila_0 ila_0_inst (
	.clk(clk_out1), // input wire clk


	.probe0(m_axis_data_tdata), // input wire [7:0]  probe0  
	.probe1(da_data), // input wire [7:0]  probe1
	.probe2(ad_data) // input wire [7:0]  probe2
);

endmodule

顶层模块adda_test对5个模块进行了例化,包括

时钟控制模块,利用MMCM分频,给DDS模块以及DAC提供50MHz采样时钟,给ADC提供25MHz采样时钟。

DDS模块,利用实验一设计的DDS IP 数字波形合成DAC,生成ADDA测试用的正弦波。

AD9708,DA数据发送模块,接受来自DDS模块的数字信号并发送至DA转换芯片的数据端口。

AD9280,AD数据接收模块,输出AD转换芯片的驱动时钟并且接收AD转换完成的数据。

ILA模块,观察送入DA芯片以及AD芯片输出的数字信号

DDS模块中Fword_set代码如下:

`timescale 1ns / 1ps
//通过按键来选择对应的频率控制字,进而选择对应的信号频率
module Fword_set(
     input              clk,
     input              rst_n,
     input  [1:0]       key_PINC,
     output reg  [15:0] Fword
    );

// 根据IP核的summery, phase width=16bits   Frequency per channel=50MHz
// 输出频率的计算公式f_out=f_clk*deta_theta/(2^B)=50M* 3,932/(2^16 )= 3M   
always @(*)begin
    case(key_PINC)
        0:  Fword <= 'h51e;     //1Mhz  1310  每次相位增加的值  deta_theta
        1:  Fword <= 'hf5c;     //3Mhz  3,932
    endcase
end

endmodule

DA数据发送模块AD9708代码如下:

`timescale 1ns / 1ps
module AD9708(
     input                 clk    ,  //时钟
     input                 rst_n  ,  //复位信号,低电平有效
     
     input        [7:0]    data_in,  //DDS读出的数据
     //DA芯片接口
     output                da_clk ,  //DA(AD9708)驱动时钟,最大支持125Mhz时钟
     output       [7:0]    da_data   //输出给DA的数据  
     );
 
 
 //*****************************************************
 //**                    main code
 //*****************************************************
 
 //数据data_in是在clk的上升沿更新的,所以DA芯片在clk的下降沿
 //而DA实际上在da_clk的上升沿锁存数据,所以时钟取反,这样clk的下降沿相当于da_clk的上升沿
assign  da_clk = ~clk;       
assign  da_data = data_in^'h0x80;   //将读到的DDS数据与0x80取异或赋值给DA数据端口
endmodule

AD数据接收模块AD9280的代码如下:

`timescale 1ns / 1ps
module AD9280(
     input                 clk         ,  //时钟
     input                 rst_n       ,  //复位信号,低电平有效
     
     input         [7:0]   ad_data     ,  //AD输入数据
     output                ad_clk         //AD(AD9280)驱动时钟,最大支持32Mhz时钟
     );   
assign ad_clk = ~clk;
endmodule

约束文件:

############## clock and reset define##################
create_clock -period 20 [get_ports sys_clk]
set_property IOSTANDARD LVCMOS33 [get_ports {sys_clk}]
set_property PACKAGE_PIN U18 [get_ports {sys_clk}]

set_property IOSTANDARD LVCMOS33 [get_ports {rst_n}]
set_property PACKAGE_PIN N15 [get_ports {rst_n}]

#################   AN108 ON AX7020   #################
set_property PACKAGE_PIN F20 [get_ports {da_clk}]
set_property PACKAGE_PIN F19  [get_ports {da_data[7]}]
set_property PACKAGE_PIN G20 [get_ports {da_data[6]}]
set_property PACKAGE_PIN G19 [get_ports {da_data[5]}]
set_property PACKAGE_PIN H18 [get_ports {da_data[4]}]
set_property PACKAGE_PIN J18  [get_ports {da_data[3]}]
set_property PACKAGE_PIN L20 [get_ports {da_data[2]}]
set_property PACKAGE_PIN L19 [get_ports {da_data[1]}]
set_property PACKAGE_PIN M20  [get_ports {da_data[0]}]
set_property PACKAGE_PIN L17  [get_ports {ad_data[0]}]
set_property PACKAGE_PIN L16  [get_ports {ad_data[1]}]
set_property PACKAGE_PIN M18  [get_ports {ad_data[2]}]
set_property PACKAGE_PIN M17  [get_ports {ad_data[3]}]
set_property PACKAGE_PIN D20 [get_ports {ad_data[4]}]
set_property PACKAGE_PIN D19 [get_ports {ad_data[5]}]
set_property PACKAGE_PIN E19  [get_ports {ad_data[6]}]
set_property PACKAGE_PIN E18  [get_ports {ad_data[7]}]
set_property PACKAGE_PIN G18  [get_ports {ad_clk}]

set_property IOSTANDARD LVCMOS33 [get_ports {da_clk}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {da_data[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_data[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {ad_clk}]

下载验证

key_PINC=0,1Mhz正弦波

key_PINC=1,3Mhz正弦波

Matlab分析验证 

导出ILA抓取的波形,利用matlab分析验证频率,代码如下:

filename = 'C:\zynq\adda_test\adda_test.srcs\csv\iladata.csv';
M = readmatrix(filename,'Range','E3:E4098');  %读取4096个数据
fs = 50000000;      %采样率
N = length(M);      %采样点数
n = 0:N-1;
t = n/fs;           %时间序列
f = n*fs/N;         %频率序列
Y = fft(M);         %对M进行FFT变换
fshift = (-N/2:N/2-1)*fs/N;
y = fftshift(Y);    %以0为中心循环平移
y_abs = abs(y);
figure;
subplot(2,1,1);
plot(t,M);          %时域波形
title('时域波形');xlabel('时间/s');ylabel('幅值');
subplot(2,1,2);
plot(fshift,y_abs);          %频域波形
title('频域波形');xlabel('频率/s');ylabel('幅值');

 key_PINC=0,iladata.csv

 key_PINC=0,iladata1.csv

 由图可知,ADC的输出波形并不光滑且含其他频率成分,但主频率为1Mhz/3Mhz

可能是由于DA与AD之间的连接并非理想环境

问题总结

由于之前的实验对DDS IP以及AD9708的了解较少,所以导致了输出的波形不理想,有毛刺。

经过查询相关资料得知,DDS IP输出数据为有符号数,而AD9708的输入数据为无符号数,具体如下图所示

所以该实验需要在两个模块之间进行数据转换,由于数据位宽为8bit,具体操作为将DDS输出的数据与十六进制数0x80异或送给DAC模块

assign  da_data = data_in^'h0x80;   //将读到的DDS数据与0x80取异或赋值给DA数据端口

参考资料

[1]黑金ALINX高速ADDA使用指南REV1.3.pdf

[2]【正点原子FPGA连载】 第二十六章 高速AD/DA实验

  • 4
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值