VGA 基础知识

本文详细介绍了VGA接口的工作原理,重点讲解了RGB色彩模型和VGA信号结构,以及如何编写640*480,60Hz的VGA驱动程序。通过实例演示了如何使用PLL生成不同频率时钟并控制RGB输出,适合FPGA设计者和嵌入式开发者学习。
摘要由CSDN通过智能技术生成

VGA(Video Graphics Array) 是视频图像阵列,通常指代VGA接口。就是常见的老式电脑中,主机和显示器相连的带有左右两个螺丝的连接线。虽然现在的显示屏大多已经采用DVI和HDMI方案,但其实VGA在另一个地方还有应用,那就是大屏的LCD。目前4.3寸以上的TFT基本都是VGA接口,这样在完成一个FPGA系统设计时,选择一个VGA接口的TFT用来显示便是最简单方便的方案。

VGA的内部信号

最重要的 5 个信号,分别是R 、G、 B 红绿蓝三色的模拟信号,以及行同步信号和场同步信号。 其他信号一般来说板子自己已经帮我们在内部接好了,我们不用去给它信号。

行和场 就可以类比于 显示屏的 宽和高

如上图所示的这样的VGA接口其实是通过模拟VGA接口连接,计算机内部以数字方式生成图像信息。这里最主要的就是要实现R、G、B 三原色信号的数模转换。

RGB是一种颜色标准,红®、绿(G)、蓝(B)。
其他各种各样的颜色都是用这三个颜色来互相叠加产生的。显示器大都是采用了RGB颜色标准,在显示器上,是通过电子枪打在屏幕的红、绿、蓝三色发光极上来产生色彩的。一般显示器可以显示2^(32)种颜色(理论上)。

电脑屏幕上的所有颜色,都由这红色绿色蓝色三种色光按照不同的比例混合而成的。一组红色绿色蓝色就是一个最小的显示单位。屏幕上的任何一个像素点颜色都可以由一组RGB值来记录和表达。

在电脑中,RGB的所谓“多少”就是指亮度,并使用整数来表示。通常情况下,RGB各有256级亮度,用数字表示为从0、1、2…直到255。

RGB的格式:

对一种颜色进行编码的方法统称为 色彩空间

RGB555:RGB555是一种16位的RGB格式,但是只有用到了5+5+5,剩下的一位其实是没有用到的。R、G、B 每个分量都用5位表示。


RGB565:RGB565使用16位表示一个像素,这16位中的5位用于R,6位用于G,5位用于B。这个比555好在 更加充分利用16位的资源

 

RGB888(也叫RGB24):RGB分量都用8位表示,取值范围为0-255。

RGB444:每个颜色通道用4位来表示,

virtex5用的RGB888。

 

 

 参考:http://t.csdn.cn/7uHis

VGA显示器一般从左上角开始扫描,从左向右逐点扫描,每扫描完一行后,向下移动一行,继续扫描。在这期间,CRT对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有行,形成一帧图片时,用场同步信号进行同步,使扫描回到屏幕的左上角,同时进行消隐,开始下一帧。

完成一行扫描的时间为水平扫描时间,倒数为行频率;完成一帧的扫描时间为垂直扫描时间,倒数为场频率。基本上用场频率来表示显示屏的刷新频率。

当计算设计的FPGA的时钟频率时需要考虑到无效显示区。

行时序/场时序都需要同步脉冲、显示后沿、显示时序段和显示前沿四部分。VGA工业标准显示模式要求:行同步,场同步都为负极性,即同步脉冲要求是负脉冲。

对于我们输入不同的行和场的同步信号,显示器会自动匹配我们的信号 产生图像。但我们的输入应该满足如下的配置。

现在以640*480,60hz编写相应的程序

`timescale 1ns / 1ps

//VGA Format 640*480@60HZ
`define H_ACTIVE		640
`define H_FRONT_PORCH	16
`define H_SYNCH_PULSE			96	
`define H_BACK_PORCH	48	
`define H_TOTAL			( `H_SYNCH_PULSE + `H_BACK_PORCH + `H_ACTIVE + `H_FRONT_PORCH ) 
//800 // pixels

`define V_ACTIVE		480	
`define V_FRONT_PORCH	11	
`define V_SYNCH_PULSE			2	 
`define V_BACK_PORCH	31	
`define V_TOTAL			 (`V_SYNCH_PULSE + `V_BACK_PORCH +  `V_ACTIVE + `V_FRONT_PORCH )	
//524 // lines


module vga_driver(
		input                 pixel_clk       ,
		input                 rst           ,
		output reg            de              ,
		output reg            h_sync          ,
		output reg            v_sync          ,
		output reg	[10:0]      y_cnt           ,
		output reg	[10:0]     x_cnt
);


//=========== 行计数器 ================
always@(posedge pixel_clk)begin
	if(rst)
		x_cnt <= 0;
	else if( x_cnt == (`H_TOTAL-1) )
		x_cnt <= 0;
	else 
		x_cnt <= x_cnt + 1;
