[X]关闭

11 ADC模块FEP-DAQ422X采集显示波形方案

文档创建者:uisrc
浏览次数:295
最后更新:2023-12-27
文档课程分类
AMD: FPGA部分(2024样板资料) » 1_START(适配所有型号) » 4-硬件功能案例
软件版本:VIVADO2021.1
操作系统:WIN10 64bit
硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA
登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!
1概述
本方案通过把DAQ422X采集到的数据,通过前面已经完成的示波器显示驱动进行在屏幕上显示ADC采集的波形数据。
2系统框图
2504661-20231227193105080-1208143047.jpg
3产品介绍
2504661-20231227193105532-1453099574.jpg
FEP-DAQ003- 12- 125M-250M-2数据采集模块采用一颗 TI 的ADS4225/ ADS4229低功耗高性能模数转换芯片,实现了 2 通道125/250MSPS 模数转换,并且支持 2 路数字 IO 输入/输出触发功能。
通过设置不同的通信模式,ADS4225/ADS4229 具有 LVDS DDR 接口模式和 LVCMOS SDR 接口两种模式。
3.1 硬件参数概述
FEP-DAQ003- 12- 125M-2/FEP-DAQ003- 12-250M-2
ADC 芯片
AD4225/4229
采样精度
12bit
-3db 带宽
320M(前置运放带宽决定)
IO 电平
1.8V 或者 3.3V 可选
采样频率
ADS4225 0~125M
ADS4229 0~250M
模拟通道
2 个
触发 IO
2 个
输入电平
-5V~+5V
数据格式
二进制补码(~2048~+2047)
信噪比 170M(SNR)
71.4dBFS
无杂散动态范围 170M(SFDR)
88dBc
功耗 165M
332mW
占用 IO 数量
40 个 GPIO


3.2 引脚定义3.2.1 SMA 引脚定义
引脚号
引脚名称
描述
PA
DAI
模拟输入通道 1
PB
DBI
模拟输入通道 2
TA
TriA
双向触发输入/输出 1
TB
TriB
双向触发输入/输出 2


3.2.2 ADS422X芯片功能引脚定义3.2.2.1 LVDS 下接口定义
2504661-20231227193105944-602993671.jpg
3.2.2.2 LVCMOS 下接口定义
2504661-20231227193106731-152161014.jpg

LVDS 和CMOS 模式的数据输出时序
2504661-20231227193107276-1322174474.jpg
LVDS 的时序要求
2504661-20231227193107669-1176258840.jpg
CMOS 模式的时序要求
2504661-20231227193108017-1613352379.jpg
2504661-20231227193108374-1279797615.jpg
3.3 数据模式设置
设置 SEN 脚的工作电平,来设置 ADS4225/ADS4229 的工作模式

SEN 脚电平
模式
0V
二进制补码和并行 CMOS 输出
0.375AVDD
偏移二进制和并行 CMOS 输出
0.625AVDD
偏移二进制和 DDR LVDS 输出


