uisrc 发表于 2023-12-29 19:18:58

2-3-31 基于FPGA简易示波器显示驱动设计

软件版本:VIVADO2021.1操作系统:WIN10 64bit硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1 概述FPGA在数据采集,数据处理,图像视频领域都有广泛的应用。很多FPGA工程师苦恼,如何让FPGA采集的数据可以直观显示。如果上一个LINUX再弄一个QT写示波器软件,工作又太复杂了。基于此,设计一款基于FPGA的示波器对实时采集的波形数据在显示器上直观显示,具有非常好实用价值。基于此目的,米联客在本方案中,完成了基于FPGA的一款简易示波器显示驱动设计,由于时间和精力问题,这款基于FPGA的示波器驱动目前还只能以描点的方式进行显示。并且没有复杂的功能,只能简单的展示采集的数据。但是这个不妨碍我们后期对该示波器IP进一步升级完善。万事开头难,让我们开始把。4系统框图首先,从顶层框架上进行设计,对于波形显示部分,我们只要给出wave_clk,wave_de,wave_data三个信号,既可以完成波形显示。其次,简易示波器的驱动部分需要完成包括背景绘制、栅格绘制、曲线绘制(绘制坐标点方式)此外,我们需要考虑尽量少的FPGA资源实现这个示波器。比如用BRAM保存有效的数据点,然后通过数据比对的方式,只对有效数据点输出到显示器上。最后,我们还要设计一个简单的乒乓存储,可以一边存储数据,一边绘制波形2 波形绘制关于HDMI输出IP的部分这里不再介绍,VTC时序设计部分这里也不详细介绍。如果读者这些基础知识不清楚的,请阅读前面的实验。2.1 波形绘制显示原理通过前面关于VTC IP视频时序驱动的学习,以及TPG IP测试图形显示的学习,我们知道,对于显示器上的图像,是从液晶屏的做上角,一个像素点一个像素点绘制,当一行所有绘制完成,进行下一行的绘制。利用肉眼的视觉暂留原理,一般1秒显示25帧以上,我们就能看到视频是动态的。本方案中,我们绘制的波形曲线只需要显示波形的数据点,比如对于1920*1080的显示区域,我们时间上只要绘制1920点波形点,即可。为了方便我们理解,我们定义HS方向是X坐标,VS方向是Y坐标。比如我们这里设计的是显示1024个波形数据点,在绘制每一行的图像的时候,比对每一个数据和VS的Y坐标是否相等,如果相等就绘制这个波形点。这样我们就能完成1024个波形点在整个屏幕的显示。2.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_ActiveSizeparameter 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, //系统时钟outputreg   O_vtc_vs,//场同步输出outputreg   O_vtc_hs,//行同步输出outputreg   O_vtc_de,//视频数据有效input   I_vtc2_offset_x,//相对屏幕原点(左上角)X方向偏移input   I_vtc2_offset_y,//相对屏幕原点(左上角)Y方向偏移outputreg   O_vtc2_de   //绘制有效的显示区域);
reg hcnt = 12'd0;    //行像素计数器,寄存器reg vcnt = 12'd0;    //场像素计数器,寄存器reg rst_cnt = 3'd0;//复位计数器,寄存器wire rst_sync = rst_cnt; //同步复位
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 == 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    endend
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; //画中画,数据有效绘制信号    endend
endmodule


