[X]关闭

米联客FEP-DAQ002-14-20M-65M-2模数转换模块使用手册

文档创建者:uisrc
浏览次数:483
最后更新:2023-09-07
首先为硬件部分介绍1产品概述


FEP-DAQ002-14-20M-65M-2是一款14bits双通道20/65MSPS ADC采集模块,该方案采用了ADI的AD9248芯片,扩展接口支持米联客所有开发板,具有1.8V IO 和 3.3V IO接口2个版本。
2硬件参数概述
  
FEP-DAQ002-14-20M-2/  FEP-DAQ002-14-65M-2
  
  
ADC芯片
  
AD9248
  
采样精度
  
14bit
  
-3db带宽
  
145M(前置运放带宽决定)
  
IO电平
  
1.8V或者3.3V可选
  
采样频率
  
AD9248-20 0~20M
AD9248-65 0~65M
  
模拟通道
  
2个
  
触发IO
  
2个
  
输入电平
  
-5V~+5V
  
数据格式
  
偏移二进制(0~16383)
  
信噪比(SNR)
  
71.6 dBc
  
无杂散动态范围(SFDR)
  
80 dBc(至Nyquist频率,AD9248-65)
  
功耗
  
800MW
  
占用IO数量
  
35个GPIO


3引脚定义3.1 SMA引脚定义
  
引脚号
  
引脚名称
描述
PA
DAI
模拟输入通道1  
PB
DBI
模拟输入通道2
TA
TriA
双向触发输入/输出1
TB
TriB
双向触发输入/输出2
3.2 AD9248芯片功能引脚定义       AD9248工作于LVCMOS模式,数据接口简单,下图为芯片引脚定义以及采样时序。







非复合模式,一个数据通道采样1个模拟通道,采用LVCMOS SDR数据时序

复合模式,一个数据通道采样2个模拟通道,采用LVCMOS DDR数据时序,这种工作模式下当 MUX_SELECT 为逻辑高时,通道 A 数据被定向到通道 A 输出总线,通道 B 数据被定向到通道 B 输出总线。当MUX_SELECT 为逻辑低电平时,通道数据取反,即通道 A 数据导向通道 B 输出总线,通道 B 数据导向通道 A 输出总线。通过切换 MUX_SELECT 位,复用数据可在任一输出数据端口上使用。


4数据模式设置
AD9248可以通过配置DFS实现数据格式的设置
  
DFS脚电平
  
数据模式
低电平
偏移二进制和并行LVCMOS  SDR
高电平
二进制补码和并行LVCMOS  SDR
5原理图
5.1 AD9248输入设计







5.2 数字IO输入输出




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



5.4 IO电平缓冲芯片
默认AD9248只能支持2.5V和3.3V IO通过SN74AVC16T245可以实现1.2V~3.3V的IO电平转换,我们这里只用到1.8V和3.3V 两种IO电平,以适应米联客不同的FEP扩展卡。


5.5 FEP功能定义


5.6FPGA 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 AD9248采集驱动
AD9248为并行ADC,每一个时钟输出一个采样点,因此驱动简单,直接读取通过时钟同步过来的数据,所以这里只需要提供外部时钟给ADC,然后读取ADC的数据总线即可。
7.2 顶层模块调用程序
  
/**********************AD9248 ADC采集波形显示*************************
  
*********************************************************************/
  
  
`timescale 1ns / 1ns//仿真时间刻度/精度
  
  
module ad9248_top
  
(
  
input            I_sysclk_p,         //系统时钟输入   
  
output           O_ad9248_clka,      //A通道时钟输出   
  
input            I_ad9248_ora,      
  
input  [13:0]   I_ad9248_da,         //A通道数据输入
  
  
output           O_ad9248_clkb,      //B通道时钟输出  
  
input            I_ad9248_orb,
  
input  [13:0]   I_ad9248_db,         //B通道数据输入
  
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端
  
);
  
  
assign O_card_power_en = 1'b1; //子卡上电
  
  
wire pclkx1,pclkx5,adc_clk,locked; //MMCM/PLL时钟信号
  
  
assign O_ad9248_clka = adc_clk;
  
assign O_ad9248_clkb = adc_clk;
  
  
//例化MMCM/PLL IP
  
clk_wiz_1 clk_hdmi_pll_inst
  
(
  
.clk_in1(I_sysclk_p),
  
.reset(!rst_cnt[7]),
  
.locked(locked),
  
.clk_out1(pclkx1),//像素时钟
  
.clk_out2(pclkx5),//HDMI输出5倍像素时钟
  
.clk_out3(adc_clk)//给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({I_ad9248_db,I_ad9248_da}) // input wire [1:0] probe0
  
);
  
  
//测试数据产生,通过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(O_ad9248_clka),//系统时钟输入
  
.I_wave1_data(I_ad9248_da[13:6]),//ADC只显示高8bits 数据
  
.I_wave1_data_de(1'b1),//ADC数据有效信号
  
  
//波形2
  
.I_wave2_clk(O_ad9248_clkb),//系统时钟输入
  
.I_wave2_data(I_ad9248_db[13:6]),//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 测试结果


逻辑分析仪采集的结果

上图中ad9248_orb代表了输入范围超过了采样范围,可以把波形发生器的输出幅度调小一些













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

本版积分规则