0
点赞
收藏
分享

微信扫一扫

混合云自动化优势有哪些?

文章目录


一、前言

  VTC(Video Timing Controller)是一种用于产生视频时序的控制器,在图像领域经常会输出各种分辨率和帧率的视频格式。因此为了方便,设置一个VTC控制模块,只需要在顶层修改一下需要输出的视频格式,就能自动的产生对应的时序,这样能方便处理一点。Xilinx Vivado 也有专门用于生成视频时序的 IP,叫做 Video Timing Controller 核,官方的说明在 PG016,本文使用Verilog实现VTC的基本功能。

二、视频时序控制原理

  在《VGA接口时序以及FPGA实现》文章中,我们实现了1080P的时序并且成功的在显示器上显示出来了。VTC原理和VGA一样,只需要在给正确的时钟频率产生出正确的VS和HS信号即可。视频显示原理如下:

在这里插入图片描述

  显示器显示图像主要由行同步信号场同步信号构成:

  • 每一行又分为:行同步信号H_SYNC;行后沿信号H_BACK_PORCH;行数据有效信号H_ACTIVE;行前沿信号 H_FRONT_PORCH。
  • 每一列同样分为:场同步信号V_SYNC;场后沿信号V_BACK_PORCH;场数据有效信号V_ACTIVE;场前沿信号V_FRONT_PORCH。
  • 只有在行数据有效信号H_ACTIVE和场数据有效信号V_ACTIVE都有效时,才输出de信号。

  常见分辨率视频所对应的各信号长度如下:

显示模式时钟/Mhz行同步hsync行后沿行有效行前沿行总共场同步vsync场后沿场有效场前沿场总共
640×480@60Hz25.296486401680023348010525
800×600@60Hz40128888004010564236001628
1024×768@60Hz6513616010242413446297683806
1280×720@60Hz74.2540220128011016505207205750
1280×1024@60Hz1081122481280481688338102411066
1920×1080@60Hz148.5441481920882200536108041125
3840×2160@60Hz59488296384019644001072216082250

三、Verilog实现

3.1 代码