end
//========== 场计数器 ==================
always@(posedge pixel_clk)begin
	if(rst)
		y_cnt <= 0;
	else if(x_cnt == (`H_TOTAL-1))begin
		if(y_cnt == (`V_TOTAL - 1) )
			y_cnt <= 0;
		else 
			y_cnt <= y_cnt + 1;
	end
end

//======== 判断输出有效信号 ==========
reg h_en;
always@(posedge pixel_clk)begin	
  
     
	if(x_cnt == (`H_TOTAL-1) )
		h_en <= 1;
	else if(x_cnt == (`H_ACTIVE-1))
		h_en <= 0;
	
end

reg v_en;
always@(posedge pixel_clk)begin
    
	if(x_cnt == (`H_TOTAL-1)) begin
		if(y_cnt == (`V_TOTAL-1) )
			v_en <= 1;
		else if(y_cnt == (`H_ACTIVE-1))
			v_en <= 0;
	end
end

always@(posedge pixel_clk) begin

        de <= v_en & h_en;
 
end
//================ 设置SYN的时间段为低电平================
always@(posedge pixel_clk)begin
    
	if(x_cnt == (`H_ACTIVE+`H_FRONT_PORCH-1))
		h_sync <=0;
	else if(x_cnt == (`H_ACTIVE+`H_FRONT_PORCH+`H_SYNCH_PULSE-1) )
		h_sync <=1;
	
end

always@(posedge pixel_clk)begin
    if(rst)
        v_sync <=1;
    else begin
	if(x_cnt == `H_TOTAL-1) begin
		if(y_cnt == (`V_ACTIVE+`V_FRONT_PORCH-1))
			v_sync <=0;
	    else if(y_cnt == (`V_ACTIVE+`V_FRONT_PORCH+`V_SYNCH_PULSE-1) )
			v_sync <=1;	
		else
		    v_sync<=v_sync;
	end
	else
	   v_sync <=v_sync;
	end
end
    
endmodule

 测试程序:

