VGA接口管脚图

引脚定义

显示原理

VGA 示器显示图像,采用扫描的方式,将构成图像的像素点,在行同步信号和场同步信号的同步下,按照从上到下、 由左到右的顺序扫描到显示屏上。

VGA 显示器扫描方式

  1. 在行、场同步信号的同步作用下,扫描坐标定位到左上角第一个像素点坐标;
  2. 自左上角(第一行)第一个像素点坐标,逐个像素点向右扫描;
  3. 扫描到第一行最后一个数据,一行图像扫描完成,进行图像消隐,扫描坐标转移到第二行行首;
  4. 重复若干次扫描至最后一行行尾,一帧图像扫描完成,进行图像消隐,扫描坐标跳转回到左上角第一行行首(图中对角线箭头),开始下一帧图像的扫描。在扫描的过程中会对每一个像素点进行单独赋值,使每个像素点显示对应色彩信息,当一帧图像扫描结束后, 开始下一帧图像的扫描,循环往复,当扫描速度足够快,加之人眼的视觉暂留特性,我们会看到一幅完整的图片,而不是一个个闪烁的像素点。这就是VGA 显示的原理。

VGA时序标准

VGA 时序由两部分构成,行同步时序与场同步时序。

VESA VGA 时序标准图

行同步时序

VESA 标准下的行同步时序图

  • 一个完整的行扫描周期,包含 6 部分: Sync(同步) 、 Back Porch(后沿) 、 LeftBorder(左边框) 、 “Addressable” Video(有效图像)、 Right Border(右边框)、 FrontPorch(前沿) ,这 6 部分的基本单位是 pixel(像素),即一个像素时钟周期。
  • 在一个完整的行扫描周期中, Video 图像信息在 HSync 行同步信号的同步下完成一行图像的扫描显示,Video 图像信息只有在“Addressable” Video(有效图像) 阶段,图像信息有效,其他阶段图像信息无效。

行同步时序

VESA 标准下的场同步时序图

  • 一个完整的场扫描周期,也包含 6 部分: Sync(同步)、 Back Porch(后沿)、 TopBorder(上边框)、 “Addressable” Video(有效图像)、 Bottom Border(底边框)FrontPorch(前沿),与行同步信号不同的是,这 6 部分的基本单位是 line(行) ,即一个完整的行扫描周期。
  • 在一个完整的场扫描周期中, Video 图像信息在 HSync(行同步信号) 和 VSync(场同步信号) 的共同作用下完成一帧图像的显示, Video 图像信息只有在“Addressable” Video(有效图像)阶段,图像信息有效,其他阶段图像信息无效。

VGA 时序图

红色区域表示在一个完整的行扫描周期中, Video 图像信息只在此区域有效,

黄色区域表示在一个完整的场扫描周期中,Video 图像信息只在此区域有效,

两者相交的橙色区域, 就是 VGA 图像的最终显示区域。

VGA 显示模式及相关参数

VGA 不同分辨率相关参数

  • 显示模式: 640x480@60
    640x480 是指 VGA 的分辨率, 640 是指有效显示图像每一行有 640 个像素点, 480 是指每一帧图像有 480 行, 640 * 480 = 307200 ≈ 300000,每一帧图片包含约 30 万个像素点,@60 是指 VGA 显示图像的刷新频率, 60 就是指 VGA 显示器每秒刷新图像 60 次,即每秒钟需要显示 60 帧图像。

行扫描周期 *场扫描周期 * 刷新频率 = 时钟频率

  • 行扫描周期: 800(像素),场扫描周期: 525(行扫描周期) 刷新频率:

60Hz800 525 60 = 25,200,000 ≈ 25.175MHz (误差忽略不计)

程序设计

本实验选用经典 VGA 显示模式 640x480@60

本实验选用经典 VGA 显示模式 640x480@60,理论时钟频率应为 25.175MHz,为了便于时钟生成,我们使用 25MHz 的时钟代替 25.175MHz 的时钟。

VGA 彩条显示实验整体框图

