学习笔记:FPGA学习之VGA通信协议

一,VGA基本原理

https://baike.baidu.com/item/VGA/258838?fr=aladdin

二,VGA通信协议

从VGA的时序图中, 可以看出,帧时序和行时序都产生了四部分,帧时序的四个部分分别是:同步脉冲(o),显示后沿(p),显示时序段(q)和显示前沿(r)。其中同步脉冲(o),显示后沿(p)和显示前沿(r)是消隐区,RGB信号无效,屏幕不显示数据。显示数据段(q)是有效数据区。行时序的四个部分是:同步脉冲(a),显示后沿(b),显示时序段(c)和显示前沿(d)。其中同步脉冲(a),显示后沿(b),显示前沿(d)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(c)是有效数据区。

从表中我们可以知道,不同的分辨率,它的时序是不一样的。以800*600@60HZ分辨率为例。HSYNC是用来控制“行时序”,HSYNC的a是拉低128个列像素,b是拉高88个列像素,c是拉高800个列像素,而d是拉高40个列像素,e总共有1056个列像素。VSYNC用来控制“帧时序”,VSYNC的o是拉低4个行像素,p是拉高23个行像素,q是拉高600个行像素,而r是拉高1个行像素,s总共有628个行像素。每帧对应628个行周期(628=4+23+600+1),每显示行包括1056点时钟,可知,时钟频率:628*1056*60约40MHZ。

三,VGA实际应用

(1)VGA显示分辨率为800*600的四种不同颜色的彩条,分别为红,黄,蓝,绿。

(2)功能模块设计

(3)verilog代码

//---------------------------------------------------------------------------
//-- VGA 800*600@60 
//-- VGA_DATA[7:0] red2,red1,red0,green2,green1,green0,blue1,blue0
//-- VGA CLOCK 40MHz.
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//-- Horizonal timing information
//-- Sync pluse   128  a
//-- back porch   88   b
//-- active       800  c
//-- front porch  40   d
//-- All line     1056 e
//-- Vertical timing information
//-- sync pluse   4    o
//-- back porch   23   p
//-- active time  600  q
//-- front porch  1    r
//-- All lines    628  s
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//-- Horizonal timing information
`define HSYNC_A   16'd128  // 128
`define HSYNC_B   16'd216  // 128 + 88
`define HSYNC_C   16'd1016 // 128 + 88 + 800
`define HSYNC_D   16'd1056 // 128 + 88 + 800 + 40
//-- Vertical  timing information
`define VSYNC_O   16'd4    // 4 
`define VSYNC_P   16'd27   // 4 + 23
`define VSYNC_Q   16'd627  // 4 + 23 + 600
`define VSYNC_R   16'd628  // 4 + 23 + 600 + 1
//---------------------------------------------------------------------------

module Vga_Module
(
	//输入端口
	CLK_50M,RST_N,
	//输出端口
	VSYNC,HSYNC,VGA_DATA
);

//---------------------------------------------------------------------------
//--	外部端口声明
//---------------------------------------------------------------------------
input 				CLK_50M;					//时钟的端口,开发板用的50M晶振
input 				RST_N;					//复位的端口,低电平复位
output 				VSYNC;					//VGA垂直同步端口
output 				HSYNC;					//VGA水平同步端口
output  	[ 7:0]	VGA_DATA;				//VGA数据端口

//---------------------------------------------------------------------------
//--	内部端口声明
//---------------------------------------------------------------------------
reg 		[15:0] 	hsync_cnt;				//水平扫描计数器
reg 		[15:0]	hsync_cnt_n;			//hsync_cnt的下一个状态
reg 		[15:0] 	vsync_cnt;				//垂直扫描计数器
reg 		[15:0] 	vsync_cnt_n;			//vsync_cnt的下一个状态
reg 		[ 7:0] 	VGA_DATA;				//RGB端口总线
reg 		[ 7:0] 	VGA_DATA_N;				//VGA_DATA的下一个状态
reg 					VSYNC;					//垂直同步端口	
reg					VSYNC_N;					//VSYNC的下一个状态
reg 					HSYNC;					//水平同步端口
reg					HSYNC_N;					//HSYNC的下一个状态
reg 					vga_data_en;			//RGB传输使能信号		
reg 					vga_data_en_n;			//vga_data_en的下一个状态
	
//时序电路,用来给hsync_cnt寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)									//判断复位
		hsync_cnt <= 16'b0;					//初始化hsync_cnt值
	else
		hsync_cnt <= hsync_cnt_n;			//用来给hsync_cnt赋值
end