`timescale 1ns / 1ps
module vga_driver_tb;
reg clk,rst;
wire de;
wire hs,vs;

wire [10:0] x_cnt;
wire [10:0] y_cnt;
    
    
  vga_driver u0(  
   . pixel_clk  (       clk         )     ,
   .rst       (       rst         )    ,
   .de          (       de        )    ,
   .h_sync      (       hs           )    ,
   .v_sync      (       vs         )    ,
   .y_cnt       (       y_cnt          )    ,
   .x_cnt       (       x_cnt          )     
    );
    
always #30 clk=~clk;

initial begin 
clk = 0;
rst = 1;
#100 rst = 0;
end    
endmodule

ise仿真:

使用ise自带的仿真。

看 hs什么时候低电平 什么时候重新拉高,如果是理想情况,一个是x_cnt到达h_active+h_front_porch-1 的时候也就是(640+16)-1=656-1=655的时候拉低,再过h_sync_pause=96 也就是(656+96)-1=752-1=751的时候拉高。

现在写一个顶层模块,同时把RGB颜色输出,但是,在此之前,我们应该给出一个60MHZ的时钟才行,注意,这里的60是根据我们之前讨论的 在不同分辨率下的VGA时序参数那里得到的。此处我们可以用ise自带的时钟IP核来完成时钟频率的转换。

1、DCM实际上就是一个DLL,可以对输入时钟进行相位移动,补偿,产生倍频和分频时钟,但是5以及以后的产品不用了。

2、PLL相对于DCM,除了不能相移时钟,其它的都一样,但是PLL产生时钟的频率比DCM更加精准,而且时钟的jitter也更好。

3、MMCM实际上就是PLL+DCM相移功能的结合体。7系列的FPGA还会在临近I/O部分放置一些PLL,专门给MIG来产生DDR时钟。

这里使用PLL

 这里使用PLL出现了很多问题,一个问题是ERROR:Xst:2035 - Port <clk> has illegal connections. This port is connected to an input buffer and other components.关于这个问题,采取了网上的办法,关掉XST里的IO Buffers。随之会出现io口无缓冲的问题,还有个问题,忘了,和clk有关,最后的解决方法是clk独立的作为一线,然后根据PLL生成60MHZ和33MHZ(本身)时钟,最后XST还是有感叹号,虽然最后编译成功。

top文件:

module top(
        output   [7:0] R,G,B,
        output h_sync,v_sync,
        input clk,rst
    );
    wire clk60M ;
	 wire clk33M;
    wire de ;

	 clock u1 (
    .CLKIN1_IN(clk), 
    .RST_IN(1'b0), 
    .CLKOUT0_OUT(clk60M), 
	 .CLKOUT1_OUT(clk33M),
    .LOCKED_OUT()
    );

    wire [10:0]x_cnt ;
    wire [9:0]y_cnt ;
    
    vga_driver u0(  
   . pixel_clk  (       clk60M         )     ,
   .rst       (       rst         )    ,
   .de          (       de        )    ,
   .h_sync      (       h_sync           )    ,
   .v_sync      (       v_sync         )    ,
   .y_cnt       (       y_cnt          )    ,
   .x_cnt       (       x_cnt          )     
    );
      
      
    reg[3:0] Rr , Gr , Br ;
    always@ (posedge clk33M)
    case ( x_cnt )  //对于x_cnt在不同的位置,我们赋予不同的颜色,就会形成彩条
        80*0 : { Rr , Gr , Br } <={ 8'b00000000  ,  8'b00000000  ,  8'b00000000  } ;
        80*1 : { Rr , Gr , Br } <={ 8'b00000000  ,  8'b00000000  ,  8'b11111111  } ;
        80*2 : { Rr , Gr , Br } <={ 8'b00000000  ,  8'b11111111  ,  8'b00000000  } ;
        80*3 : { Rr , Gr , Br } <={ 8'b00000000  ,  8'b11111111  ,  8'b11111111  } ;
        80*4 : { Rr , Gr , Br } <={ 8'b11111111  ,  8'b00000000  ,  8'b00000000  } ;
        80*5 : { Rr , Gr , Br } <={ 8'b11111111  ,  8'b00000000  ,  8'b11111111  } ;
        80*6 : { Rr , Gr , Br } <={ 8'b11111111  ,  8'b11111111  ,  8'b00000000  } ;
        80*7 : { Rr , Gr , Br } <={ 8'b11111111  ,  8'b11111111  ,  8'b11111111  } ;
    endcase

    assign B = ( de == 0 ) ? 0 : Br ;
    assign G = ( de == 0 ) ? 0 : Gr ;
    assign R = ( de == 0 ) ? 0 : Rr ;
    
    
endmodule

编写约束文件:

# PlanAhead Generated physical constraints 

NET "B[7]" LOC = AD7;
NET "B[6]" LOC = AC7;
NET "B[5]" LOC = AB5;
NET "B[4]" LOC = AA5;
NET "B[3]" LOC = AB7;
NET "B[2]" LOC = AB6;
NET "B[1]" LOC = AC5;
NET "B[0]" LOC = AC4;

# PlanAhead Generated IO constraints 

NET "B[7]" IOSTANDARD = LVCMOS33;
NET "B[6]" IOSTANDARD = LVCMOS33;
NET "B[5]" IOSTANDARD = LVCMOS33;
NET "B[4]" IOSTANDARD = LVCMOS33;
NET "B[3]" IOSTANDARD = LVCMOS33;
NET "B[2]" IOSTANDARD = LVCMOS33;
NET "B[1]" IOSTANDARD = LVCMOS33;
NET "B[0]" IOSTANDARD = LVCMOS33;

# PlanAhead Generated physical constraints 

NET "G[7]" LOC = AE6;
NET "G[6]" LOC = AD6;
NET "G[5]" LOC = Y7;
NET "G[4]" LOC = AA6;
NET "G[3]" LOC = AD5;
NET "G[2]" LOC = AD4;
NET "G[1]" LOC = Y9;
NET "G[0]" LOC = Y8;

# PlanAhead Generated IO constraints 

NET "G[7]" IOSTANDARD = LVCMOS33;
NET "G[6]" IOSTANDARD = LVCMOS33;
NET "G[5]" IOSTANDARD = LVCMOS33;
NET "G[4]" IOSTANDARD = LVCMOS33;
NET "G[3]" IOSTANDARD = LVCMOS33;
NET "G[2]" IOSTANDARD = LVCMOS33;
NET "G[1]" IOSTANDARD = LVCMOS33;
NET "G[0]" IOSTANDARD = LVCMOS33;

# PlanAhead Generated physical constraints 

NET "R[7]" LOC = W11;
NET "R[6]" LOC = Y11;
NET "R[5]" LOC = AG6;
NET "R[4]" LOC = AH5;
NET "R[3]" LOC = V7;
NET "R[2]" LOC = W7;
NET "R[1]" LOC = AF5;
NET "R[0]" LOC = AG5;

# PlanAhead Generated IO constraints 

NET "R[7]" IOSTANDARD = LVCMOS33;
NET "R[6]" IOSTANDARD = LVCMOS33;
NET "R[5]" IOSTANDARD = LVCMOS33;
NET "R[4]" IOSTANDARD = LVCMOS33;
NET "R[3]" IOSTANDARD = LVCMOS33;
NET "R[2]" IOSTANDARD = LVCMOS33;
NET "R[1]" IOSTANDARD = LVCMOS33;
NET "R[0]" IOSTANDARD = LVCMOS33;

# PlanAhead Generated physical constraints 

NET "clk" LOC = AH17;
NET "v_sync" LOC = Y6;
NET "h_sync" LOC = AE7;
NET "rst" LOC = AK6;

# PlanAhead Generated IO constraints 

NET "clk" IOSTANDARD = LVCMOS33;
NET "h_sync" IOSTANDARD = LVCMOS33;
NET "rst" IOSTANDARD = LVCMOS33;
NET "v_sync" IOSTANDARD = LVCMOS33;

 生成bit流下载到板子上,再连接显示器观察。

  • 6
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值