VGA(Video Grapghics Array),是一种使用模型信号进行视频传输的标准协议。这里使用的是RGB565图像模式
VGA显示原理
VGA 显示器显示图像,并不是直接让图像在显示器上显示出来,而是采用扫描的方式,将构成图像的像素点,在行同步信号和场同步信号的同步下,按照从上到下、由左到右的顺序扫描到显示屏上。
在行场同步信号作用下,扫描坐标定位到左上角第一个像素点坐标。在扫面的过程中会对每一个像素点进行单独赋值,使每个像素点显示对应色彩信息,当一帧图像扫描结束后,开始下一帧图像的扫描,循环往复,当扫面速度足够快,加上人的视觉暂留特性,就会显示完整的图像。
VGA的时序标准
VGA时序由两部分构成,行同步时序和场同步时序。行同步时序如下图所示。
行扫面周期分为六个部分,同步、后沿、左边框、有效图像、右边框、前沿。场扫描周期也差不多,只不过是上边框和底边框。当完成扫面之后,图像只会出现在行场有效图像范围内。
VGA参数设置
上图为VGA显示模式之一,640×480@60。640表示行有效图像的像素点个数为640个,480则表示场有效图像像素点个数。60是指VGA显示器每秒刷新图像60次,即显示帧数为60。650×480=307200,即每一帧图像包含了307200个像素点。该显示模式下的工作时钟为25.175MHz。时钟周期等于行扫描周期×场扫描周期×刷新率。
程序设计
整体设计框图如下图所示。
时钟生成模块(PLL):用来生成VGA工作的时钟。
图像生成模块(VGA_P):通过控制模块传入的坐标信号,来确定每个有效图像区的像素点。输入图像信息。图像数据生成模块以 VGA 时序控制模块传入的像素点坐标(pix_x,pix_y)为约束条
件,生成待显示彩条图像的色彩信息(pix_data)
图像控制模块(VGA_C):更长行场同步信号,找出有效图像区域并且指定零点坐标。输入RGB信息和行场同步信号。
图像控制模块代码
module VGA_C
(
input wire vga_clk , //输入工作时钟,频率25MHz
input wire sys_rst_n , //输入复位信号,低电平有效
input wire [15:0] pix_data , //输入像素点色彩信息
output wire [9:0] pix_x , //输出VGA有效显示区域像素点X轴坐标
output wire [9:0] pix_y , //输出VGA有效显示区域像素点Y轴坐标
output wire hsync , //输出行同步信号
output wire vsync , //输出场同步信号
output wire [15:0] 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 ; //场扫描周期
wire rgb_valid ; //VGA有效显示区域
wire pix_data_req ; //像素点色彩信息请求信号
reg [9:0] cnt_h ; //行同步信号计数器
reg [9:0] cnt_v ; //场同步信号计数器
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'd1)
cnt_h <= 10'd0 ;
else
cnt_h <= cnt_h + 1'd1 ;
assign hsync = (cnt_h <= H_SYNC - 1'd1) ? 1'b1 : 1'b0 ;
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'd1) && (cnt_h == H_TOTAL-1'd1))
cnt_v <= 10'd0 ;
else if(cnt_h == H_TOTAL - 1'd1)
cnt_v <= cnt_v + 1'd1 ;
else
cnt_v <= cnt_v ;
assign vsync = (cnt_v <= V_SYNC - 1'd1) ? 1'b1 : 1'b0 ;
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)
&& (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;
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;
//rgb:输出像素点色彩信息
assign rgb = (rgb_valid == 1'b1) ? pix_data : 16'b0 ;
endmodule
图像生成模块代码
module VGA_P
(
input wire vga_clk , //输入工作时钟,频率25MHz
input wire sys_rst_n , //输入复位信号,低电平有效
input wire [9:0] pix_x , //输入VGA有效显示区域像素点X轴坐标
input wire [9:0] pix_y , //输入VGA有效显示区域像素点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
顶层模块
module VGA
(
input wire sys_clk , //输入工作时钟,频率50MHz
input wire sys_rst_n , //输入复位信号,低电平有效
output wire hsync , //输出行同步信号
output wire vsync , //输出场同步信号
output wire [15:0] 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像素点色彩信息
assign rst_n = (sys_rst_n & locked);
clk_gen clk_gen_inst
(
.areset (~sys_rst_n ), //输入复位信号,高电平有效,1bit
.inclk0 (sys_clk ), //输入50MHz晶振时钟,1bit
.c0 (vga_clk ), //输出VGA工作时钟,频率25Mhz,1bit
.locked (locked ) //输出pll locked信号,1bit
);
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
.rgb (rgb ) //输出像素点色彩信息,16bit
);
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
仿真结果
每秒刷新六十次,每次大概16.6666ms,如上图所示。