4硬件电路分析
硬件接口和子卡模块请阅读"附录 1"
配套工程的 FPGA PIN 脚定义路径为 fpga_prj/uisrc/04_pin/ fpga_pin.xdc。
5程序源码
关于HDMI输出IP的部分这里不再介绍,VTC时序设计部分这里也不详细介绍。如果读者这些基础知识不清楚的,请阅读前面的实验。
5.1ADS422X采集驱动
ADS422X 数据采集通过 IDELAY 模块调整数据相对时钟的延迟,用来设置最佳采样时刻。
`timescale 1 ns / 1 ns

module uiads422X_parallel#
(
parameter  FAMILY    = "7SERIES",  
parameter  integer  DATA_WIDTH     = 12,
parameter  integer  DELAY_SETA     = 12,
parameter  integer  DELAY_SETB     = 12
)
(
input       I_refclk,
input       I_reset,

input       I_ad_clk,
input [DATA_WIDTH   -1 :0]I_ad_da,
input [DATA_WIDTH   -1 :0]I_ad_db,
output      [DATA_WIDTH   -1 :0]O_ad_da,
output      [DATA_WIDTH   -1 :0]O_ad_db,
output      O_ad_reset,
output      O_ad_sen,
output      O_ad_sclk,
output      O_ad_card_en
);

wire [DATA_WIDTH   -1:0] da_buf,db_buf,da_buf_delay,db_buf_delay;
wire      idelayctrl_reset_sync;
reg       idelayctrl_reset;
reg [3 :0]idelay_reset_cnt;
reg [15:0] cnt = 0;

assign    O_ad_card_en   = cnt[15];
assign    O_ad_reset = 1'b1;
assign    O_ad_sen   = 1'b0;
assign    O_ad_sclk  = 1'b0;

always @(posedge I_refclk)begin
    if(!cnt[15])
        cnt <= cnt +1'b1;
end

// Create a synchronous reset in the IDELAYCTRL refclk clock domain.
reset_sync idelayctrl_reset_gen
(
.clk              (I_refclk),
.enable           (1'b1),
.reset_in         (I_reset),
.reset_out        (idelayctrl_reset_sync)
);   

// The IDELAYCTRL must experience a pulse which is at least 50 ns in
// duration.  This is ten clock cycles of the 200MHz refclk.  Here we
// drive the reset pulse for 12 clock cycles.
always @(posedge I_refclk)begin
      if (idelayctrl_reset_sync == 1'b0) begin
         idelay_reset_cnt     <= 4'b0000;
         idelayctrl_reset     <= 1'b1;
      end
      else begin
         case (idelay_reset_cnt)
            4'b0000 : idelay_reset_cnt <= 4'b0001;
            4'b0001 : idelay_reset_cnt <= 4'b0010;
            4'b0010 : idelay_reset_cnt <= 4'b0011;
            4'b0011 : idelay_reset_cnt <= 4'b0100;
            4'b0100 : idelay_reset_cnt <= 4'b0101;
            4'b0101 : idelay_reset_cnt <= 4'b0110;
            4'b0110 : idelay_reset_cnt <= 4'b0111;
            4'b0111 : idelay_reset_cnt <= 4'b1000;
            4'b1000 : idelay_reset_cnt <= 4'b1001;
            4'b1001 : idelay_reset_cnt <= 4'b1010;
            4'b1010 : idelay_reset_cnt <= 4'b1011;
            4'b1011 : idelay_reset_cnt <= 4'b1100;
            default : idelay_reset_cnt <= 4'b1100;
         endcase
         if (idelay_reset_cnt == 4'b1100) begin
            idelayctrl_reset  <= 1'b0;
         end
         else begin
            idelayctrl_reset  <= 1'b1;
         end
      end
end

genvar i;
generate
for (i = 0 ; i < DATA_WIDTH ; i = i+1) begin : DAQ_DATA
IBUF #(
.IBUF_LOW_PWR("TRUE"),  // Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
.IOSTANDARD("DEFAULT")  // Specify the input I/O standard
)IBUF_da (
.O(da_buf),     // Buffer output
.I(I_ad_da)      // Buffer input (connect directly to top-level port)
);


IBUF #(
.IBUF_LOW_PWR("TRUE"),  // Low power (TRUE) vs. performance (FALSE) setting for referenced I/O standards
.IOSTANDARD("DEFAULT")  // Specify the input I/O standard
)IBUF_db (
.O(db_buf),     // Buffer output
.I(I_ad_db)      // Buffer input (connect directly to top-level port)
);

end
endgenerate

generate  if(FAMILY == "ULTRASCALE" || FAMILY == "ULTRASCALE_PLUS")begin : ULTRASCALE_FAMILY

IDELAYCTRL  #(
.SIM_DEVICE ("ULTRASCALE")
)
idelayctrl_inst(
.RDY       (idelayctrl_ready),
.REFCLK    (I_refclk),
.RST       (idelayctrl_reset)
);

    genvar k;
     for (k=0; k<DATA_WIDTH ; k=k+1)
    begin : rxdata_in_bus
    IDELAYE3 #(
    .DELAY_VALUE      (DELAY_SETA),
    .DELAY_TYPE       ("FIXED"),
    .REFCLK_FREQUENCY (300.000),
    .SIM_DEVICE       (FAMILY)
    )
    IDELAYE_A (
    .IDATAIN          (da_buf[k]),
    .DATAOUT          (da_buf_delay[k]),
    .DATAIN           (1'b0),
    .CLK              (1'b0),
    .CE               (1'b0),
    .INC              (1'b0),
    .CNTVALUEIN       (9'h0),
    .CNTVALUEOUT      (),
    .LOAD             (1'b0),
    .RST              (1'b0),
    .CASC_IN          (1'b0),
    .CASC_RETURN      (1'b0),
    .CASC_OUT         (),
    .EN_VTC           (1'b1)
    );
    IDELAYE3 #(
    .DELAY_VALUE      (DELAY_SETB),
    .DELAY_TYPE       ("FIXED"),
    .REFCLK_FREQUENCY (300.000),
    .SIM_DEVICE       (FAMILY)  
    )
    IDELAYE_B (
    .IDATAIN          (db_buf[k]),
    .DATAOUT          (db_buf_delay[k]),
    .DATAIN           (1'b0),
    .CLK              (1'b0),
    .CE               (1'b0),
    .INC              (1'b0),
    .CNTVALUEIN       (9'h0),
    .CNTVALUEOUT      (),
    .LOAD             (1'b0),
    .RST              (1'b0),
    .CASC_IN          (1'b0),
    .CASC_RETURN      (1'b0),
    .CASC_OUT         (),
    .EN_VTC           (1'b1)
    );
    end
end
else if(FAMILY == "7SERIES") begin : SERIES7_FAMILY

IDELAYCTRL  #(
.SIM_DEVICE ("7SERIES")
)
idelayctrl_inst(
.RDY       (idelayctrl_ready),
.REFCLK    (I_refclk),
.RST       (idelayctrl_reset)
);

    genvar k;
    for (k=0; k<DATA_WIDTH ; k=k+1)
    begin : rxdata_in_bus
    IDELAYE2 #(
    .HIGH_PERFORMANCE_MODE("TRUE"),
    .IDELAY_TYPE   ("FIXED"),
    .IDELAY_VALUE  (DELAY_SETA)
    )
    IDELAYE_A
    (
    .IDATAIN       (da_buf[k]),
    .DATAOUT       (da_buf_delay[k]),
    .DATAIN        (1'b0),
    .C             (1'b0),
    .CE            (1'b0),
    .INC           (1'b0),
    .CINVCTRL      (1'b0),
    .CNTVALUEIN    (5'h0),
    .CNTVALUEOUT   (),
    .LD            (1'b0),
    .LDPIPEEN      (1'b0),
    .REGRST        (1'b0)
    );

    IDELAYE2 #(
    .HIGH_PERFORMANCE_MODE("TRUE"),
    .IDELAY_TYPE   ("FIXED"),
    .IDELAY_VALUE  (DELAY_SETB)
    )
    IDELAYE_B
    (
    .IDATAIN       (db_buf[k]),
    .DATAOUT       (db_buf_delay[k]),
    .DATAIN        (1'b0),
    .C             (1'b0),
    .CE            (1'b0),
    .INC           (1'b0),
    .CINVCTRL      (1'b0),
    .CNTVALUEIN    (5'h0),
    .CNTVALUEOUT   (),
    .LD            (1'b0),
    .LDPIPEEN      (1'b0),
    .REGRST        (1'b0)
    );
    end
end
endgenerate

assign O_ad_da = da_buf_delay;
assign O_ad_db = db_buf_delay;

endmodule



5.2顶层模块调用程序
以下代码中,需要注意,通过 DELAY_SETA 和 DELAY_SETB 设置最佳的数据延迟。
对于有符号数据,通过设置 I_wave1_data(ads422x_da[11:4]+8'h80),加上 8'h80 让波形数据转为无符号,
在显示器上显示。
对于 ADS4225 修改 PLL 输出 125M 时钟
对于 ADS4229 修改 PLL 输出 250M 时钟

/**********************AD9248 ADC采集波形显示*************************
*********************************************************************/

`timescale 1ns / 1ns//仿真时间刻度/精度

