[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-21 VTC视频时序控制器设计

软件版本: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概述

[1.1 显示器发展](#1.1 显示器发展)

1.1.1屏幕显示技术的变化

1.1.2视频接口的变化

[1.2 分辨率](#1.2 分辨率)

[1.3 刷新率](#1.3 刷新率)

[2 VGA成像原理及时序标准](#2 VGA成像原理及时序标准)

[3 像素时钟](#3 像素时钟)

[4 VTC控制器设计](#4 VTC控制器设计)

[5 VTC源码](#5 VTC源码)

[6 RTL仿真](#6 RTL仿真)

6.1仿真激励文件

6.2仿真结果

[7 常用系统分辨率](#7 常用系统分辨率)


1概述

Video Timing Controller 缩写VTC是我们在所有涉及FPGA图像、FPGA视频类方案中经常用到的一种用于产生视频时序的控制器。本课以 VGA 为切入点,学习视频传输的基本知识和相关概念,以及视频时序的控制器的相关内容。

1.1 显示器发展

1.1.1屏幕显示技术的变化

显示器如今已经成为我们日常生活中不可或缺的一部分,随着显示器技术的不断发展和创新,从最早的黑白CRT到今天的MicroLED,显示器行业已经发生了翻天覆地的改变,为我们提供更好的视觉体验,本章先和大家聊一聊显示器的发展历史。

CRT显示器

CRT的全称是Cathode Ray Tube,即阴极射线管,CRT显示器的成像原理是将输入的模拟信号经过放大,变换后直接驱动电子枪扫描屏幕,电子枪发射出来的电子光束撞击到在涂有荧光粉的屏幕上,产生 RGB 三基色(红、绿、蓝),合成一个彩色像素,电子光束由上到下、由左到右依次扫描屏幕,从而形成图像。由于起初阴极射线需保证发射点到屏幕任何一点半径需等长,所以屏幕就必须得是一个弧形,而为了屏幕做大,显示器的厚度也就越厚。

CRT显示器

液晶显示器:

在CRT显示器飞速发展的几年期间,也诞生了LCD(Liquid Crystal Display)液晶显示技术,由众多细小的液晶颗粒按照矩阵的形式排布而组成的显示屏,因此LCD显示屏的物理像素数量是确定的,每个像素点的颜色都可以对应一个图像数据。图像数据是数字信号,采用"电信号"显示方式,通过在液晶层中加电,改变对液晶像素点单元施加电压的电压大小,使用色彩滤光片,将白色光分解成红、绿、蓝三种基色的光,然后通过液晶面板控制光的透过与阻挡,从而显示出图像。LCD显示器的发展让显示设备彻底摆脱了厚重的机身,也为便携式计算机的出现创造了可能。

LCD显示器

1.1.2视频接口的变化

显示器显示画面质量的好坏,不仅与显示器有关,还与视频接口有直接关系。 显示器接口是计算机与外部显示设备之间进行数据传输和连接的通道,随着视频技术的发展,人们对于视频画面质量的显示也提出了更高的要求,这也推动了显示器视频接口的发展,本文介绍几种常见的显示接口及其特点。

CVBS接口:

CVBS将音频、视频分离的视频接口,一般由三个颜色组成,黄色的"V"代表连接混合视频信号,白色的"L"代表左声道音频信号,红色的"R"代表右声道的音频信号,常用于电视、DVD等产品。

S-VIDEO接口:

S-Video全称是Separate Video,也称为Super Video,将色度,亮度分离的视频信号,提高了稳定性。S-Video接口它实际上是一种五芯接口,由两路视频亮度信号、两路视频色度信号和一路公共屏蔽地线共五条芯线组成,避免了视频设备内信号串扰而产生的图像失真,极大地提高了图像的清晰度。

VGA接口:

1987年,第一台带有VGA模拟信号接口的显示器由IBM发布,VGA接口是一种D型接口,上面共有15针空,分成三排,每排五个,它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号),可以提供640 x 480分辨率的彩色显示屏,一次可以显示16种颜色,当把分辨率降低到320 x 200,则显示256种颜色。VGA接口是显卡上应用最为广泛的接口类型,从CRT显示器时代开始,VGA接口就被使用,并且一直沿用至今。由于液晶显示器发展比CRT显示技术晚,模拟信号驱动的VGA接口已经在显示器上得到广泛的使用,为了能够兼容传统的显示接口VGA,液晶显示器通过内部电路实现了对VGA接口的完全兼容。

当使用VGA接口传输图像时,生成的图像数字信息要先经过显示驱动芯片(如显卡)D/A(数字/模拟)转换器转换为R、G、B三原色信号和行、场同步信号,由VGA线缆送到显示器的VGA接口,对于CRT显示器,这些模拟信号会直接被放大后用于驱动电子枪发射电子,对于液晶显示器,则需要使用A/D(模拟/数字)转换器将模拟信号再转换为数字信号后,去驱动RGB接口的液晶显示屏显示图像。

DVI接口:

由于VGA接口采用的是模拟信号传输,在CRT显示器上使用时可以直接生成图像,在LCD显示器使用时,需要再配置A/D(模拟/数字)转换器,而在D/A和A/D两次转换的过程中,不可避免缺失一些图像细节。1999年,Intel发明了高速传输数字信号的DVI接口,设计的初衷是用来传输未经压缩的数字化视频,相比VGA接口来说,视频传输的清晰度更高。

HDMI接口:

HDMI接口是高清多媒体接口,也是现在的主流显示器接口,可以同时传输未经压缩的视频、音频的数字信号。HDMI1可以传输1080@60Hz全高清的影像输出,带宽达到4.85Gbps。到了2013年,HDMI2.0版本推出,带宽达到18Gbps,可以支持4K@60FPS画面输出。目前的HDMI2.1接口,可提供48Gbps的带宽,并且支持8K@60Hz以及4K@120Hz视频传输,现阶段主要还是以HDMI2.0为主。

DP接口:

DP(DisplayPort)接口,可以同时传输视频、音频的数字信号,相比HDMI接口,DP接口拥有更大的带宽,2009年的DP1.2接口的带宽达到21.6bps,2016年推出的DP1.4接口带宽已经达到了32.4Gbps,接近HDMI2.0接口带宽的2倍,可以支持8K@60Hz以及4K@120Hz输出,现在DP1.4接口已成为大部分显示器的标配接口。到了2019年,DP2.0推出,带宽达到80Gbps,速度是HDMI2.1的1.6倍左右。

1.2 分辨率

当提及电子设备的显示器时,就会提及一个词"分辨率",例如1080P分辨率、2K分辨率、4K分辨率,分辨率是决定屏幕的清晰程度的重要参数。分辨率只是数学上的一个概念,仅仅是用来表示横向和纵向有多少个像素点,以1080P分辨率为例做说明:它的意思是,这块屏幕横向分布了1920列像素,在纵向分为1080行像素,那么一张分辨率为1920 x 1080的图像分辨率就达到了2073600像素,分辨率越高,所包含的像素就越多,图像就越清晰,它也会增加文件占用的存储空间。

1920 x 1080显示器的像素点排布

上图为1080P 显示器的像素点排布示意图,X 轴是显示器的横轴,Y 轴是显示器的竖轴,图中的一个小方块就是一个像素点。2K 就是2560*1440个像素点,4K就是3840*2160 个像素点。显示屏大小尺寸固定时,显示分辨率越高图像越清晰,比如看视频时我们可以选择视频的清晰度,分辨率越高视频越清晰;反之,显示分辨率一定的情况下,显示屏越小图像越清晰,比如1080P的5寸的手机要比1080P的24寸显示器显示的图像细腻。

常见的显示屏分辨率标准:

1.3 刷新率

刷新率(FPS,Frames Per Second),单位为Hz,即每秒传输图像的帧数(帧数/s)。每秒钟帧数 (FPS) 愈多,一帧是静止的图象;快速连续地显示不同帧便形成了运动的假象,每秒钟帧数愈多,所显示的动作就会愈流畅。例如:60Hz的刷新率刷也就是指屏幕一秒内只扫描60次,即60帧/秒。

2 VGA成像原理及时序标准

由上面显示器的发展介绍中,我们了解到VGA标准兴起的时候,模拟信号驱动的VGA接口已经在显示器上得到广泛的使用,当时常见的彩色显示器一般由 CRT(阴极射线管)构成,我们以白底的"米联客logo"为例,将图片完全显示在CRT显示器有效区域上,并对比现在大规模使用的液晶显示器,来介绍显示器完整展现这幅图的各个阶段。

1、CRT显示器

一幅图像,可以理解成由多个像素点从左向右依次平铺构成的,CRT 显示器基于电子枪,每次只能点亮一个像素点上的荧光粉,类似我们看书的方式,从页面的左上方开始逐字按行从左到右阅读,显示一帧图像电子枪是按照'Z'形在运动,如上图红色箭头的运动方向,当扫描速度很快的时候看起来就是一幅完成的画面了。

行扫描过程:

行时序

CRT 显示器扫描是按照一行一行的方式进行的,如上图红色实心箭头运动轨迹,扫描完一行有效数据段之后不会立马返回,而是会继续向右扫描一段区域,这个区域称为右边界区域(horizontal right border),该区域不在有效的显示范围内,对应的荧光屏玻璃上没有荧光粉也不能被点亮,可以理解为显示器右边的黑边。同样,显示器左边也有这样一段黑边,在开始显示有效数据之前,电子枪扫描到的这段区域也没有荧光粉,不会显示图像, 这个区域称为左边界区域(horizontal left border),如上图所示的蓝色区域范围为边界区域,

当电子枪扫描过了右侧没有荧光粉的边界区域后,并不会自动回到最左边准备下一行,而是需要有一个通知信号,即行同步信号脉冲(horizontal sync pulse,HSYC)。再没有收到行同步信号脉冲之前,需要关闭电子枪以实现消隐,这段时间就称为 horizontal front porch,消隐是为了不影响已经点亮的像从最右侧回到显示屏的最左侧,如图所示红素点。当收到HSYC信号,电子枪会在一定时间内色虚线箭头运动轨迹,这个回去的过程需要耗费一定的时间,这个时间就称为 horizontal back porch。当HSYC信号结束以后,电子枪就会重新打开,就可以显示新的一行图像数据了。

场扫描过程:

场时序

对于CRT显示器,电子枪扫描完所有有效行的图像后会继续向下扫描一段区域,这个区域称为下边界区域(vertical bottom border),该区域不在有效的显示范围内,对应的荧光屏玻璃上没有荧光粉也不能被点亮,可以理解为显示器下边的黑边。同样的,显示器上边也有这样一段黑边,在扫描有效数据之前,电子枪扫描到的这段区域不会显示图像, 这个区域称为上边界区域(vertical top border)。当电子枪扫描一场图像到达荧光屏的最下方后,其并不会自动回到最上边,而是需要有一个通知信号,即场同步信号脉冲(vertical sync pulse,VSYC)。再没有收到场同步信号脉冲之前,需要关闭电子枪以实现消隐,这段时间就称为 vertical front porch,消隐是为了不影响已经点亮的像素点。当收到VSYC信号,电子枪会在一定时间内从最下方回到最上方,如图所示红色虚线箭头运动轨迹,这个回去的过程需要耗费一定的时间,这个时间就称为 vertical back porch。当VSYC信号结束以后,电子枪就会重新打开,就可以显示新的一行图像数据了。

2、LCD显示器

由于CRT显示器采用电子枪显示图像,不可避免而存在黑边的原因,然而现在使用的液晶显示器不需要电子枪了,还有存在黑边是因为LCD 屏幕内部是有一个IC ,IC是集成电路芯片装置,用来对透明电极上电位信号的相位、峰值、频率等进行调整与控制,从而建立起驱动电场,从而实现液晶显示图像。然而发送一行或者一帧数据给 IC,IC需要反应时间去识别一行数据扫描完需要要换行,或者一帧图像扫描完了需要扫描下一帧图像。因此,在 LCD 屏幕中需要存在boder这些参数来锁定有效的像素数据。

3 像素时钟

像素时钟(Pixel clock,pclk),也叫RGB clock或Dot clock,即RGB的时钟信号,一个基准时钟clk对应一个像素点,根据上面我们分析的行时序和场时序,显示一帧图像需要的基准时钟数N(CLK) = H_FrameEnd * V_FrameEnd,结合刷新率,可以计算像素时钟 = H_FrameEnd * V_FrameEnd * 帧率。如果是标准分辨率,建议大家以标准分辨率参数直接填入,如果不是标准分辨率则根据实际情况可以用接近标准分辨率的参数去修改相关参数。视频数据在H_AcitiveSize和V_AcitiveSize同时有效时候有效,显示屏上的显示效果如下图所示:

H_ActiveSize:有效显示区域(Visible area)

H_Syncstart:有效显示区域+前沿(Front Porch+Right Border)

H_SyncEnd:有效显示区域+前沿+HSYC(Sync Pulse)

H_FrameEnd:有效显示区域+前沿+HSYC+后沿(Back Porch+Left Border)

V_ActiveSize:有效显示区域(Visible area)

V_Syncstart:有效显示区域+前沿(Front Porch+Bottom Border)

V_SyncEnd:有效显示区域+前沿+VSYC(Sync Pulse)

V_FrameEnd:有效显示区域+前沿+VSYC+后沿(Back Porch+Top Border)

常用 标准 系统 分辨率时序参数:

|---------------|------|-----|--------|-----|------|----|--------|----|------------|
| 分辨率@帧率 | 行时序参数(像素数量) |||| 场时序参数(像素数量) |||| 像素时钟 (MHz) |
| 分辨率@帧率 | HSYC | 后沿 | 有效显示区域 | 前沿 | VSYC | 后沿 | 有效显示区域 | 前沿 | 像素时钟 (MHz) |
| 640*480@60 | 96 | 48 | 640 | 16 | 2 | 34 | 480 | 9 | 25.175 |
| 640*480@75 | 64 | 120 | 640 | 16 | 3 | 16 | 480 | 1 | 31.5 |
| 800*600@60 | 128 | 88 | 800 | 40 | 4 | 23 | 600 | 1 | 40 |
| 1024*768@60 | 136 | 160 | 1024 | 24 | 6 | 29 | 768 | 3 | 65 |
| 1280*720@60 | 40 | 220 | 1280 | 110 | 5 | 20 | 720 | 5 | 74.25 |
| 1280*1024@60 | 112 | 248 | 1280 | 48 | 3 | 38 | 1024 | 1 | 108 |
| 1920*1080@60 | 44 | 148 | 1920 | 88 | 5 | 36 | 1080 | 4 | 148.5 |

比如对于分辨率1920*1080*60的分辨率通常采用148.5MHZ的像素时钟。H_FrameSize* V_FrameSize*帧率 = 2,200* 1,125*60= 148,500,000,在时钟晶振足够精确的情况下,可以确保帧率以恒定60fps输出。我们可以给出以下参数设置:

cpp 复制代码
H_ActiveSize    =1920 
H_SyncStart     =1920+88
H_SyncEnd       =1920+88+44
H_FrameSize     =1920+88+44+148

V_ActiveSize    =1080
V_SyncStart     =1080+4
V_SyncEnd       =1080+4+5
V_FrameSize     =1080+4+5+36 

但是很多时候如果某个参数不能满足要求,那么我们也可以重新调整参数,尽量来接近标准分辨率。

对于非标准分辨率,比如当以140MHZ输出1080*1920*60的视频时,H_FrameSize* V_FrameSize *帧率=2,123*1099*60=139,990,620 这样每一帧的精确度误差为0.000067,用户可以以上面介绍的方法计算相近参数。

cpp 复制代码
H_ActiveSize    =1920
H_SyncStart     =1920+88
H_SyncEnd       =1920+88+44
H_FrameSize     =1920+88+44+71

V_ActiveSize    =1080
V_SyncStart     =1080+4
V_SyncEnd       =1080+4+5 
V_FrameSize     =1080+4+5+16

对于140MHZ的时钟输出帧率会稍微快点。我们给出以下参数:对于非标准75MHZ像素时钟,输出1280*720*60

cpp 复制代码
H_ActiveSize    =1280
H_SyncStart     =1280+88
H_SyncEnd       =1280+88+44
H_FrameSize     =1280+88+44+239

V_ActiveSize    =720
V_SyncStart     =720+4
V_SyncEnd       =720+4+5 
V_FrameSize     =720+4+5+28

4 VTC控制器设计

通过学习VGA 时序,我们知道设计一个VGA 控制器需要包括行计数器、场计数器、行、场同步信号,有效图像数据输出的使能信号。本实验以1920*1080的分辨率为例,使用2个计数器分别产生hs行时序vs场时序中各个时间参数信号,以及有效图像数据输出的de使能信号。

hcnt列计数器:

每1个像素时钟列计数器hcnt加 1,一行像素扫描完成后,计数器清零并重新计数。

cpp 复制代码
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  

vcnt行计数器:

行计数器vcnt的前提条件是列计数器hcnt计数到设定值,行计数器vcnt加 1,所有行的像素扫描完成后,计数器清零并重新计数。

cpp 复制代码
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 

行场同步信号

根据VGA时序,我们知道在消隐段期间,产生行同步信号和场同步信号,我们设置行同步信号和场同步信号为高电平时有效。根据行、列计数器的值,当相应的计数器计数到消隐时间段时,拉高同步信号。SyncStart

表示边界区域扫描完成即将进入消隐区域,此时产生行/场同步信号,SyncEnd表示行/场同步信号产生完成,边界区域扫描完成即将进入边界区域。同时扫描到场有效显示区域和行有效显示区域时,vtc_de信号拉高,表示数据有效。

cpp 复制代码
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;//只有当视频水平方向,列有效和视频垂直方向,行同时有效,视频数据部分才是有效

RGB时序转为stream时序

stream是一种标准协议接口,可用于芯片内部的数据流传输,不同于内存数据传输相关协议,基础篇没有用到这个接口,这里只给出相关代码,详细介绍请参考"总线篇"。

cpp 复制代码
reg   vtc_vs_r1  ;
reg   vtc_hs_r1  ;
reg   vtc_de_r1  ;
reg   vtc_user_r1 ,vtc_user_r2;
reg   vtc_valid_r1,vtc_valid_r2;
reg   vtc_last_r2;
reg   vs_start;
 
always @(posedge I_vtc_clk )begin
    if(rst_sync == 1'b0) //复位
        vs_start <= 1'b0;
    else if(vtc_user_r1)//清除VS帧同步
        vs_start <= 1'b0;
    else if(vtc_vs && vtc_vs_r1==1'b0)//当vtc_vs发生上升沿跳变代表一帧开始
        vs_start <= 1'b1;
end  
      
always @(posedge I_vtc_clk  )begin
    vtc_vs_r1    <= vtc_vs;
    vtc_hs_r1    <= vtc_hs;
    vtc_user_r1  <= ~vtc_user_r1 & vs_start & vtc_de;//vtc_user延迟1拍
    vtc_last_r2  <= ~vtc_de & vtc_valid_r1; //产生stream video last 延迟于数据输入2拍
    vtc_valid_r1 <= vtc_de;//vtc_valid延迟1拍
    vtc_valid_r2 <= vtc_valid_r1;//vtc_valid对输入信号延迟2拍,以和vtc_last_r2信号配套同步
    vtc_user_r2  <= vtc_user_r1; //vtc_user 对输入信号延迟2拍,以和vtc_last_r2信号配套同步    
end    

assign O_vtc_vs       =  vtc_vs_r1;
assign O_vtc_hs       =  vtc_hs_r1;
assign O_vtc_de_valid =  vtc_valid_r2;
assign O_vtc_user     =  vtc_user_r2;
assign O_vtc_last     =  vtc_last_r2;

5 VTC源码

cpp 复制代码
`timescale 1ns / 1ns //仿真时间刻度/精度

module uivtc#
(
parameter H_ActiveSize  =   1920,               //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素
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            //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分
)
(
input           I_vtc_rstn,     //系统复位
input           I_vtc_clk,      //系统时钟
output          O_vtc_vs,       //场同步输出
output          O_vtc_hs,       //行同步输出
output          O_vtc_de_valid, //视频数据有效    
output          O_vtc_user,     //满足stream时序产生 user 信号,用于帧同步
output          O_vtc_last      //满足stream时序产生 later 信号,用于每行结束
);

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;//只有当视频水平方向,列有效和视频垂直方向,行同时有效,视频数据部分才是有效

//**********************  video stream video rgb  ***************************
//如果是输入RGB时序,那么转为stream时序
reg   vtc_vs_r1  ;
reg   vtc_hs_r1  ;
reg   vtc_de_r1  ;
reg   vtc_user_r1 ,vtc_user_r2;
reg   vtc_valid_r1,vtc_valid_r2;
reg   vtc_last_r2;
reg   vs_start;
 
always @(posedge I_vtc_clk )begin
    if(rst_sync == 1'b0) //复位
        vs_start <= 1'b0;
    else if(vtc_user_r1)//清除VS帧同步
        vs_start <= 1'b0;
    else if(vtc_vs && vtc_vs_r1==1'b0)//当vtc_vs发生上升沿跳变代表一帧开始
        vs_start <= 1'b1;
end  
      
always @(posedge I_vtc_clk  )begin
    vtc_vs_r1    <= vtc_vs;
    vtc_hs_r1    <= vtc_hs;
    vtc_user_r1  <= ~vtc_user_r1 & vs_start & vtc_de;//vtc_user延迟1拍
    vtc_last_r2  <= ~vtc_de & vtc_valid_r1; //产生stream video last 延迟于数据输入2拍
    vtc_valid_r1 <= vtc_de;//vtc_valid延迟1拍
    vtc_valid_r2 <= vtc_valid_r1;//vtc_valid对输入信号延迟2拍,以和vtc_last_r2信号配套同步
    vtc_user_r2  <= vtc_user_r1; //vtc_user 对输入信号延迟2拍,以和vtc_last_r2信号配套同步    
end    

assign O_vtc_vs       =  vtc_vs_r1;
assign O_vtc_hs       =  vtc_hs_r1;
assign O_vtc_de_valid =  vtc_valid_r2;
assign O_vtc_user     =  vtc_user_r2;
assign O_vtc_last     =  vtc_last_r2;

endmodule

6 RTL仿真

6 . 1仿真激励文件

为简化仿真,这里模拟的视频格式为320*5 即一行的有效数据为350个像素,一帧数据有5行像素数据。

cpp 复制代码
`timescale 1ns / 1ns //仿真时间刻度/精度

module vtc_tb;

localparam SYS_TIME = 20;//系统时钟周期20ns

reg I_vtc_rstn,I_vtc_clk;
wire O_vid_vs,O_vid_hs,O_vtc_de_valid,O_vtc_user,O_vtc_last;

//例化视频时序产生模块
uivtc#
(
.H_ActiveSize(320),         //视频时间参数,行视频信号,一行有效(需要显示的部分)像素所占的时钟数,一个时钟对应一个有效像素,设置320个像素
.H_FrameSize(320+88+44+239),//视频时间参数,行视频信号,一行视频信号总计占用的时钟数 
.H_SyncStart(320+88),       //视频时间参数,行同步开始,即多少时钟数后开始产生行同步信号
.H_SyncEnd(320+88+44),      //视频时间参数,行同步结束,即多少时钟数后停止产生行同步信号,之后就是行数据有效数据部分
.V_ActiveSize(5),           //视频时间参数,场视频信号,一帧图像所占用的有效(需要显示的部分)行数量,通常说的视频分辨率即H_ActiveSize*V_ActiveSize
.V_FrameSize(5+4+5+28),     //视频时间参数,场视频信号,一帧视频信号总计占用的行数量
.V_SyncStart(5+4),          //视频时间参数,场同步开始,即多少行数后开始产生场同步信号 
.V_SyncEnd (5+4+5)          //视频时间参数,场同步结束,即多少行数后停止产生场同步信号,之后就是场有效数据部分
)
uivtc_inst
(
.I_vtc_clk(I_vtc_clk),  //系统时钟
.I_vtc_rstn(I_vtc_rstn),//系统复位
.O_vtc_vs(O_vid_vs),    //图形的vs信号
.O_vtc_hs(O_vid_hs),    //图形的hs信号
.O_vtc_de_valid(O_vtc_de_valid),      //de数据有效信号
.O_vtc_user(O_vtc_user),     //满足stream时序产生 user 信号,用于帧同步
.O_vtc_last(O_vtc_last)      //满足stream时序产生 later 信号,用于每行结束
);

initial begin
    I_vtc_clk  = 1'b0;
    I_vtc_rstn = 1'b0;
    #100;
    I_vtc_rstn = 1'b1;
end

always #(SYS_TIME/2) I_vtc_clk= ~I_vtc_clk;

endmodule

6 . 2仿真结果

7 常用系统分辨率

对于148.5MHZ像素时钟,输出1080*1920*60

cpp 复制代码
H_ActiveSize    =1920 
H_SyncStart     =1920+88
H_SyncEnd       =1920+88+44
H_FrameSize     =1920+88+44+148
V_ActiveSize    =1080
V_SyncStart     =1080+4
V_SyncEnd       =1080+4+5
V_FrameSize     =1080+4+5+36 

对于74.25MHZ像素时钟,输出1280*720*60

cpp 复制代码
H_ActiveSize    =1280 
H_SyncStart     =1280+110
H_SyncEnd       =1280+110+ 40
H_FrameSize     =1280+110+ 40+220
V_ActiveSize    =720
V_SyncStart     =720+4
V_SyncEnd       =720+4+5
V_FrameSize     =720+4+5+21

对于42MHZ像素时钟,输出640*480*60

cpp 复制代码
H_ActiveSize    =640 
H_SyncStart     =640+16
H_SyncEnd       =640+16+96
H_FrameSize     =640+16+96+48
V_ActiveSize    =480
V_SyncStart     =480+9
V_SyncEnd       =480+9+2
V_FrameSize     =480+9+2+34

对于非标准分辨率,用户可以以上面介绍的方法计算相近参数。

比如对于非标准140MHZ像素时钟,输出1080*1920*60

cpp 复制代码
H_ActiveSize    =1920
H_SyncStart     =1920+88
H_SyncEnd       =1920+88+44
H_FrameSize     =1920+88+44+71

V_ActiveSize    =1080
V_SyncStart     =1080+4
V_SyncEnd       =1080+4+5 
V_FrameSize     =1080+4+5+16

比如对于非标准75MHZ像素时钟,输出1280*720*60

cpp 复制代码
H_ActiveSize    =1280
H_SyncStart     =1280+88
H_SyncEnd       =1280+88+44
H_FrameSize     =1280+88+44+239

V_ActiveSize    =720
V_SyncStart     =720+4
V_SyncEnd       =720+4+5 
V_FrameSize     =720+4+5+28
相关推荐
DS小龙哥5 小时前
基于Zynq FPGA的雷龙SD NAND存储芯片性能测试
fpga开发·sd nand·雷龙·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
上理考研周导师15 小时前
第二章 虚拟仪器及其构成原理
fpga开发
FPGA技术实战16 小时前
《探索Zynq MPSoC》学习笔记(二)
fpga开发·mpsoc
bigbig猩猩1 天前
FPGA(现场可编程门阵列)的时序分析
fpga开发
Terasic友晶科技1 天前
第2篇 使用Intel FPGA Monitor Program创建基于ARM处理器的汇编或C语言工程<二>
fpga开发·汇编语言和c语言
码农阿豪1 天前
基于Zynq FPGA对雷龙SD NAND的测试
fpga开发·sd nand·spi nand·spi nand flash·工业级tf卡·嵌入式tf卡
江山如画,佳人北望1 天前
EDA技术简介
fpga开发
淘晶驰AK1 天前
电子设计竞赛准备经历分享
嵌入式硬件·fpga开发
最好有梦想~1 天前
FPGA时序分析和约束学习笔记(4、IO传输模型)
笔记·学习·fpga开发