协议——VGA

  VGA(Video Graphics Array)是IBM在1987年随PS/2机一起推出的一种视频传输标准,具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域得到了广泛的应用。不支持热插拔,不支持音频传输。对于一些嵌入式VGA显示系统,可以在不使用VGA显示卡和计算机的情况下,实现VGA图像的显示和控制。VGA显示器具有成本低、结构简单、应用灵活的优点。对于一名FPGA工程师,尤其是视频图像的方向的学习者,VGA协议是必须要掌握的。

 

一、外部接口

协议——VGA_第1张图片

协议——VGA_第2张图片

  由电路图可以看到,VGA并没有特殊的外部芯片,我们需要关注的其实只有5个信号:HS行同步信号,VS场同步信号,R红基色,G绿基色,B蓝基色。下面慢慢解释这些信号。

 

二、色彩原理

  经过九年义务教育的我们都应该听过三基色,还给老师了的那就在再复习一下。三基色是指通过其他颜色的混合无法得到的“基本色”由于人的肉眼有感知红、绿、蓝三种不同颜色的锥体细胞,因此色彩空间通常可以由三种基本色来表达。这是色度学的最基本原理,即三基色原理。三种基色是相互独立的,任何一种基色都不能有其它两种颜色合成。红绿蓝是三基色,这三种颜色合成的颜色范围最为广泛。我们的RGB信号真是三基色的运用,对这三个信号赋予不同的数值,混合起来便是不同的色彩。

协议——VGA_第3张图片

  设计RGB信号时,既可以R信号、G信号和B信号独立的赋值,最后连到端口上,也可以直接用RGB当做一个整体信号,RGB信号在使用时的位宽有三种常见格式,以你的VGA解码芯片的配置有关。

  1. RGB_8,R:G:B = 3:3:2,即RGB332

  2. RGB_16,R:G:B = 5:6:5,即RGB565

  3. RGB_24,R:G:B = 8:8:8,即RGB888

 

三、扫描方式

  VGA显示器扫描方式分为逐行扫描和隔行扫描:逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。隔行扫描是指电子束扫描时每隔一行扫一线,完成一屏后在返回来扫描剩下的线,隔行扫描的显示器闪烁的厉害,会让使用者的眼睛疲劳。因此我们一般都采用逐行扫描的方式。

  扫描原理如下所示:

协议——VGA_第4张图片

 

四、行场信号

 协议——VGA_第5张图片

  一开始看这个时序图可能看不懂,它是把行场信号绘制在同一张图里,说明行场信号的控制是相似的,只是时间参数不一样而已。如果展开的话,其实时序是这样的:

协议——VGA_第6张图片

  这样就清楚了,大致是若干个HS信号才组合而成一个VS,如果在一副图片中,那正确的时序表示方式应该如下图这样。

协议——VGA_第7张图片

  现在稍稍解释一下这些参数。SYNC是“信号同步”,Back proch和Left border常常加在一起称为“显示后沿”,Addressable video为“显示区域”,Right porder和Front porch常常加在一起称为“显示前沿”,一个时序其实就是先拉高一段较短的“信号同步”时间,然后拉低一段很长的时间,这就是一个回合。同时需要注意,其实也可以完全相反。即先拉低一段时间“信号同步”时间,然后拉高一段很长的时间。

  具体这些时间参数是怎么来的呢?且看下文。

 

五、规格参数

  直接拿数据手册说话!

协议——VGA_第8张图片

协议——VGA_第9张图片

协议——VGA_第10张图片

  以上是常用的几种规格参数表,对着这些表即可确定时间。如果为了嫌麻烦,也可以先计算好写在代码里。下面是我弄好的代码参数,需要用什么规格就用什么,其他注释掉即可。

 1 //640x480 @60 25Mhz -------------------------
 2 parameter H_TOTAL          = 800            ; //行扫描周期
 3 parameter H_SYNC           = 96             ; //行同步
 4 parameter H_BACK           = 48             ; //行显示后沿
 5 parameter H_DISP           = 640            ; //行有效数据
 6 parameter H_FRONT          = 16             ; //行显示前沿
 7 parameter V_TOTAL          = 525            ; //场扫描周期
 8 parameter V_SYNC           = 2              ; //场同步
 9 parameter V_BACK           = 33             ; //场显示后沿