module ads422x_top
(
input           I_sysclk_p,         //系统时钟输入
output          O_ads422x_clk_p,  
output          O_ads422x_clk_n,  
input           I_ads422x_clk,
input  [11 :0]  I_ads422x_da,
input  [11 :0]  I_ads422x_db,
output          O_ads422x_reset,
output          O_ads422x_sen,
output          O_ads422x_sclk,
output          O_card_power_en,    //子卡电源使能

output          O_HDMI_CLK_P,       //HDMI时钟输出 P端
output          O_HDMI_CLK_N,       //HDMI时钟输出 N端
output [2:0]    O_HDMI_TX_P,        //HDMI数据输出 P端
output [2:0]    O_HDMI_TX_N         //HDMI数据输出 N端
);

wire pclkx1,pclkx5,ref_clk,adc_clk,locked; //MMCM/PLL时钟信号  

//ADS422X直流版需要提供差分时钟工作
OBUFDS ADC_DIFF_CLK_O_inst (
.O (O_ads422x_clk_p),     // Diff_p output (connect directly to top-level port)
.OB(O_ads422x_clk_n),     // Diff_n output (connect directly to top-level port)
.I (adc_clk)         // Buffer input
);

//例化MMCM/PLL IP
clk_wiz_1 clk_hdmi_pll_inst
(
.clk_in1 (I_sysclk_p),
.reset   (!rst_cnt[7]),
.locked  (locked),
.clk_out1(ref_clk),
.clk_out2(pclkx1),//像素时钟
.clk_out3(pclkx5),//HDMI输出5倍像素时钟
.clk_out4(adc_clk)//输出给ADC
);

