基于FPGA的VGA控制器实现(1)

VGA协议介绍

VGA是常用的视频协议,该协议中的信号是模拟信号,与之相对应的协议是HDMI协议,HDMI协议是数字协议。数字信号具有抗干扰的效果,如果做过较多的VGA协议的实现可以发现VGA协议会有模糊现象的出现,而HDMI协议可以很好的改善这点。我们会先写VGA协议,然后在VGA协议的基础上写HDMI协议,由此我们也可以发现,VGA协议是HDMI协议的基础,所以我们先学习VGA协议,在学习HDMI协议的书写。
VGA协议有很多分辨率,不同的分辨率又有不同的刷新速率,常见的分辨率如下:
在这里插入图片描述
在这里插入图片描述
我们这次以最常见的640480 @60Hz为例进行讲解,该分辨率下的详细情况如下:
在这里插入图片描述
其中:
1、是VGA的时钟频率,该时钟频率近似即可不需要特别严格的设置
2、每秒钟刷新60张图片,每张图片的分辨率是640
480
技术手册中的时序图如下:
在这里插入图片描述
联立上面两张图,可以清楚的知道上面每一部分所占像素的大小。
VGA每个像素的位数
上图数据代表VGA每个像素的位数

VGA协议时序图

VGA系统常见的系统框图如下:
在这里插入图片描述
该分辨率情况下的像素位宽每个位的意义如下:
cnt_h(144,783)&&cnt_v(35,194)红色区域
cnt_h(144,783)&&cnt_v(195,354)绿色区域
cnt_h(144,783)&&cnt_v(355,514)红色区域
整个显示数据在整个VGA控制时序中的位置如下:
在这里插入图片描述
VGA协议的时序图如下:

上面各个信号的含义如下:
分辨率:640x480
刷新率:60hz
pixel 频率(时钟):25mhz
hsync:行同步信号
vsync:场同步信号

VGA驱动代码

废话不多说结合上面对VGA时序的简单介绍与下面的代码,相信同学们可以很好的完成对VGA时序的理解