模块名称功能描述
vga_colorbar顶层模块
clk_gen时钟生成模块,生成VGA驱动时钟
vga_ctrlVGA时序控制模块,驱动VGA图像显示
vga_pic图像数据生成模块,生成VGA待显示图像
  1. 系统上电后,板卡传入系统时钟(sys_clk)和复位信号(sys_rst_n)到顶层模块;
  2. 系统时钟由顶层模块传入时钟生成模块(clk_gen),分频产生 VGA 工作时钟(vga_clk),作为图像数据生成模块(vga_pic)和 VGA 时序控制模块(vga_ctrl)的工作时钟;
  3. 图像数据生成模块以 VGA 时序控制模块传入的像素点坐标(pix_x,pix_y)为约束条件,生成待显示彩条图像的色彩信息(pix_data);
  4. 图像数据生成模块生成的彩条图像色彩信息传入 VGA 时序控制模块,在模块内部使用使能信号滤除掉非图像显示有效区域的图像数据,产生 RGB 色彩信息(rgb),在行、场同步信号(hsync、 vsync)的同步作用下,将 RGB 色彩信息扫描显示到VGA 显示器,显示出彩条图像。

时钟生成模块

调用 IP 核 实现时钟分频。

信号位宽类型功能描述
areset1BitInput复位信号,高电平有效
inclk01BitInput50MHz晶振时钟输入
c01BitOutput输出分频后25MHzVGA工作时钟
locked1BitOutput输出稳定时钟信号的指示信号

VGA 时序控制模块

信号位宽类型功能描述
vga_clk1BitInput工作时钟,频率25MHz
sys_rst_n1BitInput复位信号,低电平有效
pi_data16BitInput彩条图像像素点色彩信息
pix_x10BitOutputVGA有效显示区域像素点X轴坐标
pix_y10BitOutputVGA有效显示区域像素点Y轴坐标
hsync1BitOutput行同步信号
vsync1BitOutput场同步信号
rgb16BitOutputRGB图像色彩信息

波形绘制

VGA 时序控制模块参考波形图

程序代码

vga_ctrl.文件

module  vga_ctrl
(
    input    wire            vga_clk   ,
    input    wire            sys_rst_n ,
    input   wire    [15:0]  pix_data  ,

    output  wire     [9:0]  pix_x      ,
    output  wire     [9:0]  pix_y         ,
    output  wire              hsync     ,
    output  wire               vsync     ,
    output  wire     [15:0] vga_rgb

);

parameter H_SYNC    =   10'd96  ,   //行同步
          H_BACK    =   10'd40  ,   //行时序后沿
          H_LEFT    =   10'd8   ,   //行时序左边框
          H_VALID   =   10'd640 ,   //行有效数据
          H_RIGHT   =   10'd8   ,   //行时序右边框
          H_FRONT   =   10'd8   ,   //行时序前沿
          H_TOTAL   =   10'd800 ;   //行扫描周期
parameter V_SYNC    =   10'd2   ,   //场同步
          V_BACK    =   10'd25  ,   //场时序后沿
          V_TOP     =   10'd8   ,   //场时序上边框
          V_VALID   =   10'd480 ,   //场有效数据
          V_BOTTOM  =   10'd8   ,   //场时序下边框
          V_FRONT   =   10'd2   ,   //场时序前沿
          V_TOTAL   =   10'd525 ;   //场扫描周期

reg        [9:0]    cnt_h      ;
reg      [9:0]    cnt_v      ;

wire            pix_data_req;   //像素点色彩信息请求信号
wire            rgb_valid  ;     //VGA有效显示区域

//行计数器计数
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h <= 10'd0;
    else    if(cnt_h == H_TOTAL -1'b1)
        cnt_h <= 10'd0;
    else
        cnt_h <= cnt_h + 1'b1;

//场计数器计数
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v <= 10'd0;
    else    if((cnt_v == V_TOTAL - 1'b01)&&(cnt_h == H_TOTAL - 1'b1))//当行扫描周期与场扫描周期同时完成时
        cnt_v <= 10'd0;
    else    if(cnt_h == H_TOTAL - 1'b1)//当行扫描周期完成时,场扫描周期自加1
        cnt_v <= cnt_v + 1'b1;
    else
        cnt_v <= cnt_v;

//VGA有效显示区域
assign rgb_valid = ((cnt_h >= H_SYNC + H_BACK + H_LEFT) 
                     && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID)
                     && (cnt_v >= V_SYNC + V_BACK + V_TOP) 
                     && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID))
                     ? 1'b1 : 1'b0;
                     
