VGA显示器成像原理
图像显示的时候,是采用逐行扫描的方式,从左到右,从上到下,每次扫描一个点的时候发送一个数据,然后那个像素点就会把这个数据对应的颜色发送到屏幕上,在每一次回扫的过程中,不能影响屏幕上既有图像的颜色,所以就是消隐信号(BLK)存在的意义,在每次回扫时,消隐信号启动,此时屏幕上没有新的数据输入,也就不会影响原本的颜色,消隐分为场扫描和行扫描。
VGA时序
行扫描:根据上图进行分析,首先需要一个行同步信号,根据这个行同步信号用来指导消隐信号的变化,以及数据的传输,行同步信号(HSYC)的一个周期包含的时间有行同步时间(Sync Pulse)、Back Porch(回扫时间)、Left Border(显示器左侧黑边的扫描的时间)、Visible area(数据传输的有效时间)、Right Border(显示器右侧黑边的扫描的时间)、Front Porch(产生消隐信号用的时间)
场扫描:根据上图进行分析,首先需要一个场同步信号,根据这个场同步信号用来指导消隐信号的变化,以及数据的传输,场同步信号(VSYC)的一个周期包含的时间有场同步时间(Sync Pulse)、Back Porch(回扫时间)、Left Border(显示器左侧黑边的扫描的时间)、Visible area(数据传输的有效时间)、Right Border(显示器右侧黑边的扫描的时间)、Front Porch(产生消隐信号用的时间)
行扫描和场扫描类似,相关点在于每次扫描一行,场即竖直方向上扫描一个点,所以说场扫描时的那个时间其实根据行扫描来变化的。
根据时序来看,其实也就只有在Visible area这个区域是有效的数据传输时间,其他位置数据都不传输,可以直接让消隐信号启动,不输入数据就完事了。
然后对模块的端口分析一下
VGA_HS:就是行同步信号,根据上面所述的时间周期来控制VGA_HS的变化
VGA_VS:就是场同步信号,根据上面所述的时间周期来控制VGA_VS的变化
R/G/B:就是输入的数据(在数据传输的有效时间输入)
CLOCK:VGA模块的驱动时钟,根据不同的像素和刷新频率而不同,具体为多少要查询相关手册
VGA_BLK:消隐信号、根据上面所述的时间周期来控制VGA_HS的变化
上面所述的时间具体为多少呢?也是根据不同的像素而不同,具体为多少要查询相关手册
一、GM7123芯片
在VGA图像显示时,采用的是GM7123芯片
在驱动GM7123时有多种数据传输方式
我采用的是RGB888格式的数据传输。
下面就是VGA驱动模块的程序部分啦,我采用的是1920*1080像素的显示模式,根据下图中参数进行编写
当0时刻时 ,行同步信号为下降沿开始,当44时,行同步信号拉高,当44(行同步信号脉冲时间)+148(H_Back_Porch)+0(H_Left_Border)=192是开始发送有效数据,当192+1920(有效数据时间)=2112时有效数据发送完成,2112+0(H_Right_Borde)+88(H_Front_Porch)=2200时,一个周期结束。只有在有效数据发送时,才不会启动消隐信号,其余时间不发送数据,可以让消隐信号始终有效。
场同步信号和行同步信号类似,但是要注意,只有扫描完一行时,场同步信号才会+1。
module VGA_CTRL(
clk,
Rst_n,
data_in,
Hcounter,
Vcounter,
VGA_HS,
VGA_VS,
VGA_BLK,
VGA_RGB
);
input clk;
input Rst_n;
input [23:0] data_in;
output [11:0] Hcounter;
output [10:0] Vcounter;
output reg VGA_HS;
output reg VGA_VS;
output reg VGA_BLK;
output [23:0] VGA_RGB;
reg [11:0] Hcnt;
reg [10:0] Vcnt;
parameter HS_End = 44;
parameter VS_End = 5;
parameter Hdata_Begin = 192;
parameter Vdata_Begin = 41;
parameter Hdata_End = 2112;
parameter Vdata_End = 1121;
parameter Hsync_End = 2200;
parameter Vsync_End = 1125;
//行扫描计数器
always @ (posedge clk or negedge Rst_n)
if(!Rst_n)
Hcnt<=12'd0;
else if (Hcnt == Hsync_End - 1)
Hcnt<=12'd0;
else Hcnt<=Hcnt+1'b1;
//场扫描计数器
always @ (posedge clk or negedge Rst_n)
if(!Rst_n)
Vcnt<=11'd0;
else if(Hcnt == Hsync_End - 1)
begin
if (Vcnt == Vsync_End - 1)
Vcnt<=11'd0;
else Vcnt<=Vcnt+1'b1;
end
//行同步信号赋值
always @ (posedge clk or negedge Rst_n)
if(!Rst_n)
VGA_HS<=1'b0;
else if (Hcnt >= HS_End)
VGA_HS<=1'b1;
else VGA_HS<=1'b0;
//场同步信号赋值
always @ (posedge clk or negedge Rst_n)
if(!Rst_n)
VGA_VS<=1'b0;
else if (Vcnt >= VS_End)
VGA_VS<=1'b1;
else VGA_VS<=1'b0;
//消隐信号的赋值
always @ (posedge clk or negedge Rst_n)
if(!Rst_n)
VGA_BLK<=1'b0;
else if(Hcnt > Hdata_Begin-1 && Hcnt<= Hdata_End-1 && Vcnt>Vdata_Begin-1 && Vcnt<=Vdata_End-1)
VGA_BLK<=1'b1;
else VGA_BLK<=1'b0;
//RGB赋值
assign VGA_RGB=(VGA_BLK == 1'b1)?data_in:24'd0;
//像素横坐标
assign Hcounter=(VGA_BLK == 1'b1)? (Hcnt - 12'd192-1'b1): 12'd0;
//像素纵坐标
assign Vcounter=(VGA_BLK == 1'b1)? (Vcnt - 11'd41) : 11'd0;
endmodule
注意这里的驱动模块多了两个端口,Hcounter和Vcounter引出这两个输出是为了方便根据有效数据时段的像素点赋值。
下面就是做的四个小小的简单小实验
彩条显示实验
彩条显示时将屏幕分成八等分,每一块显示不同的颜色
代码如下
module VGA_display(
clk,
Rst_n,
VGA_Clk,
VGA_HS,
VGA_VS,
VGA_BLK,
VGA_RGB
);
input clk;
input Rst_n;
output VGA_Clk;
output VGA_HS;
output VGA_VS;
output VGA_BLK;
output [23:0] VGA_RGB;
reg [23:0] data_in;
wire [11:0] Hcounter;
wire [10:0] Vcounter;
wire H0,H1,V0,V1,V2,V3;
//颜色设置
parameter BLACK = 24'h000000, //黑色
BLUE = 24'h0000FF, //蓝色
RED = 24'hFF0000, //红色
PURPPLE = 24'hFF00FF, //紫色
GREEN = 24'h00FF00, //绿色
CYAN = 24'h00FFFF, //青色
YELLOW = 24'hFFFF00, //黄色
WHITE = 24'hFFFFFF; //白色
//像素块设置
assign H0 =(Hcounter>= 12'd0 && Hcounter <= 12'd959)? 1'b1:1'b0;
assign H1 =(Hcounter>= 12'd960 && Hcounter <= 12'd1919)? 1'b1:1'b0;
assign V0 =(Vcounter>= 11'd0 && Vcounter <= 11'd269)? 1'b1:1'b0;
assign V1 =(Vcounter>= 11'd270 && Vcounter <= 11'd539)? 1'b1:1'b0;
assign V2 =(Vcounter>= 11'd540 && Vcounter <= 11'd809)? 1'b1:1'b0;
assign V3 =(Vcounter>= 11'd810 && Vcounter <= 11'd1079)? 1'b1:1'b0;
VGA_CLOCK VGA_CLOCK(
.inclk0(clk),
.c0(VGA_Clk)
);
VGA_CTRL VGA_CTRL(
.clk(VGA_Clk),
.Rst_n(Rst_n),
.data_in(data_in),
.Hcounter(Hcounter),
.Vcounter(Vcounter),
.VGA_HS(VGA_HS),
.VGA_VS(VGA_VS),
.VGA_BLK(VGA_BLK),
.VGA_RGB (VGA_RGB)
);
always @ (*)
case({H0,H1,V0,V1,V2,V3})
6'b101000:data_in=BLACK;
6'b100100:data_in=RED;
6'b100010:data_in=GREEN;
6'b100001:data_in=YELLOW;
6'b011000:data_in=BLUE;
6'b010100:data_in=PURPPLE;
6'b010010:data_in=CYAN;
6'b010001:data_in=WHITE;
default:data_in=BLACK;
endcase
endmodule
方块移动实验