wire  [11 :0]  ads422x_da;
wire  [11 :0]  ads422x_db;

uiads422X_parallel #
(
.FAMILY    ("7SERIES"),
.DATA_WIDTH(12       ),//ADC数据位宽
.DELAY_SETA(25       ),//通道A的delay延迟
.DELAY_SETB(25       ) //通道B的delay延迟
)
uiads422X_parallel_inst
(
.I_refclk  (ref_clk), //IP内部的delay模块参考时钟,7系列200M KU KU+ 300M   
.I_reset   (~locked), //IP内部复位模块
.I_ad_clk  (I_ads422x_clk),//ADC同步时钟
.I_ad_da   (I_ads422x_da), //ADC数据输入通道A
.I_ad_db   (I_ads422x_db), //ADC数据输入通道B
.O_ad_da   (ads422x_da  ), //ADC数据输入数据经过延迟模块后输出,通道A
.O_ad_db   (ads422x_db  ), //ADC数据输入数据经过延迟模块后输出,通道B
.O_ad_reset(O_ads422x_reset), //ADC控制信号
.O_ad_sen  (O_ads422x_sen),    //ADC控制信号,设置ADC的工作模式
.O_ad_sclk (O_ads422x_sclk),  //ADC控制信号,设置ADC的工作模式
.O_ad_card_en(O_card_power_en)//ADC模块的电源使能,当用到电源使能的时候需要用到  
);

wire vtc_rstn,vtc_clk,vtc_vs,vtc_hs,vtc_de,vtc2_de;
wire [23:0] wave_rgb; //RGB颜色寄存器
assign vtc_clk  = pclkx1;//像素时钟
assign vtc_rstn = locked;//VTC复位信号

//上电延迟复位
reg [7:0]    rst_cnt=0; //复位计数器
wire  rstn = rst_cnt[7];//用高位复位

always @(posedge I_sysclk_p)begin
    if (rst_cnt[7])
        rst_cnt <=  rst_cnt;
    else
        rst_cnt <= rst_cnt+1'b1;
end

