[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-24 基于FPGA简易示波器显示驱动设计

软件版本:Anlogic -TD5.9.1-DR1_ES1.1

操作系统:WIN10 64bit

硬件平台:适用安路(Anlogic)FPGA

实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板

板卡获取平台:https://milianke.tmall.com/

登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!

目录

1 概述

2 波形绘制

2.1 波形绘制显示原理

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

2.3 uiwave.v源码

2.4 uiwave_buf.v通过BRAM缓存ADC数据

3 测试数据产生

4 测试结果

4.1 硬件接线

4.2 运行结果


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_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)beginif(rst_sync == 1'b0) //复位hcnt <= 12'd0;else if(hcnt != (H_FrameSize - 1'b1))//计数范围从0 ~ H_FrameSize-1hcnt <= hcnt + 1'b1;else hcnt <= 12'd0;
end         //场计数器,用于计数已经完成的行视频信号
always @(posedge I_vtc_clk)beginif(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 - 1end
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)beginif(rst_sync == 1'b0)beginO_vtc_vs <= 1'b0;O_vtc_hs <= 1'b0;O_vtc_de <= 1'b0;O_vtc2_de <= 1'b0;endelse beginO_vtc_vs <= vtc_vs; //场同步信号打拍输出O_vtc_hs <= vtc_hs; //行同步信号打拍输出O_vtc_de <= vtc_de; //视频有效信号打拍输出O_vtc2_de <= vtc2_de; //画中画,数据有效绘制信号end
endendmodule

2.3 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 / 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)beginvtc_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)beginif(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)beginif(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)beginif((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)begincasex({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

uiwave_buf.v源码中有以下代码

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

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)begincasex({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 

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  [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;//用于设置写第一个数据相对地址0wire [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)beginif(I_vtc_rstn == 1'b0)begin //复位重置所有寄存器addra      <= 10'd0;addr0_en   <= 1'b1;wea        <= 1'b0; buf_flag   <= 1'b0;WR_S       <= 1'd0;endelse begincase(WR_S) //写状态机0:begin if(I_wave_data_de)begin //有效波形数据点if(addra == 1023)begin //1024个数据写完wea      <= 1'b0; //停止写addra    <= 0;    //相对地址设置0addr0_en <= 1'b1;WR_S     <= 1'd1;//进入状态机1endelse begin //写入1024个数据wea      <= 1'b1; //写使能addr0_en <= 1'b0;addra    <= (addr0_en == 1'b0) ? (addra + 1'b1) : 0;//相对地址递增endendelse beginwea <= 1'b0;endend1:begin //等待VTC时序同步if(async_vtc_vs[3:2] == 2'b10)begin//当数据同步后,准备下一次写WR_S     <= 1'd0; //回到状态0buf_flag <= ~buf_flag;//乒乓地址切换endenddefault:WR_S   <= 2'd0;endcaseend
end//读BRAM 状态机
always @(posedge I_vtc_clk or negedge I_vtc_rstn)beginif(I_vtc_rstn == 1'b0)begin//复位重置所有寄存器addrb   <= 10'd0;RD_S    <= 1'd0;endelse begincase(RD_S)0:beginif(I_vtc_de_r)begin //I_vtc_de_r代表了有效绘制区域if(addrb == 1023)begin //1024个数据读完addrb <= 0;    //相对地址设置0RD_S  <= 1'd1; //进入状态1endelse //没一样都会扫描所有的ADC数据addrb   <= addrb + 1'b1;//相对地址递增endend1:beginif(I_vtc_de_r == 0) //等待de变为0RD_S <= 0; //回到状态0重新扫描enddefault:RD_S   <= 1'd0;endcaseend
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

2.5 BRAM 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 [2:0]    O_hdmi_tx_p,        //HDMI数据输出 P端
output [2:0]    O_hdmi_tx_n         //HDMI数据输出 N端
);localparam SYSCLKHZ     =  25_000_000; //定义系统时钟25MHZ
localparam T500MS_CNT   = (SYSCLKHZ-1); //定义每500ms访问一次EEPROM //上电延迟复位
reg [7:0]    rst_cnt=0; //复位计数器 
wire  rstn = rst_cnt[7];//用高位复位
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 [23:0] rgb_o; //RGB颜色寄存器assign vtc_clk  = pclkx1;//像素时钟
assign vtc_rstn = locked;//
assign S_rst = ~locked;//PLL时钟管理IP 输出 pclkx1和pclkx5以及locked信号
pll U_pll(
.refclk   ( I_sysclk    ),//系统时钟输入
.reset    ( !rst_cnt[7] ),
.lock     ( locked      ),//PLL LOCKED
.clk0_out ( pclkx1      ),//像素时钟
.clk1_out ( pclkx5      ),//HDMI IO的serdes 时钟 5倍的像素时钟
.clk2_out ( clk100M     )//100M时钟,给ADC采集用
); always @(posedge I_sysclk)beginif (rst_cnt[7])rst_cnt <=  rst_cnt;elserst_cnt <= rst_cnt+1'b1;
end//hdmi 输出IP
hdmi_tx#(//HDMI视频参数设置       
.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),  //视频时间参数,场视频信号,一帧视频信号总计占用的行数量               .VIDEO_VIC          ( 16       ),
.VIDEO_TPG          ( "Disable"),//设置disable,用户数据驱动HDMI接口,否则设置eable产生内部测试图形
.VIDEO_FORMAT       ( "RGB444" )//设置输入数据格式为RGB格式
)u_hdmi_tx
(
.I_pixel_clk        ( pclkx1           ),//像素时钟
.I_serial_clk       ( pclkx5           ),//串行发送时钟
.I_rst              ( S_rst              ),//异步复位信号,高电平有效//.I_video_in_user    ( vtc_user         ),//视频输入帧起始信号
//.I_video_in_valid   ( vtc_de_valid     ),//视频输入有效信号
//.I_video_in_last    ( vtc_last         ),//视频输入行结束信号
//.I_video_in_data    ( video_hdmi_data  ),//视频输入数据.I_video_rgb_enable (1'b1               ),//是否使能RGB输入接口,设置1使能,否则采用stream video时序接口  
.I_video_in_vs      (vtc_vs            ),//RGB 输入VS 帧同步
.I_video_in_de      (vtc_de       ),//RGB 输入de有效
.I_video_in_data    (rgb_o), //视频输入数据     .O_hdmi_clk_p       ( O_hdmi_clk_p       ),//HDMI时钟通道
.O_hdmi_tx_p        ( O_hdmi_tx_p        )//HDMI数据通道
);//此VTC IP 用于产生绘制波形的有效区域,波形绘制区域大小未1024*600
uivtc#
(
.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 [25:0]  t500ms_cnt   = 26'd0;//500ms计数器wire t500ms_en = (t500ms_cnt==T500MS_CNT);//500ms 使能信号//每间隔500ms状态机运行一次
always@(posedge clk100M) beginif(locked == 0)t500ms_cnt <= 0;else if(t500ms_cnt == T500MS_CNT) t500ms_cnt <= 0;else t500ms_cnt <= t500ms_cnt + 1'b1;
endreg [1:0]WAVE_S;       //写数据状态机
reg [9:0]test_data =0; //测试数据wire data_en = (WAVE_S == 0|| WAVE_S == 1); //写数据使能always @(posedge clk100M)beginif(locked == 1'b0)beginWAVE_S    <= 2'd2;test_data <=10'd0;endelse begincase(WAVE_S)0:beginif(test_data == 255)WAVE_S <= 2'd1;else test_data <= test_data + 1'b1; //数据递增end1:beginif(test_data == 0)WAVE_S <= 2'd2;else test_data <= test_data - 1'b1; //数据递减end2:if(t500ms_en)WAVE_S <= 2'd0;else WAVE_S <= WAVE_S;default:beginWAVE_S <= 2'd0;endendcase  end
end//例化波形显示器 IP,默认支持2个通道数据,可以扩展支持更多通道
uiwave uiwave_inst
(
//波形1
.I_wave1_clk(clk100M),//系统时钟输入
.I_wave1_data(test_data[7:0]),//波形测试数据
.I_wave1_data_de(data_en),//数据有效信号//波形2
.I_wave2_clk(clk100M),//系统时钟输入
.I_wave2_data(~test_data[7:0]),//演示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 运行结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1485895.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

解析Type-C母座与Type-C公头:特点与区别

解析Type-C母座与Type-C公头&#xff1a;特点与区别 在数字连接领域&#xff0c;Type-C接口因其高速、多功能等特点备受瞩目。然而&#xff0c;在Type-C连接器中&#xff0c;母座和公头作为两个重要组成部分&#xff0c;却有着各自独特的特点和用途。本文将深入探讨Type-C母座…

编程中的智慧四:设计模式总览

前面三篇我们通过从一些零散的例子&#xff0c;和简单应用来模糊的感受了下设计模式在编程中的智慧&#xff0c;从现在开始正式进入设计模式介绍&#xff0c;本篇将从设计模式的7大原则、设计模式的三大类型、与23种设计模式的进行总结&#xff0c;和描述具体意义。 设计模式体…

新形势下职业教育人工智能人才培养策略

一、引言 随着人工智能技术的飞速发展&#xff0c;社会对人工智能人才的需求日益增长。职业教育作为培养实用型人才的重要基地&#xff0c;应积极响应市场需求&#xff0c;加强人工智能人才的培养。然而&#xff0c;当前职业教育在人工智能人才培养方面仍存在一些问题&#xf…

C++树形结构(总)

目录 一.基础&#xff1a; 1.概念&#xff1a; 2.定义&#xff1a; Ⅰ.树的相关基础术语&#xff1a; Ⅱ.树的层次&#xff1a; 3.树的性质&#xff1a; 二.存储思路&#xff1a; 1.结构体存储&#xff1a; 2.数组存储&#xff1a; 三.树的遍历模板&#xff1a; 四.…

App用户从哪来?Xinstall全渠道数据统计告诉你答案!

在移动互联网时代&#xff0c;App已经成为了我们日常生活中不可或缺的一部分。然而&#xff0c;对于App运营者来说&#xff0c;如何了解用户的来源&#xff0c;从而优化推广策略&#xff0c;一直是一个难题。今天&#xff0c;我们就来科普一下App用户来源分析的重要性&#xff…

使用idea创建Javaweb项目(步骤)

第一步创建Javaweb项目 File>New>Project 第二步 勾选Web Application >Next 然后就是进行起名&#xff0c;完成。 完成创建项目&#xff0c;检查是否文件齐全 配置tomcat 配置好&#xff0c;就能启动tomcat&#xff0c;显示首页 导入jar包。导入进项目&#xf…

博客建站4 - ssh远程连接服务器

1. 什么是SSH?2. 下载shh客户端3. 配置ssh密钥4. 连接服务器5. 常见问题 5.1. IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY! 1. 什么是SSH? SSH&#xff08;Secure Shell&#xff09;是一种加密的网络协议&#xff0c;用于在不安全的网络中安全地远程登录到其他…

LC617-合并二叉树

文章目录 1 题目描述2 思路优化代码完整输入输出 参考 1 题目描述 https://leetcode.cn/problems/merge-two-binary-trees/description/ 给你两棵二叉树&#xff1a; root1 和 root2 。 将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另…

解决 elementUI 组件在 WebStorm 中显示为未知标签的问题

解决 elementUI 组件在 WebStorm 中显示为未知标签的问题 一、问题 自从转到 ts 之后&#xff0c;编辑器就一直提示用到的 elementUI 标签未知&#xff0c;一直显示一溜黄色警示&#xff0c;很烦&#xff1a; 二、解决 把它改成大写就可以了。 如下&#xff1a; 把整个项目…

视频编码中算术编码原理详解

介绍 最近研究 CABAC 熵编码原理&#xff0c;因此在剖析 CABAC 熵编码原理之前&#xff0c;先复习下算术编码的原理。算术编码是图像压缩的主要算法之一。 是一种无损数据压缩方法&#xff0c;也是一种熵编码的方法。和其它熵编码方法不同的地方在于&#xff0c;其他的熵编码方…

2024视频改字祝福 豪车装X系统源码uniapp前端源码

源码介绍 uniapp视频改字祝福 豪车装X系统源码 全开源,只有uniapp前端&#xff0c;API接口需要寻找对应的。 创意无限&#xff01;AI视频改字祝福&#xff0c;豪车装X系统源码开源&#xff0c;打造个性化祝福视频不再难&#xff01; 想要为你的朋友或家人送上一份特别的祝福…

使用 Nginx 统计固定源 IP 访问项目的时间

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

相交链表-list

160. 相交链表 - 力扣&#xff08;LeetCode&#xff09; 链表没有直接求几个的size 用哈希表把heada存进哈希&#xff0c;在用哈希表的count&#xff08;b&#xff09;&#xff0c;这个计算b出现几次&#xff0c;没出现就是0&#xff1b; class Solution { public:ListNode *g…

【计算机系统架构】从0开始构建一台现代计算机|二进制、布尔运算和ALU|第2章

博主简介&#xff1a;努力学习的22级计算机科学与技术本科生一枚&#x1f338;博主主页&#xff1a; Yaoyao2024往期回顾&#xff1a; 【计算机系统架构】从0开始构建一台现代计算机|布尔代数和基础逻辑门|第一章每日一言&#x1f33c;: 勇敢的人&#xff0c;不是不落泪的人&am…

张量的基本使用

目录 1.张量的定义 2.张量的分类 3.张量的创建 3.1 根据已有数据创建张量 3.2 根据形状创建张量 3.3 创建指定类型的张量 1.张量的定义 张量&#xff08;Tensor&#xff09;是机器学习的基本构建模块&#xff0c;是以数字方式表示数据的形式。PyTorch就是将数据封装成张量…

昇思25天学习打卡营第10天|ResNet50图像分类

学习如何使用MindSpore框架和ResNet50网络进行图像分类。 图像分类是计算机视觉的基础任务&#xff0c;就是给定一张图片&#xff0c;判断它属于哪个类别&#xff0c;比如猫、狗、飞机等。 ResNet50是一种深度学习网络&#xff0c;由微软实验室的何恺明在2015年提出&#xff…

odoo17 win11布署

今天重装系统&#xff0c;正巧试了下odoo17的布置&#xff0c;系统配置&#xff1a; windows 11专业版&#xff0c;python 3.12.3 postgresql postgresql-13.15-1-windows-x64 安装过程中适当调了一下python库版本 # The officially supported versions of the following pa…

springboot+vue+mybatis校园二手交易平台+PPT+论文+讲解+售后

现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本校园二手交易平台就是在这样的大环境下诞生&#xff0c;其可以帮助使用者在短时间内处理完毕庞大的数据信息&#…

揭秘App使用统计:Xinstall如何助你洞悉用户行为

在移动互联网时代&#xff0c;App使用统计对于开发者而言至关重要。通过深入了解用户的使用习惯和行为模式&#xff0c;开发者可以优化产品设计、提升用户体验&#xff0c;并制定出更精准的营销策略。然而&#xff0c;如何进行全面的App使用统计并分析数据&#xff0c;一直是困…

尚庭公寓开发笔记(一)

本篇文章讲的是p前五十节课 可以关注后续 传统的数据库设计流程 分为三个阶段&#xff1a;概念模型设计阶段 逻辑模型设计阶段 物理模型设计 阶段 为本项目设计数据库模型 地图的存储只需要保存经纬度就ok 本项目采用的是mysql数据库 所有表都使用的是innnodb存储引擎 我们使…