`timescale 1ns / 1ps
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : vga_drive.v
// Create Time  : 2020-02-03 20:08:42
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************

module vga_drive(
    input                   vga_clk         ,
    input                   rst_n           ,
    output  reg             hsync           ,
    output  reg             vsync           ,
    output  reg     [ 7:0]  vga_data         
);
 
//========================================================================================\
//**************Define Parameter and  Internal Signals**********************************
//========================================================================================/
localparam  H_TOTAL_TIME    =   800         ;
localparam  H_ADDR_TIME     =   640         ;
localparam  H_SYNC_TIME     =   96          ;
localparam  H_BACK_PORCH    =   40          ;
localparam  H_LEFT_BORDER   =   8           ;
localparam  V_TOTAL_TIME    =   525         ;
localparam  V_ADDR_TIME     =   480         ;
localparam  V_SYNC_TIME     =   2           ;
localparam  V_BACK_PORCH    =   25          ;
localparam  V_LEFT_BORDER   =   8           ;

reg                 [12:0]  cnt_h           ;
reg                 [12:0]  cnt_v           ;
 
//========================================================================================\
//**************     Main      Code        **********************************
//========================================================================================/
always @(posedge vga_clk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_h           <=      13'd0;
    else if(cnt_h == (H_TOTAL_TIME-1'd1))
        cnt_h           <=      13'd0;
    else
        cnt_h           <=      cnt_h + 1'b1;

always @(posedge vga_clk or negedge rst_n)
    if(rst_n == 1'b0)
        cnt_v           <=      13'd0;
    else if(cnt_v == (V_TOTAL_TIME-1'b1) && cnt_h == (H_TOTAL_TIME-1'd1)) 
        cnt_v           <=      13'd0;
    else if(cnt_h == (H_TOTAL_TIME-1'd1))
        cnt_v           <=      cnt_v + 1'b1;
    else
        cnt_v           <=      cnt_v;

always @(posedge vga_clk or negedge rst_n)
    if(rst_n == 1'b0)
        hsync           <=      1'b1;
    else if(cnt_h == (H_TOTAL_TIME-1'd1))
        hsync           <=      1'b1;
    else if(cnt_h >= (H_SYNC_TIME-1'b1))
        hsync           <=      1'b0;
    else
        hsync           <=      hsync;
        
always @(posedge vga_clk or negedge rst_n)
    if(rst_n == 1'b0)
        vsync           <=      1'b1;
    else if(cnt_v == (V_TOTAL_TIME-1'b1) && cnt_h == (H_TOTAL_TIME-1'd1))
        vsync           <=      1'b1;
    else if(cnt_v >= (V_SYNC_TIME-1'b1) && cnt_h == (H_TOTAL_TIME-1'd1))
        vsync           <=      1'b0;
    else
        vsync           <=      vsync;

always @(posedge vga_clk or negedge rst_n)
    if(rst_n == 1'b0)
        vga_data        <=      8'd0;
    else if(cnt_h >= (H_SYNC_TIME+H_BACK_PORCH+H_LEFT_BORDER-1'b1) && cnt_h < (H_SYNC_TIME+H_BACK_PORCH+H_LEFT_BORDER+H_ADDR_TIME-1'b1))begin
        if(cnt_v >= (V_SYNC_TIME+V_BACK_PORCH+V_LEFT_BORDER) && cnt_v < (V_SYNC_TIME+V_BACK_PORCH+V_LEFT_BORDER+13'd160))
            vga_data        <=      8'b111_000_00;
        else if(cnt_v >= (V_SYNC_TIME+V_BACK_PORCH+V_LEFT_BORDER+160) && cnt_v < (V_SYNC_TIME+V_BACK_PORCH+V_LEFT_BORDER+13'd320))
            vga_data        <=      8'b000_111_00;
        else if(cnt_v >= (V_SYNC_TIME+V_BACK_PORCH+V_LEFT_BORDER+320) && cnt_v < (V_SYNC_TIME+V_BACK_PORCH+V_LEFT_BORDER+13'd480))
            vga_data        <=      8'b000_000_11;
        else 
            vga_data        <=      8'd0;
    end else
        vga_data        <=      8'd0;

endmodule

VGA测试代码

与前面我们的习惯一样,如果只给出模块代码没有测试代码将会很影响我们的学习,所以这里我们将继续给出测试代码,如下:

`timescale 1ns / 1ps
`define     CLOCK       40
// *********************************************************************************
// Project Name : OSXXXX
// Author       : zhangningning
// Email        : [email protected]
// Website      : 
// Module Name  : vga_tb.v
// Create Time  : 2020-02-03 21:05:31
// Editor       : sublime text3, tab size (4)
// CopyRight(c) : All Rights Reserved
//
// *********************************************************************************
// Modification History:
// Date             By              Version                 Change Description
// -----------------------------------------------------------------------
// XXXX       zhangningning          1.0                        Original
//  
// *********************************************************************************


module vga_tb;
reg                        vga_clk         ;
reg                        rst_n           ;
wire                       hsync           ;
wire                       vsync           ;
wire               [ 7:0]  vga_data        ;  

initial begin
    vga_clk         =       1'b0;
    rst_n           <=       1'b0;
    #(`CLOCK*100)
    rst_n           <=      1'b1;
end     
always  #(`CLOCK/2)     vga_clk         =       ~vga_clk;

vga_drive vga_drive_inst(
    .vga_clk            (vga_clk            ),
    .rst_n              (rst_n              ),
    .hsync              (hsync              ),
    .vsync              (vsync              ),
    .vga_data           (vga_data           )     
);
endmodule

经过上面的知识,相信大家可以很好的学会VGA时序,接下来会有一两个VGA时序的例子,然后讲解HDMI协议。

总结

创作不易,认为文章有帮助的同学们可以收藏点赞支持。(工程也都在群中)对文章有什么看法或者需要更近一步交流的同学,可以加入下面的群:
在这里插入图片描述

发布了23 篇原创文章 · 获赞 9 · 访问量 5402

猜你喜欢

转载自blog.csdn.net/zhangningning1996/article/details/104163460