2.3 uiwave.v源码uiwave.v
/*************uiwave简易波形绘制驱动******************************--版本号1.0--1.代码简洁,占用极少逻辑资源,代码结构清晰,逻辑设计严谨--2.使用方便,只需要输入ADC的值,就能完成波形绘制--3.占用资源少,波形输入8bits ADC值,存储到BLOCK RAM 只需要1048*8bit 大小的BRAM,即可完成1通道的波形存储--4.乒乓绘制,当绘制一个波形的时候,另外个波形存储到另外一段地址空间--5.绘制过程中,每一行数据都读出和Y坐标匹配,如果匹配成功,使能O_pixel_en绘制这个数据点--6.背景绘制黑色--7.栅格绘制白色--8.支持多通道绘制*********************************************************************/
`timescale 1ns / 1nsmodule uiwave(//波形1input         I_wave1_clk,      //波形1时钟input I_wave1_data,   //波形1数据input         I_wave1_data_de,//波形1数据有效
//波形2input         I_wave2_clk,      //波形2时钟input 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 O_vtc_rgb   //同步输出显示颜色);
reg vtc_vs_r; //vs寄存器reg vtc_de_r; //de寄存器reg vcnt,hcnt;//vcnt计数有多少行,hcnt计数有多少列
reg    grid_de; //栅格绘制使能
assign O_vtc_vs = vtc_vs_r; //同步后输出O_vtc_vsassign O_vtc_de = vtc_de_r; //同步后输出O_vtc_de
//寄存,同步always @(posedge I_vtc_clk)begin    vtc_vs_r <= {vtc_vs_r,I_vtc_vs};    vtc_de_r <= {vtc_de_r,I_vtc_de};end
//以下hcnt用于计数列,vcnt用于计数行数
//hcnt像素计数器always @(posedge I_vtc_clk)begin    if(hcnt == 1023)      hcnt <= 12'd0;    else if(vtc_de_r && (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==7&&(vcnt==63||vcnt == 0))||((hcnt==63||hcnt==0)&&vcnt==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};   //黑色背景    endcaseend
//波形缓存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), //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),      //VTC时序发生器的de有效区域输入.I_vtc_vs(I_vtc_vs),             //VTC时序发生器的VS同步信号输入.I_vtc_vcnt(vcnt),               //vtc的数据偏移,主要对有符号数据进行调整.O_pixel_en(wave2_pixel_en)      //输出输出使能);
endmodule



uiwave_buf.v源码中有以下代码
assign   O_pixel_en= I_vtc_de_r&(I_vtc_vcnt == wave_data);


pixel_en_o信号就是wave1_pixel_en和wave2_pixel_en信号,在上级对wave1_pixel_en跟wave2_pixel_en有效的像素赋值,输出波形点颜色,grid_de有效的区域显示栅格点,其他区域显示黑色背景。Uiwave.v绘制背景、栅格、波形点的代码如下:
//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};   //黑色背景    endcaseend


2.4 uiwave_buf.v通过BRAM缓存ADC数据通过控制buf_flag信号,每次读写的地址进行切换,确保不会对同一个地址同时进行读写,造成数据冲突。
/*************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 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 I_vtc_vcnt,    //vtc的数据偏移,主要对有符号数据进行调整output      O_pixel_en   //输出输出使能);
//BRAM 简单双口BRAMreg addra = 0;//BRAM 通道A地址    //reg         ena   = 0;//BRAM 通道A使能reg         wea   = 0;//BRAM 通道A写使能reg addrb = 0;//BRAM 通道B地址reg         enb   = 0;//BRAM 通道B读使能reg WR_S,RD_S;//写状态机,读状态机reg         buf_flag;//buf_flag用于乒乓地址缓存切换reg         addr0_en;//用于设置写第一个数据相对地址0
wire wave_data;//写波形数据到BRAMreg async_vtc_vs =0; //同步信号
always @(posedge I_wave_clk)begin //对异步I_vtc_vs采样    async_vtc_vs <= {async_vtc_vs,I_vtc_vs};end
//绘制波形数据点使能,绘制原理://当匹配到存储的ADC数据和正在扫描的Y坐标值一致就输出,每个X坐标方向绘制1个波形点assign   O_pixel_en= I_vtc_de_r&(I_vtc_vcnt == wave_data);
//写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 == 2'b10)begin//当数据同步后,准备下一次写               WR_S   <= 1'd0; //回到状态0               buf_flag <= ~buf_flag;//乒乓地址切换            end      end      default:WR_S   <= 2'd0;      endcase   endend
//读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   endend
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


2.5BRAM IP设置关于更多BRAM的IP介绍请阅读前面关于BRAM的实验数据输入8bits,深度2048,这样设计可以使用最少的BRAM完成2段曲线的存储。所以如果是ADC数据,输入高8bit即可。3 测试数据产生为了验证波形显示驱动,我们编写了一个简单的三角波程序
/**********************wave_test波形测试显示**********************************************************************************************/`timescale 1ns / 1ns//仿真时间刻度/精度
module wave_test(input         I_sysclk,         //系统时钟输入output          O_hdmi_clk_p,       //HDMI时钟输出 P端output          O_hdmi_clk_n,       //HDMI时钟输出 N端output     O_hdmi_tx_p,      //HDMI数据输出 P端output     O_hdmi_tx_n         //HDMI数据输出 N端);
localparam SYSCLKHZ   =50_000_000; //定义系统时钟50MHZlocalparam T500MS_CNT   = (SYSCLKHZ-1); //定义每500ms访问一次EEPROM
//上电延迟复位reg     rst_cnt=0; //复位计数器wirerstn = rst_cnt;//用高位复位wire pclkx1,pclkx5,clk100M,locked; //MMCM/PLL时钟信号   
wire vtc_rstn,vtc_clk,vtc_vs,vtc_hs,vtc_de,vtc2_grid_de_o,vtc2_de_o;wire rgb_o; //RGB颜色寄存器
assign vtc_clk= pclkx1;//像素时钟assign vtc_rstn = locked;//clk100M
//例化MMCM/PLL IPclk_wiz_1 clk_hdmi_pll_inst(.clk_in1(I_sysclk),.reset(!rst_cnt),.locked(locked),.clk_out1(pclkx1),//像素时钟.clk_out2(pclkx5),//HDMI输出5倍像素时钟.clk_out3(clk100M)//100M时钟,给ADC采集用);
always @(posedge I_sysclk)begin    if (rst_cnt)      rst_cnt <=rst_cnt;    else      rst_cnt <= rst_cnt+1'b1;end
//例化HDMI 输出IPuihdmitx #(.FAMILY("7FAMILY")//选择芯片所支持的系列"7FAMILY" "UFAMILY"            )uihdmitx_inst(.I_rstn(locked),//复位.I_hs(vtc_hs),//hs信号.I_vs(vtc_vs),//vs信号.I_de(vtc_de),//de信号.I_rgb({rgb_o}),//RGB数据.I_pclkx1(pclkx1),//像素时钟.I_pclkx2_5(1'b0),//2.5倍像素时钟,只有UFAMILY需要.I_pclkx5(pclkx5),//5倍像素时钟.O_hdmi_tx_clk_p(O_hdmi_clk_p),//HDMI时钟输出P端.O_hdmi_tx_clk_n(O_hdmi_clk_n),//HDMI时钟输出N端.O_hdmi_tx_p(O_hdmi_tx_p),//HDMI输出数据P端.O_hdmi_tx_n(O_hdmi_tx_n)//HDMI输出数据N端);
//此VTC IP 用于产生绘制波形的有效区域,波形绘制区域大小未1024*600uivtc#(.H_ActiveSize(1280),          //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素.H_FrameSize(1280+88+44+239), //视频时间参数,行视频信号,一行视频信号总计占用的时钟数.H_SyncStart(1280+88),      //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号.H_SyncEnd(1280+88+44),   //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行有效数据部分.V_ActiveSize(720),         //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize.V_FrameSize(720+4+5+28),   //视频时间参数,场视频信号,一帧视频信号总计占用的行数量.V_SyncStart(720+4),          //视频时间参数,场同步开始,即多少行数后开始产生场同步信号.V_SyncEnd (720+4+5),       //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分.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_o)//绘制波形显示区域的有效区域);
//测试数据产生,通过test_data产生测试数据,可以用于测试波形显示器的基本功能测试
reg t500ms_cnt   = 26'd0;//500ms计数器
wire t500ms_en = (t500ms_cnt==T500MS_CNT);//500ms 使能信号
//每间隔500ms状态机运行一次always@(posedge clk100M) begin    if(locked == 0)      t500ms_cnt <= 0;    else if(t500ms_cnt == T500MS_CNT)      t500ms_cnt <= 0;    else      t500ms_cnt <= t500ms_cnt + 1'b1;end
reg WAVE_S;       //写数据状态机reg test_data =0; //测试数据
wire data_en = (WAVE_S == 0|| WAVE_S == 1); //写数据使能
always @(posedge clk100M)begin    if(locked == 1'b0)begin      WAVE_S    <= 2'd2;      test_data <=10'd0;    end    else begin       case(WAVE_S)            0:begin            if(test_data == 255)                WAVE_S <= 2'd1;            else                test_data <= test_data + 1'b1; //数据递增            end            1:begin            if(test_data == 0)                WAVE_S <= 2'd2;            else                test_data <= test_data - 1'b1; //数据递减            end            2:            if(t500ms_en)                WAVE_S <= 2'd0;            else                WAVE_S <= WAVE_S;            default:begin                WAVE_S <= 2'd0;            end       endcase    endend

//例化波形显示器 IP,默认支持2个通道数据,可以扩展支持更多通道uiwave uiwave_inst(
//波形1.I_wave1_clk(clk100M),//系统时钟输入.I_wave1_data(test_data),//波形测试数据.I_wave1_data_de(data_en),//数据有效信号
//波形2.I_wave2_clk(clk100M),//系统时钟输入.I_wave2_data(~test_data),//演示2通道显示,对另外一个波形通道取反.I_wave2_data_de(data_en),//数据有效信号
.I_vtc_rstn(vtc_rstn),//时序发生复位.I_vtc_clk (vtc_clk), //像素时钟.I_vtc_vs(vtc_vs),//场同步输出.I_vtc_de(vtc2_de_o),//同步,绘制波形显示区域的有效区域.O_vtc_rgb(rgb_o)//同步RGB数据 绘制数据输出
);
endmodule


4 测试结果4.1 硬件接线(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)请确保下载器和开发板已经正确连接,并且开发板已经上电(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)
4.2 运行结果
页: [1]
查看完整版本: 2-3-31 基于FPGA简易示波器显示驱动设计