//组合电路,水平扫描
always @ (*)
begin
	if(hsync_cnt == `HSYNC_D)				//判断水平扫描时序
		hsync_cnt_n = 16'b0;					//如果水平扫描完毕,计数器将会被清零
	else
		hsync_cnt_n = hsync_cnt + 1'b1;	//如果水平没有扫描完毕,计数器继续累加
end

//时序电路,用来给vsync_cnt寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)									//判断复位
		vsync_cnt <= 16'b0;					//给行扫描赋值
	else
		vsync_cnt <= vsync_cnt_n;			//给行扫描赋值
end

//组合电路,垂直扫描
always @ (*)
begin
	if((vsync_cnt == `VSYNC_R) && (hsync_cnt == `HSYNC_D))//判断垂直扫描时序
		vsync_cnt_n = 16'b0;					//如果垂直扫描完毕,计数器将会被清零
	else if(hsync_cnt == `HSYNC_D)		//判断水平扫描时序
		vsync_cnt_n = vsync_cnt + 1'b1;	//如果水平扫描完毕,计数器继续累加
	else
		vsync_cnt_n = vsync_cnt;			//否则,计数器将保持不变
end

//时序电路,用来给HSYNC寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)									//判断复位
		HSYNC <= 1'b0;							//初始化HSYNC值
	else
		HSYNC <= HSYNC_N;						//用来给HSYNC赋值
end

//组合电路,将HSYNC_A区域置0,HSYNC_B+HSYNC_C+HSYNC_D置1
always @ (*)
begin	
	if(hsync_cnt < `HSYNC_A)				//判断水平扫描时序
		HSYNC_N = 1'b0;						//如果在HSYNC_A区域,那么置0
	else
		HSYNC_N = 1'b1;						//如果不在HSYNC_A区域,那么置1
end

//时序电路,用来给VSYNC寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)									//判断复位
		VSYNC <= 1'b0;							//初始化VSYNC值
	else
		VSYNC <= VSYNC_N;						//用来给VSYNC赋值
end

//组合电路,将VSYNC_A区域置0,VSYNC_P+VSYNC_Q+VSYNC_R置1
always @ (*)
begin	
	if(vsync_cnt < `VSYNC_O)				//判断水平扫描时序
		VSYNC_N = 1'b0;						//如果在VSYNC_O区域,那么置0
	else
		VSYNC_N = 1'b1;						//如果不在VSYNC_O区域,那么置1
end

//时序电路,用来给vga_data_en寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)									//判断复位
		vga_data_en <= 1'b0;					//初始化vga_data_en值
	else
		vga_data_en <= vga_data_en_n;		//用来给vga_data_en赋值
end

//组合电路,判断显示有效区(列像素>216&&列像素<1017&&行像素>27&&行像素<627)
always @ (*)
begin
	if((hsync_cnt > `HSYNC_B && hsync_cnt <`HSYNC_C) && 
		(vsync_cnt > `VSYNC_P && vsync_cnt < `VSYNC_Q))
		vga_data_en_n = 1'b1;				//如果在显示区域就给使能数据信号置1
	else
		vga_data_en_n = 1'b0;				//如果不在显示区域就给使能数据信号置0
end


//时序电路,用来给VGA_DATA寄存器赋值
always @ (posedge CLK_50M or negedge RST_N)
begin
	if(!RST_N)									//判断复位
		VGA_DATA <= 8'h0;						//初始化VGA_DATA值
	else
		VGA_DATA <= VGA_DATA_N;				//用来给VGA_DATA赋值
end

//组合电路,显示彩条,判断区域并根据数据填充颜色
always @ (*)
begin
	if((hsync_cnt > `HSYNC_B) && (hsync_cnt <= `HSYNC_B + 10'd200) && vga_data_en)	
		VGA_DATA_N = 8'hE0;			//红色
	else if((hsync_cnt > `HSYNC_B + 10'd200) && (hsync_cnt <= `HSYNC_B + 10'd400) && vga_data_en)	
		VGA_DATA_N = 8'hFC;			//黄色
	else if((hsync_cnt > `HSYNC_B + 10'd400) && (hsync_cnt <= `HSYNC_B + 10'd600) && vga_data_en)	
		VGA_DATA_N = 8'h03;			//蓝色
	else if((hsync_cnt > `HSYNC_B + 10'd600) && (hsync_cnt <= `HSYNC_B + 10'd800) && vga_data_en)	
		VGA_DATA_N = 8'h1C;			//绿色
	else
		VGA_DATA_N = 8'h00;			//黑色	
end

endmodule

猜你喜欢

转载自blog.csdn.net/Archar_Saber/article/details/82530231