VGA接口管脚图
引脚定义
显示原理
VGA 示器显示图像,采用扫描的方式,将构成图像的像素点,在行同步信号和场同步信号的同步下,按照从上到下、 由左到右的顺序扫描到显示屏上。
- 在行、场同步信号的同步作用下,扫描坐标定位到左上角第一个像素点坐标;
- 自左上角(第一行)第一个像素点坐标,逐个像素点向右扫描;
- 扫描到第一行最后一个数据,一行图像扫描完成,进行图像消隐,扫描坐标转移到第二行行首;
- 重复若干次扫描至最后一行行尾,一帧图像扫描完成,进行图像消隐,扫描坐标跳转回到左上角第一行行首(图中对角线箭头),开始下一帧图像的扫描。在扫描的过程中会对每一个像素点进行单独赋值,使每个像素点显示对应色彩信息,当一帧图像扫描结束后, 开始下一帧图像的扫描,循环往复,当扫描速度足够快,加之人眼的视觉暂留特性,我们会看到一幅完整的图片,而不是一个个闪烁的像素点。这就是VGA 显示的原理。
VGA时序标准
VGA 时序由两部分构成,行同步时序与场同步时序。
行同步时序
- 一个完整的行扫描周期,包含 6 部分: Sync(同步) 、 Back Porch(后沿) 、 LeftBorder(左边框) 、 “Addressable” Video(有效图像)、 Right Border(右边框)、 FrontPorch(前沿) ,这 6 部分的基本单位是 pixel(像素),即一个像素时钟周期。
- 在一个完整的行扫描周期中, Video 图像信息在 HSync 行同步信号的同步下完成一行图像的扫描显示,Video 图像信息只有在“Addressable” Video(有效图像) 阶段,图像信息有效,其他阶段图像信息无效。
行同步时序
- 一个完整的场扫描周期,也包含 6 部分: Sync(同步)、 Back Porch(后沿)、 TopBorder(上边框)、 “Addressable” Video(有效图像)、 Bottom Border(底边框)FrontPorch(前沿),与行同步信号不同的是,这 6 部分的基本单位是 line(行) ,即一个完整的行扫描周期。
- 在一个完整的场扫描周期中, Video 图像信息在 HSync(行同步信号) 和 VSync(场同步信号) 的共同作用下完成一帧图像的显示, Video 图像信息只有在“Addressable” Video(有效图像)阶段,图像信息有效,其他阶段图像信息无效。
红色区域表示在一个完整的行扫描周期中, Video 图像信息只在此区域有效,
黄色区域表示在一个完整的场扫描周期中,Video 图像信息只在此区域有效,
两者相交的橙色区域, 就是 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_colorbar | 顶层模块 |
clk_gen | 时钟生成模块,生成VGA驱动时钟 |
vga_ctrl | VGA时序控制模块,驱动VGA图像显示 |
vga_pic | 图像数据生成模块,生成VGA待显示图像 |
- 系统上电后,板卡传入系统时钟(sys_clk)和复位信号(sys_rst_n)到顶层模块;
- 系统时钟由顶层模块传入时钟生成模块(clk_gen),分频产生 VGA 工作时钟(vga_clk),作为图像数据生成模块(vga_pic)和 VGA 时序控制模块(vga_ctrl)的工作时钟;
- 图像数据生成模块以 VGA 时序控制模块传入的像素点坐标(pix_x,pix_y)为约束条件,生成待显示彩条图像的色彩信息(pix_data);
- 图像数据生成模块生成的彩条图像色彩信息传入 VGA 时序控制模块,在模块内部使用使能信号滤除掉非图像显示有效区域的图像数据,产生 RGB 色彩信息(rgb),在行、场同步信号(hsync、 vsync)的同步作用下,将 RGB 色彩信息扫描显示到VGA 显示器,显示出彩条图像。
时钟生成模块
调用 IP 核 实现时钟分频。
信号 | 位宽 | 类型 | 功能描述 |
---|---|---|---|
areset | 1Bit | Input | 复位信号,高电平有效 |
inclk0 | 1Bit | Input | 50MHz晶振时钟输入 |
c0 | 1Bit | Output | 输出分频后25MHzVGA工作时钟 |
locked | 1Bit | Output | 输出稳定时钟信号的指示信号 |
VGA 时序控制模块
信号 | 位宽 | 类型 | 功能描述 |
---|---|---|---|
vga_clk | 1Bit | Input | 工作时钟,频率25MHz |
sys_rst_n | 1Bit | Input | 复位信号,低电平有效 |
pi_data | 16Bit | Input | 彩条图像像素点色彩信息 |
pix_x | 10Bit | Output | VGA有效显示区域像素点X轴坐标 |
pix_y | 10Bit | Output | VGA有效显示区域像素点Y轴坐标 |
hsync | 1Bit | Output | 行同步信号 |
vsync | 1Bit | Output | 场同步信号 |
rgb | 16Bit | Output | RGB图像色彩信息 |
波形绘制
程序代码
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)