一、VGA原理
1、VGA接口简介
VGA的全称是Video Graphics Array,即视频图形阵列,是一个使用模拟信号进行视频传输的标准。早期的CRT显示器由于设计制造上的原因,只能接收模拟信号输入,因此计算机内部的显卡负责进行数模转换,而VGA接口就是显卡上输出模拟信号的接口。如今液晶显示器虽然可以直接接收数字信号,但是为了兼容显卡上的VGA接口,也大都支持VGA标准。
VGA显示中,FPGA需要产生5个信号分别是:行同步信号HS、场同步信号VS、R、G、B三基色信号。
在VGA视频传输标准中,视频图像被分解为红、绿、蓝三原色信号,经过数模转换之后,在行同步(HSYNC )和场同步(VSYNC)信号的同步下分别在三个独立通道传输。VGA在传输过程中的同步时序分为行时序和场时序。
2、VGA显示原理
VGA显示中,FPGA需要产生5个信号分别是:行同步信号HS、场同步信号VS、R、G、B三基色信号。
三基色颜色编码:
颜色 | 黑 | 蓝 | 紫 | 绿 | 清 | 黄 | 白 |
---|---|---|---|---|---|---|---|
R | 0 | 0 | 1 | 1 | 0 | 0 | 1 |
G | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
B | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
实际上,对于显示器来说,RGB三个信号其实是模拟信号,其电平的高低可以表示颜色的深浅。
扫描时序:
(1)行时序(像素数)
(2)帧时序(行数)
显示规格:
以640*480@60为例,一帧所需要的时间:1s/60=0.017s。 1行所需要的时间:0.017s/525=32.39us 单位‘’元素‘’ 所需要时间:32.39us/800=40.5ns ,所需要的时钟频率为:1s/40.5ns=24.69MHZ 四舍五入取 25MHZ可以满足要求,我所用的FPGA有125MHZ的时钟,故取其五分频即可。
二、VGA模块
此处使用的是小梅哥的VGA显示模块,使用了一个GM7123 3路高清视频编码芯片,该芯片的主要功能是将RGB888的颜色数据转换成模拟的电压信号,然后送到VGA接口的3个R、G、B接口,例如RGB888数据,最后颜色数据就是24位,共有2^24种颜色。当然,这个芯片也适用于RGB565、RGB555、RGB444等图像数据类型。
小梅哥VGA模块如图:
GM7123视频编码芯片主要引出来的端口有以下几个:
R0~R7:红色通道;
G0~G7:绿色通道;
B0~B7:蓝色通道;
clock:输入时钟;
BLK:消影信号。
从VGA接口引出的信号主要有:
VGA_HS:行同步信号;
VGA_VS:帧同步信号。
三、VGA接口设计
1、设计要求
选择640x480像素,60Hz刷新率的帧率,时钟使用25MHz。
2、设计实现
代码实现:
(1)VGA控制模块
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-14 11:06:48
// Revise Data : 2020-09-14 11:06:48
// File Name : VGA_ctrl.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description : VGA控制模块,使用GM7123 3通道高清视频编码电路
module VGA_ctrl(
input clk_25M ,
input rst_n ,
input [23:0] data_in ,
output wire VGA_clk ,//25MHz
output wire[23:0] VGA_RGB ,
output wire VGA_HS ,
output wire VGA_VS ,
output wire VGA_BLK ,
output wire[9:0] hcount ,//VGA行扫描计数器
output wire[9:0] vcount ,//VGA场扫描计数器
output wire dat_act
);
parameter VGA_HS_end = 10'd95,
hdat_begin=10'd143,
hdat_end=10'd783,
hpixel_end=10'd799,
VGA_VS_end=10'd1,
vdat_begin=10'd34,
vdat_end=10'd514,
vline_end=10'd524;
assign VGA_clk = clk_25M;
reg [9:0] hcount_r ;
reg [9:0] vcount_r ;
wire add_hcount ;
wire add_vcount ;
assign hcount = dat_act?(hcount_r-hdat_begin):10'd0;
assign vcount = dat_act?(vcount_r-vdat_begin):10'd0;
assign VGA_BLK = VGA_HS && VGA_VS;
always @(posedge clk_25M or negedge rst_n) begin
if (!rst_n) begin
hcount_r <= 10'd0;
end
else if (add_hcount) begin
hcount_r <= 10'd0;
end
else begin
hcount_r <= hcount_r + 1'b1;
end
end
assign add_hcount = hcount_r==hpixel_end;
always @(posedge clk_25M or negedge rst_n) begin
if (!rst_n) begin
vcount_r <= 10'd0;
end
else if (add_hcount) begin
if (add_vcount) begin
vcount_r <= 10'd0;
end
else begin
vcount_r <= vcount_r + 1'b1;
end
end
end
assign add_vcount = vcount_r==vline_end;
assign dat_act = ((hcount_r>=hdat_begin)&&(hcount_r<hdat_end))
&&((vcount_r>=vdat_begin)&&(vcount_r<vdat_end));
assign VGA_RGB = dat_act ? data_in:24'h000000;
assign VGA_HS = (hcount_r>VGA_HS_end);
assign VGA_VS = (vcount_r>VGA_VS_end);
endmodule
(2)顶层模块
// Company :
// Engineer :
// -----------------------------------------------------------------------------
// https://blog.csdn.net/qq_33231534 PHF's CSDN blog
// -----------------------------------------------------------------------------
// Create Date : 2020-09-14 13:52:17
// Revise Data : 2020-09-14 13:53:18
// File Name : VGA_top.v
// Target Devices : XC7Z015-CLG485-2
// Tool Versions : Vivado 2019.2
// Revision : V1.1
// Editor : sublime text3, tab size (4)
// Description : 通过VGA模块使显示器显示彩条
module VGA_top(
input clk ,
input rst_n ,
output wire VGA_clk ,
output wire[23:0] VGA_RGB ,
output wire VGA_HS ,
output wire VGA_VS ,
output wire VGA_BLK
);
parameter VGA_HS_end = 10'd95;
parameter hdat_begin = 10'd143;
parameter hdat_end = 10'd783;
parameter hpixel_end = 10'd799;
parameter VGA_VS_end = 10'd1;
parameter vdat_begin = 10'd34;
parameter vdat_end = 10'd514;
parameter vline_end = 10'd524;
wire dat_act ;
wire[9:0] hcount ;//VGA行扫描计数器
wire[9:0] vcount ;//VGA场扫描计数器
pll inst_pll (.inclk0(clk), .c0(clk_25M));
VGA_ctrl #(
.VGA_HS_end(VGA_HS_end),
.hdat_begin(hdat_begin),
.hdat_end(hdat_end),
.hpixel_end(hpixel_end),
.VGA_VS_end(VGA_VS_end),
.vdat_begin(vdat_begin),
.vdat_end(vdat_end),
.vline_end(vline_end)
) inst_VGA_ctrl (
.clk_25M (clk_25M),
.rst_n (rst_n),
.data_in (data_in),
.VGA_clk (VGA_clk),
.VGA_RGB (VGA_RGB),
.VGA_HS (VGA_HS),
.VGA_VS (VGA_VS),
.VGA_BLK (VGA_BLK),
.hcount (hcount),
.vcount (vcount),
.dat_act (dat_act)
);
reg [23:0] data_in;
wire clk_25M;
always @(posedge clk_25M or negedge rst_n) begin
if (!rst_n) begin
data_in <= 24'h000000;
end
else if (dat_act) begin
if (hcount<80) begin
data_in <= 24'hffffff;
end
else if (hcount>=80&&hcount<160) begin
data_in <= 24'h0000ff;
end
else if (hcount>=80&&hcount<160) begin
data_in <= 24'hff0000;
end
else if (hcount>=160&&hcount<240) begin
data_in <= 24'hff00ff;
end
else if (hcount>=240&&hcount<320) begin
data_in <= 24'h00ff00;
end
else if (hcount>=400&&hcount<480) begin
data_in <= 24'h00ffff;
end
else if (hcount>=480&&hcount<560) begin
data_in <= 24'hffff00;
end
else if (hcount>=560&&hcount<640) begin
data_in <= 24'hffffff;
end
else begin
data_in <= 24'h000000;
end
end
end
endmodule
测试代码:
`timescale 1ns/1ns
module VGA_ctrl_tb (); /* this is automatically generated */
reg rst_n;
reg clk_25M;
parameter VGA_HS_end = 10'd95;
parameter hdat_begin = 10'd143;
parameter hdat_end = 10'd783;
parameter hpixel_end = 10'd799;
parameter VGA_VS_end = 10'd1;
parameter vdat_begin = 10'd34;
parameter vdat_end = 10'd514;
parameter vline_end = 10'd524;
localparam clk_period = 20;
reg [23:0] data_in;
wire VGA_clk;
wire [23:0] VGA_RGB;
wire VGA_HS;
wire VGA_VS;
wire VGA_BLK;
wire [9:0] hcount;
wire [9:0] vcount;
wire dat_act;
VGA_ctrl #(
.VGA_HS_end(VGA_HS_end),
.hdat_begin(hdat_begin),
.hdat_end(hdat_end),
.hpixel_end(hpixel_end),
.VGA_VS_end(VGA_VS_end),
.vdat_begin(vdat_begin),
.vdat_end(vdat_end),
.vline_end(vline_end)
) inst_VGA_ctrl (
.clk_25M (clk_25M),
.rst_n (rst_n),
.data_in (data_in),
.VGA_clk (VGA_clk),
.VGA_RGB (VGA_RGB),
.VGA_HS (VGA_HS),
.VGA_VS (VGA_VS),
.VGA_BLK (VGA_BLK),
.hcount (hcount),
.vcount (vcount),
.dat_act (dat_act)
);
initial clk_25M = 0;
always #(clk_period/2) clk_25M = ~clk_25M;
initial begin
#2;
rst_n = 0;
data_in = 24'd0;
#(clk_period*20);
rst_n = 1;
#(clk_period*20);
end
always@(posedge clk_25M) begin
if (hcount>0&&vcount>0) begin
data_in <= hcount;
end
else begin
data_in <= 0;
end
end
endmodule
仿真图形:
一帧图像:
一行图像数据:
3、实现结果
四、总结
后期将对OV7670摄像头视频数据通过VGA接口传输到显示器实现。