assign pix_data_req = ((cnt_h >= H_SYNC + H_BACK + H_LEFT - 1'b1)             //超前rgb_valid有效信号一个单位时钟周期
                     && (cnt_h < H_SYNC + H_BACK + H_LEFT + H_VALID - 1'b1)  
                     && (cnt_v >= V_SYNC + V_BACK + V_TOP) 
                     && (cnt_v < V_SYNC + V_BACK + V_TOP + V_VALID))
                     ? 1'b1 : 1'b0;                     

//VGA有效显示区域像素点坐标,pix_data_req使坐标信号超前一个时钟周期解决致数据与有效信号不同步的问题 
assign pix_x = (pix_data_req == 1'b1) ? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 10'h3ff;

assign pix_y = (pix_data_req == 1'b1) ? (cnt_v - (V_SYNC + V_BACK + V_TOP)) : 10'h3ff;

//行,场同步信号
assign hsync = (cnt_h <= H_SYNC - 1'b1) ? 1'b1 : 1'b0;
assign vsync = (cnt_v <= V_SYNC - 1'b1) ? 1'b1 : 1'b0;

//vga_rgb输出像素点色彩信息
assign vga_rgb = (rgb_valid == 1'b1) ? pix_data :16'h0000;


endmodule

tb_vga_ctrl.文件

`timescale  1ns/1ns
module tb_vga_ctrl();

reg             sys_clk        ;
reg              sys_rst_n    ;

wire        [15:0]    pix_data;

wire            vga_clk        ;
wire            locked        ;
wire            rst_n       ;

wire      [9:0]    pix_x        ;
wire      [9:0]    pix_y        ;
wire              hsync       ;
wire              vsync       ;
wire     [15:0] vga_rgb     ;

//sys_clk,sys_rst_n初始赋值
initial
    begin
        sys_clk = 1'b1   ;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    end
//sys_clk:产生时钟
always #10 sys_clk = ~sys_clk;


assign rst_n = (sys_rst_n && locked);

/*
always@(posedge vga_clk or negedge sys_rst_n)  //使用时序逻辑会使坐标信号和pix_data信号滞后一个时钟周期导致数据与有效信号不同步
    if(sys_rst_n == 1'b0)
        pix_data <= 16'h0000;
    else    if(pi_x >= 10'd0 && pi_x <= 10'd639
                && pi_y >= 10'd0 && pi_y <= 10'd479)
        pix_data <= 16'hffff;
    else
        pix_data <= 16'h0000;
*/

//锁相环ip
pll_gen  pll_gen_inst
(
  .pll_rst (~sys_rst_n),    // input
  .clkin1  (sys_clk),       // input
  .pll_lock(locked),        // output
  .clkout0 (vga_clk)        // output
);



vga_ctrl vga_ctrl_inst
(
    .vga_clk   (vga_clk),
    .sys_rst_n (rst_n)  ,
    .pix_data  (pix_data),

    .pix_x      (pix_x   ),
    .pix_y      (pix_y   ),
    .hsync     (hsync  ),
    .vsync     (vsync  ),
    .vga_rgb   (vga_rgb)

);

vga_pic vga_pic_inst
(
    .vga_clk   (vga_clk),
    .sys_rst_n (rst_n),
    .pix_x     (pix_x),
    .pix_y     (pix_y ),

    .pix_data  (pix_data)
);


endmodule

vga_pic.v文件

module vga_pic
(
    input    wire          vga_clk   ,
    input    wire          sys_rst_n ,
    input    wire    [9:0] pix_x     ,
    input   wire    [9:0] pix_y     ,

    output  reg   [15:0] pix_data
);

parameter   H_VALID =   10'd640 ,   //行有效数据
            V_VALID =   10'd480 ;   //场有效数据

parameter   RED     =   16'hF800,   //红色
            ORANGE  =   16'hFC00,   //橙色
            YELLOW  =   16'hFFE0,   //黄色
            GREEN   =   16'h07E0,   //绿色
            CYAN    =   16'h07FF,   //青色
            BLUE    =   16'h001F,   //蓝色
            PURPPLE =   16'hF81F,   //紫色
            BLACK   =   16'h0000,   //黑色
            WHITE   =   16'hFFFF,   //白色
            GRAY    =   16'hD69A;   //灰色


//pix_data:输出像素点色彩信息,根据当前像素点坐标指定当前像素点颜色数据
always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pix_data    <= 16'd0;
    else    if((pix_x >= 0) && (pix_x < (H_VALID/10)*1))
        pix_data    <=  RED;
    else    if((pix_x >= (H_VALID/10)*1) && (pix_x < (H_VALID/10)*2))
        pix_data    <=  ORANGE;
    else    if((pix_x >= (H_VALID/10)*2) && (pix_x < (H_VALID/10)*3))
        pix_data    <=  YELLOW;
    else    if((pix_x >= (H_VALID/10)*3) && (pix_x < (H_VALID/10)*4))
        pix_data    <=  GREEN;
    else    if((pix_x >= (H_VALID/10)*4) && (pix_x < (H_VALID/10)*5))
        pix_data    <=  CYAN;
    else    if((pix_x >= (H_VALID/10)*5) && (pix_x < (H_VALID/10)*6))
        pix_data    <=  BLUE;
    else    if((pix_x >= (H_VALID/10)*6) && (pix_x < (H_VALID/10)*7))
        pix_data    <=  PURPPLE;
    else    if((pix_x >= (H_VALID/10)*7) && (pix_x < (H_VALID/10)*8))
        pix_data    <=  BLACK;
    else    if((pix_x >= (H_VALID/10)*8) && (pix_x < (H_VALID/10)*9))
        pix_data    <=  WHITE;
    else    if((pix_x >= (H_VALID/10)*9) && (pix_x < H_VALID))
        pix_data    <=  GRAY;
    else
        pix_data    <=  BLACK;

endmodule

vga_colorbar.v文件

module vga_colorbar
(
    input   wire         sys_clk   ,
    input    wire         sys_rst_n ,

    output    wire          hsync    ,
    output    wire           vsync     ,
    output    wire  [15:0] vga_rgb   

);

wire            vga_clk ;   //VGA工作时钟,频率25MHz
wire            locked  ;   //PLL locked信号
wire            rst_n   ;   //VGA模块复位信号
wire    [9:0]   pix_x   ;   //VGA有效显示区域X轴坐标
wire    [9:0]   pix_y   ;   //VGA有效显示区域Y轴坐标
wire    [15:0]  pix_data;   //VGA像素点色彩信息

//rst_n:VGA模块复位信号
assign  rst_n = (sys_rst_n & locked);

//锁相环ip
pll_gen  pll_gen_inst
(
  .pll_rst (~sys_rst_n),    // input
  .clkin1  (sys_clk),       // input
  .pll_lock(locked),        // output
  .clkout0 (vga_clk)        // output
);

//------------- vga_ctrl_inst -------------
vga_ctrl  vga_ctrl_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
    .pix_data   (pix_data   ),  //输入像素点色彩信息,16bit

    .pix_x      (pix_x      ),  //输出VGA有效显示区域像素点X轴坐标,10bit
    .pix_y      (pix_y      ),  //输出VGA有效显示区域像素点Y轴坐标,10bit
    .hsync      (hsync      ),  //输出行同步信号,1bit
    .vsync      (vsync      ),  //输出场同步信号,1bit
    .vga_rgb    (vga_rgb        )   //输出像素点色彩信息,16bit
);

//------------- vga_pic_inst -------------
vga_pic vga_pic_inst
(
    .vga_clk    (vga_clk    ),  //输入工作时钟,频率25MHz,1bit
    .sys_rst_n  (rst_n      ),  //输入复位信号,低电平有效,1bit
    .pix_x      (pix_x      ),  //输入VGA有效显示区域像素点X轴坐标,10bit
    .pix_y      (pix_y      ),  //输入VGA有效显示区域像素点Y轴坐标,10bit

    .pix_data   (pix_data   )   //输出像素点色彩信息,16bit

);




endmodule

tb_vag_colorbar.v文件

`timescale  1ns/1ns
module  tb_vag_colorbar();

reg             sys_clk        ;
reg              sys_rst_n    ;

wire              hsync       ;
wire              vsync       ;
wire     [15:0] vga_rgb     ;

initial
    begin
        sys_clk = 1'b1   ;
        sys_rst_n <= 1'b0;
        #20
        sys_rst_n <= 1'b1;
    end

always #10 sys_clk = ~sys_clk;

vga_colorbar    vga_colorbar_inst
(
    .sys_clk  (sys_clk),
    .sys_rst_n(sys_rst_n),

    .hsync    (hsync  ),
    .vsync      (vsync  ),
    .vga_rgb  (vga_rgb)
);


endmodule

参考资料

[1] 野火《FPGA Verilog开发实战指南》:

[[野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 — [野火]FPGA Verilog开发实战指南——基于Altera EP4CE10 征途Pro开发板 文档 (embedfire.com)](https://doc.embedfire.com/fpga/altera/ep4ce10_pro/zh/latest/index.html)

最后修改:2023 年 10 月 21 日
如果觉得我的文章对你有用,请随意赞赏