`timescale 1ns/1ns
module vtc#
(
    parameter                                           H_SYNC                  = 96,   //行同步信号
    parameter                                           H_BACK_PORCH            = 48,   //行后沿
    parameter                                           H_ACTIVE                = 640,  //行有效数据
    parameter                                           H_FRONT_PORCH           = 16,   //行前沿
    parameter                                           V_SYNC                  = 2,    //场同步信号
    parameter                                           V_BACK_PORCH            = 33,   //场后沿
    parameter                                           V_ACTIVE                = 480,  //场有效信号
    parameter                                           V_FRONT_PORCH           = 10    //场前沿
) 
(
    input                                               clk ,                   
    input                                               rst_n   ,
    output  reg                                         vs  ,                   //输出vs信号
    output  reg                                         hs  ,                   //输出hs信号
    output  reg                                         de  ,                   //输出de信号
    output  reg                                         h_end                   //每一行结束信号
);
    
    localparam                                          hcnt_max    = H_SYNC + H_BACK_PORCH + H_ACTIVE + H_FRONT_PORCH;     //行扫描最大计数值
    localparam                                          vcnt_max    = V_SYNC + V_BACK_PORCH + V_ACTIVE + V_FRONT_PORCH;     //列扫描最大计数值

    reg             [12:0]                              h_cnt = 13'd0  ;        //行扫描器,对列计数
    reg             [11:0]                              v_cnt = 12'd0  ;        //列扫描器,对行计数
    reg             [3:0]                               rst_cnt = 4'd0 ;        //复位计数器
    reg                                                 rst_sync = 1'b0  ;      //同步复位信号

    reg                                                 data_valid = 1'b0  ;          //输出数据有效信号
    reg                                                 data_valid_reg1 =1'b0  ;
    reg                                                 data_valid_reg2 =1'b0  ;
    reg                                                 hs_valid = 1'b0  ;           //行同步有效信号
    reg                                                 hs_valid_reg1 =1'b0  ;
    reg                                                 hs_valid_reg2 =1'b0  ;
    reg                                                 vs_valid = 1'b0  ;           //行同步有效信号
    reg                                                 vs_valid_reg1 =1'b0  ;
    reg                                                 vs_valid_reg2 =1'b0  ;
 

//异步复位,同步释放
always @(posedge clk or negedge rst_n) begin
    if(rst_n == 1'b0)
        rst_cnt <= 3'd0;
    else if (rst_cnt[3] == 1'b1) 
        rst_cnt <= rst_cnt;
    else
        rst_cnt <= rst_cnt + 1'b1;   
end

always @(posedge clk) begin
    if(rst_cnt[3] == 1'b0)
        rst_sync <= 1'b0;
    else
        rst_sync <= 1'b1;
end

//水平方向扫描,对列计数
always @(posedge clk) begin
    if(rst_sync == 1'b0)
        h_cnt <= 13'd0;
    else if(h_cnt == hcnt_max - 1)
        h_cnt <= 13'd0;
    else
        h_cnt <= h_cnt + 1'b1;
end

//垂直方向,对行计数
always @(posedge clk) begin
    if(rst_sync == 1'b0)
        v_cnt <= 12'd0;
    else if((v_cnt == vcnt_max - 1) && (h_cnt == hcnt_max - 1))
        v_cnt <= 12'd0;
    else if(h_cnt == hcnt_max - 1)
        v_cnt <= v_cnt + 1'b1;
    else
        v_cnt <= v_cnt;
end

//行同步信号
always @(posedge clk) begin
    if(rst_sync == 1'b0)
        hs_valid <= 1'b0;
    else if(h_cnt <= H_SYNC - 1)
        hs_valid <= 1'b1;
    else
        hs_valid <= 1'b0; 
end

always @(posedge clk) begin
    if(rst_sync == 1'b0)begin
        hs_valid_reg1 <= 1'b0;
        hs_valid_reg2 <= 1'b0;
    end
    else begin
        hs_valid_reg1 <= hs_valid;
        hs_valid_reg2 <= hs_valid_reg1;
    end
end

//场同步信号
always @(posedge clk) begin
    if(rst_sync == 1'b0)
        vs_valid <= 1'b0;
    else if(v_cnt <= V_SYNC - 1)
        vs_valid <= 1'b1;
    else
        vs_valid <= 1'b0;
end

always @(posedge clk) begin
    if(rst_sync == 1'b0)begin
        vs_valid_reg1 <= 1'b0;
        vs_valid_reg2 <= 1'b0;
    end
    else begin
        vs_valid_reg1 <= vs_valid;
        vs_valid_reg2 <= vs_valid_reg1;
    end
end

//数据有效信号
always @(posedge clk) begin
     if(rst_sync == 1'b0)
        data_valid <= 1'b0;
    else if(((h_cnt >= H_SYNC + H_BACK_PORCH)&&(h_cnt < hcnt_max - H_FRONT_PORCH))&&((v_cnt >= V_SYNC + V_BACK_PORCH)&&(v_cnt < vcnt_max - V_FRONT_PORCH)))
        data_valid <= 1'b1;
    else
        data_valid <= 1'b0;  
end

always @(posedge clk) begin
    if(rst_sync == 1'b0)begin
        data_valid_reg1 <= 1'b0;
        data_valid_reg2 <= 1'b0;
    end
    else begin
        data_valid_reg1 <= data_valid;
        data_valid_reg2 <= data_valid_reg1;
    end
end

//输出信号
always @(posedge clk) begin
    if(rst_sync == 1'b0)
        h_end <= 1'b0;
    else if(~data_valid_reg1 & data_valid_reg2)
        h_end <= 1'b1;
    else
        h_end <= 1'b0;
end

always @(posedge clk) begin
    if(rst_sync == 1'b0)begin
        de <= 1'b0;
        vs <= 1'b0;
        hs <= 1'b0;
    end
    else begin
        de <= data_valid_reg2;
        vs <= vs_valid_reg2;
        hs <= hs_valid_reg2;
    end
end
endmodule

3.2 仿真以及分析

  tb文件编写

`timescale 1ns / 1ps
module tb_vtc();

    reg                                                 clk ;
    reg                                                 rst_n   ;
    wire                                                de  ;
    wire                                                hs  ;
    wire                                                vs  ;
    wire                                                h_end   ;

    initial begin
        clk = 0;
        rst_n = 0;
        #200;
        rst_n = 1;
    end

always # 10 clk     = ~clk;

vtc#(
    .H_SYNC        ( 96 ),
    .H_BACK_PORCH  ( 48 ),
    .H_ACTIVE      ( 640 ),
    .H_FRONT_PORCH ( 16 ),
    .V_SYNC        ( 2 ),
    .V_BACK_PORCH  ( 33 ),
    .V_ACTIVE      ( 480 ),
    .V_FRONT_PORCH ( 10 )
)u_vtc(
    .clk           ( clk           ),
    .rst_n         ( rst_n         ),
    .vs            ( vs            ),
    .hs            ( hs            ),
    .de            ( de            ),
    .h_end         ( h_end         )
);

endmodule

仿真结果如下:
在这里插入图片描述
  由上图可以看出,V_SYNC信号共占2个v_cnt周期。

在这里插入图片描述
  由上图可以看出,H_SYNC信号共有1920ns,1920/20=96个h_cnt周期。

在这里插入图片描述  由上图可以看出,de信号共有12800ns,12800/20=640个h_cnt周期。综上,本次仿真符合640*480@60hz的视频时序

举报

相关推荐

0 条评论