10 parameter V_DISP           = 480            ; //场有效数据
11 parameter V_FRONT          = 10             ; //场显示前沿
12 /*
13 //800x600 @60 40Mhz -------------------------
14 parameter H_TOTAL          = 1056           ; //行扫描周期
15 parameter H_SYNC           = 128            ; //行同步
16 parameter H_BACK           = 88             ; //行显示后沿
17 parameter H_DISP           = 800            ; //行有效数据
18 parameter H_FRONT          = 40             ; //行显示前沿
19 parameter V_TOTAL          = 628            ; //场扫描周期
20 parameter V_SYNC           = 4              ; //场同步
21 parameter V_BACK           = 23             ; //场显示后沿
22 parameter V_DISP           = 600            ; //场有效数据
23 parameter V_FRONT          = 1              ; //场显示前沿
24 
25 //1280x960 @60 108Mhz -----------------------
26 parameter H_TOTAL          = 1800           ; //行扫描周期
27 parameter H_SYNC           = 112            ; //行同步
28 parameter H_BACK           = 312            ; //行显示后沿
29 parameter H_DISP           = 1280           ; //行有效数据
30 parameter H_FRONT          = 96             ; //行显示前沿
31 parameter V_TOTAL          = 1000           ; //场扫描周期
32 parameter V_SYNC           = 3              ; //场同步
33 parameter V_BACK           = 36             ; //场显示后沿
34 parameter V_DISP           = 960            ; //场有效数据
35 parameter V_FRONT          = 1              ; //场显示前沿
36 */

 

六、实例讲解

  最近使用的开发板带了一个TFT屏,分辨率为480x272,其显示原理和VGA接口完全相同,因此拿这个屏幕编写一段程序看看。

  1 //==========================================================================
  2 // --- 名称 : TFT_driver.v
  3 // --- 作者 : xianyu_FPGA
  4 // --- 日期 : 2019-01-03
  5 // --- 描述 : TFT显示屏控制器,分辨率480x272,显示三个竖着的彩条
  6 //==========================================================================
  7 
  8 module TFT_driver
  9 //=====================<端口声明>===========================================
 10 (
 11 //input -------------------------------------
 12 input  wire             clk                 , //时钟,9Mhz
 13 input  wire             rst_n               , //复位,低电平有效
 14 //user interfaces ---------------------------
 15 output wire             TFT_req             , //输出请求信号
 16 input  wire [15:0]      data                , //得到图像数据
 17 //output ------------------------------------
 18 output wire             TFT_clk             , //TFT像素时钟
 19 output wire             TFT_de              , //TFT使能
 20 output wire             TFT_pwm             , //TFT背光控制
 21 output wire             TFT_hsync           , //TFT行同步信号
 22 output wire             TFT_vsync           , //TFT场同步信号
 23 output reg  [15:0]      TFT_rgb               //TFT像素输出
 24 );
 25 //=====================<参数定义>===========================================
 26 //480x272 @60 9Mhz --------------------------
 27 parameter H_TOTAL       = 525               ; //行扫描周期
 28 parameter H_SYNC        = 41                ; //行同步
 29 parameter H_BACK        = 2                 ; //行显示后沿
 30 parameter H_DISP        = 480               ; //行有效数据
 31 parameter H_FRONT       = 2                 ; //行显示前沿
 32 parameter V_TOTAL       = 286               ; //场扫描周期
 33 parameter V_SYNC        = 10                ; //场同步
 34 parameter V_BACK        = 2                 ; //场显示后沿
 35 parameter V_DISP        = 272               ; //场有效数据
 36 parameter V_FRONT       = 2                 ; //场显示前沿
 37 
 38 //=====================<信号定义>===========================================
 39 //行场信号
 40 reg  [9:0]              cnt_h               ;
 41 wire                    add_cnt_h           ;
 42 wire                    end_cnt_h           ;
 43 reg  [9:0]              cnt_v               ;
 44 wire                    add_cnt_v           ;
 45 wire                    end_cnt_v           ;
 46 reg                     TFT_en              ;
 47 wire                    red_area            ;
 48 wire                    green_area          ;
 49 wire                    blue_area           ;
 50 
 51 //--------------------------------------------------------------------------
 52 //--   行、场计数
 53 //--------------------------------------------------------------------------
 54 always @(posedge clk or negedge rst_n) begin
 55     if(!rst_n)
 56         cnt_h <= 0;
 57     else if(add_cnt_h) begin
 58         if(end_cnt_h)
 59             cnt_h <= 0;
 60         else
 61             cnt_h <= cnt_h + 1;
 62     end
 63     else
 64         cnt_h <= cnt_h;
 65 end
 66 
 67 assign add_cnt_h = 1;
 68 assign end_cnt_h = add_cnt_h && cnt_h==H_TOTAL-1;
 69 
 70 always @(posedge clk or negedge rst_n) begin 
 71     if(!rst_n)
 72         cnt_v <= 0;
 73     else if(add_cnt_v) begin
 74         if(end_cnt_v)
 75             cnt_v <= 0;
 76         else
 77             cnt_v <= cnt_v + 1;
 78     end
 79     else
 80         cnt_v <= cnt_v;
 81 end
 82 
 83 assign add_cnt_v = end_cnt_h;
 84 assign end_cnt_v = add_cnt_v && cnt_v==V_TOTAL-1;
 85 
 86 //--------------------------------------------------------------------------
 87 //--    TFT请求信号和使能信号,注意时序的对齐
 88 //--------------------------------------------------------------------------
 89 assign TFT_req = (cnt_h >= H_SYNC + H_BACK - 1) && (cnt_h < H_SYNC + H_BACK + H_DISP - 1) &&
 90                  (cnt_v >= V_SYNC + V_BACK    ) && (cnt_v < V_SYNC + V_BACK + V_DISP    )
 91                  ? 1 : 0;
 92 
 93 always @(posedge clk) begin
 94     TFT_en <= TFT_req;
 95 end
 96 
 97 //--------------------------------------------------------------------------
 98 //--   行场信号
 99 //--------------------------------------------------------------------------
