23 VTC视频时序控制器设计

发布时间 2023-12-29 17:17:55作者: 米联客(milianke)

软件版本:VIVADO2021.1

操作系统:WIN10 64bit

硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA

登录米联客(MiLianKe)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!

1 概述

Video Timing Controller 缩写VTC是我们在所有涉及FPGA图像、FPGA视频类方案中经常用到的一种用于产生视频时序的控制器。

2 VTC控制器设计

2.1 系统框图

VTC控制器通过hcnt和vcnt计数器实现hs时序vs时序以及de时序。

2.2 时序设计

视频数据在H_AcitiveSize和V_AcitiveSize同时有效时候有效,显示屏上的显示效果如下图所示。

3 VTC源码

 

`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            //视频时间参数,场同步结束,即多少场数后停止产生场同步信号,之后就是场有效数据部分

)

(

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

4 RTL仿真

4.1 仿真激励文件

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

/*************视频时序测试仿真文件****************************************

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

 

`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

 

4.2 仿真结果

5 分辨率以及时钟计算方法

如果是标准分辨率,建议大家以标准分辨率参数直接填入,如果不是标准分辨率则根据实际情况可以用接近标准分辨率的参数去修改相关参数。

比如对于标准分辨率1080*1920*60的分辨率通常采用148.5MHZ的像素时钟。此时我们可以给出以下参数设置:

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

计算分辨率和时钟的推断可以用一个关键公式 像素时钟= H_FrameSize* V_FrameSize*帧率,但是通常我们只会知道,H_ActiveSize、V_ActiveSize以及帧率,而像素时钟和其他参数都需要我们自己设置。

    可以先以以上标准1080*1920*60的分辨率计算下:

H_FrameSize* V_FrameSize*帧率 = 2,200* 1,125*60= 148,500,000,在时钟晶振足够精确的情况下,可以确保帧率以恒定60fps输出。

但是很多时候如果某个参数不能满足要求,比如系统时钟只能提供140MHZ的情况,那么我们也可以重新调整参数,尽量来接近标准分辨率。

比如当以140MHZ输出1080*1920*60fps的视频时,我们给出以下参数:

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

H_FrameSize* V_FrameSize *帧率=2,123*1099*60=139,990,620 这样每一帧的精确度误差为0.000067。对于140MHZ的时钟输出帧率会稍微快点。

6 常用系统分辨率

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

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

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

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

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

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