基于FPGA的VGA控制输出显示(使用GM7123高清视频编码芯片)

一、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接口传输到显示器实现。

猜你喜欢

转载自blog.csdn.net/qq_33231534/article/details/108583972