100 assign TFT_hsync = (cnt_h < H_SYNC) ? 0 : 1;
101 assign TFT_vsync = (cnt_v < V_SYNC) ? 0 : 1;
102 
103 //--------------------------------------------------------------------------
104 //--    其他信号
105 //--------------------------------------------------------------------------
106 assign TFT_clk = clk;
107 assign TFT_de  = TFT_en;
108 assign TFT_pwm = rst_n;
109 
110 //--------------------------------------------------------------------------
111 //--   rgb信号
112 //--------------------------------------------------------------------------
113 //assign TFT_rgb = TFT_en ? data : 0;
114 
115 always @(*) begin
116     if(TFT_en) begin
117 
118         if(red_area) begin                      //红色区域
119             TFT_rgb <= 16'b11111_000000_00000;
120         end
121         else if(green_area) begin               //绿色区域
122             TFT_rgb <= 16'b00000_111111_00000;
123         end
124         else if(blue_area) begin                //蓝色区域
125             TFT_rgb <= 16'b00000_000000_11111;
126         end
127         
128     end
129     else begin                                  //非显示区域
130         TFT_rgb <= 0;
131     end
132 end
133 
134 
135 assign red_area   = cnt_h >= (H_SYNC + H_BACK) && cnt_h < (H_SYNC + H_BACK + H_DISP*1/3) && 
136                     cnt_v >= (V_SYNC + V_BACK) && cnt_v < (V_SYNC + V_BACK + V_DISP);
137 assign green_area = cnt_h >= (H_SYNC + H_BACK) && cnt_h < (H_SYNC + H_BACK + H_DISP*2/3) && 
138                     cnt_v >= (V_SYNC + V_BACK) && cnt_v < (V_SYNC + V_BACK + V_DISP);
139 assign blue_area  = cnt_h >= (H_SYNC + H_BACK) && cnt_h < (H_SYNC + H_BACK + H_DISP*3/3) && 
140                     cnt_v >= (V_SYNC + V_BACK) && cnt_v < (V_SYNC + V_BACK + V_DISP);
141 
142 
143                     
144                     
145 
146 endmodule

  这个工程还包括顶层top模块,pll分频模块,这些就不展示了。还一点是接口处的user interfaces的信号没有使用到,而是自己通过代码赋的值。工程最终正常运行,显示出从左到右的三个竖彩条,其效果如下所示:

协议——VGA_第11张图片

 

七、后记

  这样只是简单的使用了VGA,最终还是要以显示视频或图像为目标,这就涉及到模块之间的交互问题,下次再总结吧!

 

参考资料:

[1]开源骚客.VGA系列之一:VGA显示驱动篇

[2]NingHeChuan.基于FPGA的VGA显示静态图片

[3]威三学院FPGA教程

[4]袁玉卓, 曾凯锋, 梅雪松. FPGA自学笔记:设计与验证[M]. 北京航空航天出版社, 2017.

转载于:https://www.cnblogs.com/xianyufpga/p/11128817.html

你可能感兴趣的:(嵌入式)