VGA 显示器扫描方式示意图
(1) 在行、场同步信号的同步作用下,扫描坐标定位到左上角第一个像素点坐标;
(2) 自左上角(第一行)第一个像素点坐标,逐个像素点向右扫描(图中第一个水平方向箭
头);
(3) 扫描到第一行最后一个数据,一行图像扫描完成,进行图像消隐,扫描坐标自第一
行行尾转移到第二行行首(图中第一条虚线);
(4) 重复若干次扫描至最后一行行尾,一帧图像扫描完成,进行图像消隐,扫描坐标跳
转回到左上角第一行行首(图中对角线箭头),开始下一帧图像的扫描。
在扫描的过程中会对每一个像素点进行单独赋值,使每个像素点显示对应色彩信息,
当一帧图像扫描结束后, 开始下一帧图像的扫描,循环往复,当扫描速度足够快,加之人
眼的视觉暂留特性,我们会看到一幅完整的图片,而不是一个个闪烁的像素点。
VESA 标准下的行同步时序图
图中 Video 代表传输的图像信息, HSync 表示行同步信号。 HSync 自上升沿起到下一个上升沿止为一个完整周期,我们称之为行扫描周期。一个完整的行扫描周期,包含 6 部分: Sync(同步) 、 Back Porch(后沿) 、 Left Border(左边框) 、 “Addressable” Video(有效图像)、 Right Border(右边框)、 Front Porch(前沿) ,这 6 部分的基本单位是 pixel(像素),即一个像素时钟周期。在一个完整的行扫描周期中, Video 图像信息在 HSync 行同步信号的同步下完成一图像的扫描显示, Video 图像信息只有在“Addressable” Video(有效图像) 阶段,图像信息有效,其他阶段图像信息无效。HSync 行同步信号在 Sync(同步) 阶段,维持高电平,其他阶段均保持低电平,在下一个行扫描周期的 Sync(同步) 阶段, HSync 行扫描信号会再次拉高,其他阶段拉低,周
而复始
VESA 标准下的场同步时序图
Video 代表传输的图像信息, VSync 表示场同步信号, VSync 自上升沿起到下一个上升沿止为一个完整周期, 我们称之为场扫描周期。一个完整的场扫描周期,也包含 6 部分: Sync(同步)、 Back Porc(后沿)、 TopBorder(上边框)、 “Addressable” Video(有效图像)、 Bottom Border(底边框)、 FrontPorch(前沿),与行同步信号不同的是,这 6 部分的基本单位是 line(行) ,即一个完整的行扫描周期。
在一个完整的场扫描周期中, Video 图像信息在 HSync(行同步信号)和 VSync(场同步信号) 的共同作用下完成一帧图像的显示, Video 图像信息只有在“Addressable” Video(有效图像)阶段,图像信息有效,其他阶段图像信息无效。VSync 行同步信号在 Sync(同步)阶段,维持高电平,其他阶段均保持低电平,完成一个场扫描周期后,进入下一帧图像的扫描
VGA 时序图
图中的红色区域表示在一个完整的行扫描周期中, Video 图像信息只在此区域有效,黄色区域表示在一个完整的场扫描周期中, Video 图像信息只在此区域有效,两者相交的橙色区域, 就是 VGA 图像的最终显示区域
输出RGB、Hsync、Vsync、数据信号,并输出像素点坐标。
module VGA_CTRL(
input wire Clk ,
input wire Rst_n ,
input wire [15:0] Pix_data ,
output wire [15:0] Reb ,
output wire Hsync ,
output wire Vsync ,
output wire [10:0] Pix_x ,
output wire [10:0] Pix_y
);
reg [10:0] cnt_h ; //行同步信号计数器
reg [10:0] cnt_v ; //场同步信号计数器
wire rgb_value ; //像素信息输出有效信号
wire pix_data_reg ; //像素点坐标开始信号
parameter H_SYNC = 11'd96 , //行同步周期
H_BACK = 11'd40 , //行后沿周期
H_LEFT = 11'd8 , //行左边框周期
H_ABLE = 11'd640 , //行有效图像周期数
H_RIGHT = 11'd8 , //行右边框
H_PRONT = 11'd8 , //行前沿
H_TORAL = 11'd800 ; //行总扫描周期
parameter V_SYNC = 11'd2 , //列同步周期
V_BACK = 11'd25 , //列后沿周期
V_LEFT = 11'd8 , //列左边框周期
V_ABLE = 11'd480 , //列有效图像周期数
V_RIGHT = 11'd8 , //列右边框
V_PRONT = 11'd2 , //列前沿
V_TORAL = 11'd525 ; //列总扫描周期
//行同步信号计数器计数
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_h <= 1'b0;
else
if(cnt_h == (H_TORAL - 1'b1))
cnt_h <= 1'b0;
else
cnt_h <= cnt_h + 1'b1;
//列同步计数器计数
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_v <= 1'b0;
else
if((cnt_h == (H_TORAL - 1'b1)) && (cnt_v == (V_TORAL - 1'b1)))
cnt_v <= 1'b0;
else
if(cnt_h == (H_TORAL - 1'b1))
cnt_v <= cnt_v + 1'b1;
else
cnt_v <= cnt_v;
//reb数据输出有效信号rgb_value产生
assign rgb_value = ((cnt_h >= (H_SYNC + H_BACK +H_LEFT)) && (cnt_h < (H_SYNC + H_BACK +H_LEFT + H_ABLE)) &&
(cnt_v >= (V_SYNC + V_BACK +V_LEFT)) && (cnt_v < (V_SYNC + V_BACK +V_LEFT + V_ABLE)));
//输入图像信息请求信号
assign pix_data_reg = ((cnt_h >= (H_SYNC + H_BACK + H_LEFT - 1'b1)) && (cnt_h < (H_SYNC + H_BACK + H_LEFT + H_ABLE - 1'b1)) &&
(cnt_v >= (V_SYNC + V_BACK + V_LEFT)) && (cnt_v < (V_SYNC + V_BACK + V_LEFT + V_ABLE)));
//像素点坐标产生
assign Pix_x = (pix_data_reg)? (cnt_h - (H_SYNC + H_BACK + H_LEFT - 1'b1)) : 11'h7ff;
assign Pix_y = (pix_data_reg)? (cnt_v - (V_SYNC + V_BACK + V_LEFT)) : 11'h7ff;
//行同步信号产生
assign Hsync = (cnt_h <= (H_SYNC - 1'b1))? 1'b1 : 1'b0 ;
//场同步信号产生
assign Vsync = (cnt_v <= (V_SYNC - 1'b1))? 1'b1 : 1'b0 ;
assign Reb = (rgb_value) ? Pix_data : 16'b0 ;
endmodule
使用时序逻辑生成模拟的像素输入数据。仿真17ms一帧。
`timescale 1ns/1ns
`define CLOCK 20
module VGA_CTRL_tb(); //仿真一帧17ms
reg Rst_n ;
reg Clk ;
wire clk_25m ;
wire locked ;
wire sys_rst_n ;
reg [15:0] pix_data ;
wire [15:0] reb ;
wire Hsync ;
wire Vsync ;
wire [10:0] Pix_x ;
wire [10:0] Pix_y ;
initial Clk = 1;
always #(`CLOCK/2) Clk = ~ Clk;
assign sys_rst_n = locked && Rst_n ;
CLK_START CLK_START_inst (
.areset (!Rst_n ),
.inclk0 (Clk ),
.c0 (clk_25m ),
.locked (locked )
);
VGA_CTRL VGA_CTRL_inst(
.Clk (clk_25m ) ,
.Rst_n (sys_rst_n ) ,
.Pix_data (pix_data ) ,
.Reb (reb ) ,
.Hsync (Hsync ) ,
.Vsync (Vsync ) ,
.Pix_x (Pix_x ) ,
.Pix_y (Pix_y )
);
always @(posedge clk_25m or negedge Rst_n)
if(!Rst_n)
pix_data <= 1'b0;
else
if((Pix_x >= 1'b0) && (Pix_x <= 11'd639) && (Pix_y >= 1'b0) && (Pix_y <= 11'd479))
pix_data <= 16'hffff;
else
pix_data <= 1'b0;
initial
begin
Rst_n = 0;
#(`CLOCK*5+1);
Rst_n = 1;
#(`CLOCK+1);
$stop;
end
endmodule
将输入的像素点x的坐标平均分为10等分,依次显示红、橙、黄、绿、青、蓝、紫、黑、白、灰色。
module VGA_PIC(
input wire Clk ,
input wire Rst_n ,
input wire [10:0] Pix_x ,
input wire [10:0] Pix_y ,
output reg [15:0] Pix_data
);
parameter H_VALID = 12'd640 , //行有效数据
V_VALID = 12'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; //灰色
always @(posedge Clk or negedge Rst_n)
if(!Rst_n)
Pix_data <= 1'b0;
else
if((Pix_x >= 1'b0) && (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_COLOR(
input wire Clk ,
input wire Rst_n ,
output wire [15:0] Rgb ,
output wire Hsync ,
output wire Vsync
);
wire clk_25m ;
wire locked ;
wire sys_rst_n ;
wire [15:0] pix_data ;
wire [10:0] Pix_x ;
wire [10:0] Pix_y ;
assign sys_rst_n = locked && Rst_n ;
CLK_START CLK_START_inst (
.areset (!Rst_n ),
.inclk0 (Clk ),
.c0 (clk_25m ),
.locked (locked )
);
VGA_CTRL VGA_CTRL_inst(
.Clk (clk_25m ) ,
.Rst_n (sys_rst_n ) ,
.Pix_data (pix_data ) ,
.Reb (Rgb ) ,
.Hsync (Hsync ) ,
.Vsync (Vsync ) ,
.Pix_x (Pix_x ) ,
.Pix_y (Pix_y )
);
VGA_PIC VGA_PIC_inst(
.Clk (clk_25m) ,
.Rst_n (sys_rst_n) ,
.Pix_x (Pix_x ) ,
.Pix_y (Pix_y ) ,
.Pix_data (pix_data)
);
endmodule
`timescale 1ns/1ns
`define CLOCK 20
module VGA_COLOR_tb();
reg Clk ;
reg Rst_n ;
wire [15:0] Rgb ;
wire Hsync ;
wire Vsync ;
VGA_COLOR VGA_COLOR_inst(
.Clk (Clk),
.Rst_n (Rst_n),
.Rgb (Rgb ),
.Hsync (Hsync ),
.Vsync (Vsync )
);
initial Clk = 1;
always #(`CLOCK/2) Clk = ~ Clk;
initial
begin
Rst_n = 0;
#(`CLOCK*5+1);
Rst_n = 1;
#(`CLOCK*5+1);
$stop;
end
endmodule