//例化HDMI 输出IP
uihdmitx #
(
.FAMILY("7FAMILY")  //选择芯片所支持的系列"7FAMILY" "UFAMILY"            
)
uihdmitx_inst
(
.I_rstn         (locked),//复位
.I_HS           (vtc_hs),//hs信号
.I_VS           (vtc_vs),//vs信号
.I_VDE          (vtc_de),//de信号
.I_RGB          (wave_rgb),//RGB数据
.I_PCLKX1       (pclkx1),//像素时钟
.I_PCLKX2_5     (1'b0),//2.5倍像素时钟,只有UFAMILY需要
.I_PCLKX5       (pclkx5),//5倍像素时钟
.O_TMDS_TX_CLK_P(O_HDMI_CLK_P),//HDMI时钟输出P端
.O_TMDS_TX_CLK_N(O_HDMI_CLK_N),//HDMI时钟输出N端
.O_TMDS_TX_P    (O_HDMI_TX_P),//HDMI输出数据P端
.O_TMDS_TX_N    (O_HDMI_TX_N)//HDMI输出数据N端
);

//此VTC IP 用于产生绘制波形的有效区域,波形绘制区域大小未1024*600
uivtc#
(
.H_ActiveSize(1280),          //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素
.H_SyncStart(1280+88),        //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号
.H_SyncEnd(1280+88+44),       //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行有效数据部分
.H_FrameSize(1280+88+44+239), //视频时间参数,行视频信号,一行视频信号总计占用的时钟数
.V_ActiveSize(720),           //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize
.V_SyncStart(720+4),          //视频时间参数,场同步开始,即多少行数后开始产生场同步信号
.V_SyncEnd (720+4+5),         //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分
.V_FrameSize(720+4+5+28),     //视频时间参数,场视频信号,一帧视频信号总计占用的行数量
.H2_ActiveSize(1024),         //波形绘制区域行像素大小        
.V2_ActiveSize(256)           //波形绘制区域场像素大小
)
uivtc_inst
(
.I_vtc_clk   (vtc_clk),  //系统时钟
.I_vtc_rstn  (vtc_rstn), //系统复位
.I_vtc2_offset_x(128),   //X坐标相对屏幕的原始坐标的偏移
.I_vtc2_offset_y(200),   //Y坐标相对屏幕的原始坐标的偏移
.O_vtc_vs    (vtc_vs),   //场同步输出
.O_vtc_hs    (vtc_hs),   //行同步输出
.O_vtc_de    (vtc_de),   //视频数据有效
.O_vtc2_de   (vtc2_de)   //绘制波形显示区域的有效区域
);

ila_0 ila_dbg (
.clk(I_ads422x_clk), // input wire clk
.probe0({ads422x_da,ads422x_db})
);

//测试数据产生,通过test_data产生测试数据,可以用于测试波形显示器的基本功能测试
//reg [7:0]test_data =0;
//always @(posedge vtc_clk)
//  if(vtc2_de)
//       test_data[7:0] = test_data + 1'b1;

//例化波形显示器 IP,默认支持2个通道数据,可以扩展支持更多通道
uiwave uiwave_inst
(
//波形1
.I_wave1_clk(I_ads422x_clk),//系统时钟输入
.I_wave1_data(ads422x_da[11:4]+8'h80),//ADC只显示高8bits 数据
.I_wave1_data_de(1'b1),//ADC数据有效信号

//波形2
.I_wave2_clk(I_ads422x_clk),//系统时钟输入
.I_wave2_data(ads422x_db[11:4]+8'h80),//ADC只显示高8bits 数据
.I_wave2_data_de(1'b1),//ADC数据有效信号

.I_vtc_rstn(vtc_rstn),//时序发生复位
.I_vtc_clk (vtc_clk), //像素时钟
.I_vtc_vs  (vtc_vs),  //场同步输出
.I_vtc_de  (vtc2_de),//同步,绘制波形显示区域的有效区域
.O_vtc_rgb (wave_rgb)//同步RGB数据 绘制数据输出  

);

endmodule




6测试结果6.1硬件接线
(该教程使用的是1.8V的422X子卡,测试前请确保您手上的核心板电压已调整为1.8V。)
请确保下载器和开发板已经正确连接,并且开发板已经上电(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)

2504661-20231227193108890-333836300.jpg


2504661-20231227193109346-1059760339.jpg
6.2测试结果
2504661-20231227193109821-1202433463.jpg

逻辑分析仪采集的结果
2504661-20231227193110222-1103640474.jpg

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则