米联客FEP-DAQ003-12-125M-250M-2模数转换模块使用手册

发布时间 2023-09-10 07:57:11作者: 米联客(milianke)

1产品概述

 

FEP-DAQ003-12-125M-250M-2 数据采集模块采用一颗 TI 的 ADS4225/ ADS4229低功耗高性能模数转换芯片,实现了 2 通道125MSPS/250MSPS 模数转换,并且支持 2 路数字 IO 输入/输出触发功能。模块采用自定义 FEP 扩展接口,具有成本低, 实用性强的特性,可以适配"米联客"所有具备 FEP 扩展接口的板卡。

通过设置不同的通信模式,ADS4225/ADS4229具有LVDS DDR 接口模式和 LVCMOS SDR 接口两种模式。

2硬件参数概述

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数量

40GPIO

3引脚定义

3.1 SMA引脚定义

引脚号

引脚名称

描述

PA

DAI

模拟输入通道1

PB

DBI

模拟输入通道2

TA

TriA

双向触发输入/输出1

TB

TriB

双向触发输入/输出2

3.2 ADS422X芯片功能引脚定义

3.2.1 LVDS下接口定义

3.2.2 LVCMOS下接口定义

 

LVDS和CMOS模式的数据输出时序

LVDS的时序要求

CMOS模式的时序要求

4数据模式设置

设置SEN 脚的工作电平,来设置ADS4225/ADS4229的工作模式

SEN 脚电平

模式

0V

二进制补码和并行CMOS 输出

0.375AVDD

偏移二进制和并行CMOS 输出

0.625AVDD

偏移二进制和DDR LVDS 输出

AVDD

二进制补码和DDR LVDS 输出

5原理图

5.1 ADS4225/4229输入设计

 

5.2 数字IO输入输出

5.3 FEP模块IO电平保护电路设计

FEP的接口电压可能不一致,可能导致FPGA IO或者FEP子卡的芯片IO损坏,因此设计如下电路,当工作于1.8V模式下,TPS79618可以正常上电,否则无法上电。

5.4 FEP功能定义

根据FEP功能定义,匹配开发板的FEP扩展接口原理图配置FPGA的IO约束

5.6 FPGA PIN脚约束

米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹

01_rtl:放用户编写的rtl代码

02_sim:仿真文件或者工程

03_ip:放使用到的ip文件

04_pin:放fpga的pin脚约束文件或者时序约束文件

05_boot:放编译好的bit或者bin文件(一般为空)

06_doc:放本一些相关文档(一般为空)

6 系统框图

本方案种,把前面测试程序中的数据改为从ADC采集的数据

7 波形绘制

关于HDMI输出IP的部分这里不再介绍,VTC时序设计部分这里也不详细介绍。如果读者这些基础知识不清楚的,可以参考米联客入门级教学课程的教学资料。

7.1 ADS422X采集驱动

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[i]),     // Buffer output

.I(I_ad_da[i])      // 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[i]),     // Buffer output

.I(I_ad_db[i])      // 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

7.2 顶层模块调用程序

以下代码中,需要注意,通过DELAY_SETADELAY_SETB设置最佳的数据延迟。

对于有符号数据,通过设置I_wave1_data(ads422x_da[11:4]+8'h80),加上8'h80让波形数据转为无符号,在显示器上显示。

对于ADS4225修改PLL输出125M时钟

对于ADS4229修改PLL输出250M时钟

/**********************ADS422X 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(22       ),//通道Adelay延迟

.DELAY_SETB(22       ) //通道Bdelay延迟

)

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(adc_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

 

7.3 设置画中画区域

7.3.1 显示区域时序

显示器上的图像,是从液晶屏的左上角,一个像素点一个像素点绘制,当一行所有绘制完成,进行下一行的绘制。利用肉眼的视觉暂留原理,一般1秒显示25帧以上,我们就能看到视频是动态的。

本方案中,我们绘制的波形曲线只需要显示波形的数据点,比如对于1920*1080的显示区域,我们只要绘制1920点波形点,即可。

为了方便我们理解,我们定义HS方向是X坐标,VS方向是Y坐标。

比如我们这里设计的是显示1024个波形数据点,在绘制每一行图像的时候,比对每一个数据和VS的Y坐标是否相等,如果相等就绘制这个波形点。这样我们就能完成1024个波形点在整个屏幕的显示。

7.3.2 画中画的vtc视频时序模块设计

我们这里显示的波形数据点是1024,高度是256,因此我们需要实现一个画中画的功能。栅格绘制,以及波形数据点会以画中画的有效区域进行显示。

支持画中画的uivtc.v源码

 

/*************uivtc(video timing controller)视频时序控制器*************

--版本号1.1

--以下是米联客设计的uivtc(video timing controller)视频时序控制器

--1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨

--2.使用方便,只需要输入6个参数既可以实现对不同视频分辨率时序的控制

--3.该视频时序控制,一个时钟对应一个像素

--4.通常我们说的像素,比如1080P代表了1920*1080是指视频的有效显示区域,实际的视频还包含不能显示的区域,比如行同步,场同步时间

--5.通常我们说的行视频信号,也称之为视频的水平像素信号;场视频信号,也称之为视频的垂直像素信号;

--6.针对波形绘制,增加画中画绘制区域功能

*********************************************************************/

 

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

 

module uivtc#

(

parameter H_ActiveSize   =   1980,               //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素

parameter H_FrameSize    =   1920+88+44+148,     //视频时间参数,行视频信号,一行视频信号总计占用的时钟数

parameter H_SyncStart    =   1920+88,            //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号

parameter H_SyncEnd      =   1920+88+44,         //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行有效数据部分

 

parameter V_ActiveSize   =   1080,               //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize

parameter V_FrameSize    =   1080+4+5+36,        //视频时间参数,场视频信号,一帧视频信号总计占用的行数量

parameter V_SyncStart    =   1080+4,             //视频时间参数,场同步开始,即多少行数后开始产生场同步信号

parameter V_SyncEnd      =   1080+4+5,           //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分

 

parameter H2_ActiveSize  =   640,

parameter V2_ActiveSize  =   480

)

(

input           I_vtc_rstn,//系统复位

input           I_vtc_clk, //系统时钟

output  reg     O_vtc_vs,  //场同步输出

output  reg     O_vtc_hs,  //行同步输出

output  reg     O_vtc_de,  //视频数据有效  

input  [11:0]   I_vtc2_offset_x,//相对屏幕原点(左上角)X方向偏移

input  [11:0]   I_vtc2_offset_y,//相对屏幕原点(左上角)Y方向偏移

output  reg     O_vtc2_de       //绘制有效的显示区域

);

 

reg [11:0] hcnt = 12'd0;    //行像素计数器,寄存器

reg [11:0] vcnt = 12'd0;    //场像素计数器,寄存器  

reg [2 :0] rst_cnt = 3'd0;  //复位计数器,寄存器

wire rst_sync = rst_cnt[2]; //同步复位

 

always @(posedge I_vtc_clk or negedge I_vtc_rstn)begin //通过计数器产生同步复位

    if(I_vtc_rstn == 1'b0)

        rst_cnt <= 3'd0;

    else if(rst_cnt[2] == 1'b0)

        rst_cnt <= rst_cnt + 1'b1;

end    

 

//行像素计数器

always @(posedge I_vtc_clk)begin

    if(rst_sync == 1'b0) //复位

        hcnt <= 12'd0;

    else if(hcnt != (H_FrameSize - 1'b1))//计数范围从0 ~ H_FrameSize-1

        hcnt <= hcnt + 1'b1;

    else

        hcnt <= 12'd0;

end        

 

//场计数器,用于计数已经完成的行视频信号

always @(posedge I_vtc_clk)begin

    if(rst_sync == 1'b0)

        vcnt <= 12'd0;

    else if(hcnt == (H_ActiveSize  - 1'b1)) begin//是否一行像素结束

           vcnt <= (vcnt == (V_FrameSize - 1'b1)) ? 12'd0 : vcnt + 1'b1;//每一行计数,场计数器加1,计数范围0~V_FrameSize - 1

    end

end

 

wire hs_valid  =  hcnt < H_ActiveSize; //行信号有效像素部分

wire vs_valid  =  vcnt < V_ActiveSize; //场信号有效像素部分

wire vtc_hs   =  (hcnt >= H_SyncStart && hcnt < H_SyncEnd);//产生hs,行同步信号

wire vtc_vs    = (vcnt > V_SyncStart && vcnt <= V_SyncEnd);//产生vs,场同步信号      

wire vtc_de   =  hs_valid && vs_valid;//只有当行像素有效和场像素同时有效,视频数据部分才是有效

 

//画中画,波形绘制区域

wire hs2_valid  =  (hcnt>=I_vtc2_offset_x)&& (hcnt<(I_vtc2_offset_x+H2_ActiveSize)); //画中画,波形绘制区域HS有效信号

wire vs2_valid  =  (vcnt>=I_vtc2_offset_y)&& (vcnt<(I_vtc2_offset_y+V2_ActiveSize)); //画中画,波形绘制区域VS有效信号

wire vtc2_de    =  hs2_valid && vs2_valid; //画中画,数据有效绘制信号

 

//完一次寄存打拍输出,有利于改善时序,尤其对于高分辨率,高速的信号,打拍可以改善内部时序,以运行于更高速度

always @(posedge I_vtc_clk)begin

    if(rst_sync == 1'b0)begin

        O_vtc_vs <= 1'b0;

        O_vtc_hs <= 1'b0;

        O_vtc_de <= 1'b0;

        O_vtc2_de <= 1'b0;

    end

    else begin

        O_vtc_vs <= vtc_vs; //场同步信号打拍输出

        O_vtc_hs <= vtc_hs; //行同步信号打拍输出

        O_vtc_de <= vtc_de; //视频有效信号打拍输出

        O_vtc2_de <= vtc2_de; //画中画,数据有效绘制信号

    end

end

 

endmodule

7.3.3 栅格绘制波形绘制

uiwave.v

`timescale 1ns / 1ns

module uiwave

(

 

//波形1

input         I_wave1_clk,      //波形1时钟

input  [7 :0] I_wave1_data,     //波形1数据

input         I_wave1_data_de,  //波形1数据有效

 

//波形2

input         I_wave2_clk,      //波形2时钟

input  [7 :0] I_wave2_data,     //波形2数据

input         I_wave2_data_de,  //波形2数据有效

 

//VTC时序输入

input         I_vtc_rstn,       //时序复位输入

input         I_vtc_clk,        //时序时钟输入

input         I_vtc_vs,         //VS-帧同步,信号同步输入

input         I_vtc_de,         //de有效区域,信号同步输入

 

//同步时序输出,以及像素输出

output        O_vtc_vs,         //帧同步输出

output        O_vtc_de,         //de信号同步后输出

output reg [23:0] O_vtc_rgb     //同步输出显示颜色

);

 

reg  [1  :0] vtc_vs_r; //vs寄存器

reg  [1  :0] vtc_de_r; //de寄存器

reg  [11 :0] vcnt,hcnt;//vcnt计数有多少行,hcnt计数有多少列

 

reg    grid_de; //栅格绘制使能

 

assign O_vtc_vs = vtc_vs_r[0]; //同步后输出O_vtc_vs

assign O_vtc_de = vtc_de_r[0]; //同步后输出O_vtc_de

 

//寄存,同步

always @(posedge I_vtc_clk)begin

    vtc_vs_r <= {vtc_vs_r[0],I_vtc_vs};

    vtc_de_r <= {vtc_de_r[0],I_vtc_de};

end

 

//以下hcnt用于计数列,vcnt用于计数行数

 

//hcnt像素计数器

always @(posedge I_vtc_clk)begin

    if(hcnt == 1023)

        hcnt <= 12'd0;

    else if(vtc_de_r[0] && (hcnt != 1023)) //hcnt计数列,共计1024个像素

        hcnt <= hcnt + 1'b1;

end

 

//vcnt计数有多少行

always @(posedge I_vtc_clk)begin

    if(vtc_vs_r == 2'b01)

        vcnt <= 8'd0;

    else if((vtc_de_r == 2'b10) && (vcnt != 255)) //de信号用于计数行,共计256

        vcnt <= vcnt + 1'b1;

end

 

//栅格绘制

always @(posedge I_vtc_clk)begin

    if((hcnt[2:0]==7&&(vcnt[5:0]==63||vcnt == 0))||((hcnt[5:0]==63||hcnt==0)&&vcnt[2:0]==7)||(vcnt == 0 && hcnt==0))

        grid_de <= O_vtc_de;

    else

        grid_de <= 1'b0;

end

 

//1--绘制波形曲线1,绿色点

//2--绘制波形曲线2,黄色点

//3--绘制栅格虚线,白色点

//4--绘制背景色,黑色

always @(posedge I_vtc_clk)begin

    casex({grid_de,wave2_pixel_en,wave1_pixel_en})

            3'bxx1:

               O_vtc_rgb <= {8'h00,8'hff,8'h00};   //wave1信号显示像素颜色

            3'bx10:

               O_vtc_rgb <= {8'hff,8'hff,8'h00};   //wave2信号显示像素颜色

            3'b100:

               O_vtc_rgb <= {8'h96,8'h96,8'h96};   //网格显示像素为白色点

        default:

               O_vtc_rgb <= {8'h00,8'h00,8'h00};   //黑色背景

    endcase

end

 

//波形缓存1,以及波形绘制像素点输出使能

uiwave_buf uiwave1_buf_inst

(

.I_wave_clk    (I_wave1_clk),     //写数据输入时钟,和ADC采集时钟同步

.I_wave_data   (I_wave1_data),    //写数据

.I_wave_data_de(I_wave1_data_de), //写数据有效

 

.I_vtc_clk      (I_vtc_clk),      //VTC时序发生器时钟输入

.I_vtc_rstn     (I_vtc_rstn),     //VTC时序发生器复位

.I_vtc_de_r     (vtc_de_r[0]),    //VTC时序发生器的de有效区域输入

.I_vtc_vs       (I_vtc_vs),      //VTC时序发生器的VS同步信号输入

.I_vtc_vcnt     (vcnt),           //vtc的数据偏移,主要对有符号数据进行调整

.O_pixel_en     (wave1_pixel_en)  //输出输出使能

);

 

//波形缓存2,以及波形绘制像素点输出使能

uiwave_buf uiwave2_buf_inst

(

.I_wave_clk      (I_wave2_clk),     //写数据输入时钟,和ADC采集时钟同步

.I_wave_data     (I_wave2_data),    //写数据

.I_wave_data_de  (I_wave2_data_de), //写数据有效

 

.I_vtc_clk       (I_vtc_clk),       //VTC时序发生器时钟输入

.I_vtc_rstn      (I_vtc_rstn),      //VTC时序发生器复位

.I_vtc_de_r      (vtc_de_r[0]),     //VTC时序发生器的de有效区域输入

.I_vtc_vs        (I_vtc_vs),       //VTC时序发生器的VS同步信号输入

.I_vtc_vcnt      (vcnt),            //vtc的数据偏移,主要对有符号数据进行调整

.O_pixel_en      (wave2_pixel_en)   //输出输出使能

);

 

endmodule

7.3.4 波形点缓存

uiwave_buf.v通过BRAM缓存ADC数据

/*************uiwave_buf简易波形绘制驱动******************************

--版本号1.0

--1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨

--2.使用方便,只需要输入ADC的值,就能完成波形绘制

--3.占用资源少,波形输入8bits ADC值,存储到BLOCK RAM 只需要1048*8bit 大小的BRAM,即可完成1通道的波形存储

--4.乒乓绘制,当绘制一个波形的时候,另外个波形存储到另外一段地址空间

--5.绘制过程中,每一行数据都读出和Y坐标匹配,如果匹配成功,使能O_pixel_en绘制这个数据点

*********************************************************************/

 

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

 

module uiwave_buf

(

input     I_wave_clk,    //写数据输入时钟,和ADC采集时钟同步

input  [7 :0] I_wave_data,   //写数据

input         I_wave_data_de,//写数据有效

 

input         I_vtc_clk,     //VTC时序发生器时钟输入

input         I_vtc_rstn,    //VTC时序发生器复位

input         I_vtc_vs,      //VTC时序发生器的VS同步信号输入

input         I_vtc_de_r,    //VTC时序发生器的de有效区域输入

input  [7 :0] I_vtc_vcnt,    //vtc的数据偏移,主要对有符号数据进行调整

output        O_pixel_en     //输出输出使能

);

 

//BRAM 简单双口BRAM

reg  [9 :0] addra = 0;  //BRAM 通道A地址    

//reg         ena   = 0;  //BRAM 通道A使能

reg         wea   = 0;  //BRAM 通道A写使能

reg  [9 :0] addrb = 0;  //BRAM 通道B地址

reg         enb   = 0;  //BRAM 通道B读使能

reg  [0 :0] WR_S,RD_S;  //写状态机,读状态机

reg         buf_flag;//buf_flag用于乒乓地址缓存切换

reg         addr0_en;//用于设置写第一个数据相对地址0

 

wire [7 :0] wave_data;//写波形数据到BRAM

reg  [3 :0] async_vtc_vs =0; //同步信号

 

always @(posedge I_wave_clk)begin //对异步I_vtc_vs采样

    async_vtc_vs <= {async_vtc_vs[2:0],I_vtc_vs};

end

 

//绘制波形数据点使能,绘制原理:

//当匹配到存储的ADC数据和正在扫描的Y坐标值一致就输出,每个X坐标方向绘制1个波形点

assign   O_pixel_en  = I_vtc_de_r&(I_vtc_vcnt[7:0] == wave_data[7:0]);

 

//BRAM 状态机

always @(posedge I_wave_clk or negedge I_vtc_rstn)begin

    if(I_vtc_rstn == 1'b0)begin //复位重置所有寄存器

       addra      <= 10'd0;

       addr0_en   <= 1'b1;

       wea      <= 1'b0;

       buf_flag   <= 1'b0;

       WR_S     <= 1'd0;

    end

    else begin

        case(WR_S) //写状态机

        0:begin

        if(I_wave_data_de)begin //有效波形数据点

               if(addra == 1023)begin //1024个数据写完

                 wea      <= 1'b0; //停止写

                 addra    <= 0;    //相对地址设置0

                 addr0_en <= 1'b1;

                 WR_S     <= 1'd1;//进入状态机1

               end

               else begin //写入1024个数据

                 wea      <= 1'b1; //写使能

                 addr0_en <= 1'b0;

                 addra    <= (addr0_en == 1'b0) ? (addra + 1'b1) : 0;//相对地址递增

               end

            end

            else begin

              wea <= 1'b0;

            end

        end

        1:begin //等待VTC时序同步

            if(async_vtc_vs[3:2] == 2'b10)begin//当数据同步后,准备下一次写

               WR_S     <= 1'd0; //回到状态0

               buf_flag <= ~buf_flag;//乒乓地址切换

            end

        end

        default:WR_S   <= 2'd0;

        endcase

     end

end

 

//BRAM 状态机

always @(posedge I_vtc_clk or negedge I_vtc_rstn)begin

    if(I_vtc_rstn == 1'b0)begin//复位重置所有寄存器

       addrb   <= 10'd0;

       RD_S    <= 1'd0;

    end

    else begin

        case(RD_S)

        0:begin

          if(I_vtc_de_r)begin //I_vtc_de_r代表了有效绘制区域

               if(addrb == 1023)begin //1024个数据读完

                 addrb <= 0;    //相对地址设置0

                 RD_S  <= 1'd1; //进入状态1

               end

               else //没一样都会扫描所有的ADC数据

                 addrb   <= addrb + 1'b1;//相对地址递增

            end

        end

    1:begin

          if(I_vtc_de_r == 0) //等待de变为0

                RD_S <= 0; //回到状态0重新扫描

               

        end

        default:RD_S   <= 1'd0;

        endcase

     end

end  

 

wave_ram buf_inst(

.dina(I_wave_data), //写入波形数据

.addra({buf_flag,addra}), //写地址,其中addra是相对地址,buf_flag是地址高位,用于读写的乒乓切换

.wea(wea), //写使能

.clka(I_wave_clk),//写时钟

 

.doutb(wave_data), //读出的波形数据

.addrb({~buf_flag,addrb}), //写地址,其中addrb是相对地址,buf_flag是地址高位,用于读写的乒乓切换

.clkb(I_vtc_clk)//读时钟

);

 

endmodule

 

7.4 测试结果

7.4.1 硬件接线

以MLK-F6-7015为演示板卡,其他板卡类似

设置波形发生器产生测试波形

7.4.2 测试结果

逻辑分析仪采集的结果

 

 

附录1:FEP卡命名规则(MLK-NV2023版本)

1 FEP-DAQ模数转换类系列命名

模拟数字采集,数模转换模块命名规则

FEP:FEP系列

DAQ:模数转换系列

Num:编号

Bit:采样位宽

SPS:采样率

Channels:支持的采样速率

2 FEP-AUD音频类系列命名

音频模块命名

FEP:FEP系列

AUD:音频系列

Num:编号

Bit:采样位宽

SPS:采样率

Channels:支持的采样速率

3 FEP-COM通信类系列命名

FEP:FEP系列

COM:通用通信类模块或者IO模块

Num:编号

Class1:类型,预留

Class2:类型,预留

4 FEP-LAN通信类系列命名

FEP:FEP系列

LAN:以太网通信类

Num:编号

Class1:类型,预留

Class2:类型,预留

5 FEP-VID通信类系列命名

FEP:FEP系列

VID:视频类

Num:编号

Class1:类型,预留

Class2:类型,预留

6 FEP-CAM摄像头类

FEP:FEP系列

CAM:摄像头类

Num:编号

Class1:类型,预留

Class2:类型,预留

7 FEP-MEM存储类

FEP:FEP系列

MEM:存储类

Num:编号

Class1:类型,预留

Class2:类型,预留

 

 

 

 

 

附录2:常见问题

1 联系方式

技术交流群网址: https://www.uisrc.com/f-380.html查看最新可以加入的QQ

 

技术微信:18951232035

技术电话:18951232035

 

官方微信公众号(新微信公众号):

2 售后

1、7天无理由退货(人为原因除外)

2、质保期限:本司产品自快递签收之日起,提供一年质保服务(主芯片,比如FPGA 或者CPU等除外)。

3、维修换货,需提供淘宝订单编号或合同编号,联系销售/技术支持安排退回事宜。

售后维修请登录工单系统:https://www.uisrc.com/plugin.php?id=x7ree_service

4、以下情形不属于质保范畴。

A:由于用户使用不当造成板子的损坏:比如电压过高造成的开发板短路,自行焊接造成的焊盘脱落、铜线起皮 等

B:用户日常维护不当造成板子的损坏:比如放置不当导致线路板腐蚀、基板出现裂纹等

5、质保范畴外(上方第4条)及质保期限以外的产品,本司提供有偿维修服务。维修仅收取器件材料成本,往返运 费全部由客户承担。

6、寄回地址,登录网页获取最新的售后地址:https://www.uisrc.com/t-1982.html

3 销售

天猫米联客旗舰店:https://milianke.tmall.com

京东米联客旗舰店:https://milianke.jd.com/

FPGA|SOC生态店:https://milianke.taobao.com

 

销售电话:18921033576

 

常州溧阳总部:常州溧阳市中关村吴潭渡路雅创高科制造谷 10-1幢楼

4 在线视频

https://www.uisrc.com/video.html

5 资源下载

https://www.uisrc.com/download.html

6 软件或其他下载

https://www.uisrc.com/f-download.html