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

一、外部接口

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

二、色彩原理

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

  设计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对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。隔行扫描是指电子束扫描时每隔一行扫一线,完成一屏后在返回来扫描剩下的线,隔行扫描的显示器闪烁的厉害,会让使用者的眼睛疲劳。因此我们一般都采用逐行扫描的方式。

  扫描原理如下所示:

四、行场信号

 

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

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

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

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

五、规格参数

  直接拿数据手册说话!

  以上是 640x480 @60Hz 的规格参数表,对着这个表即可确定时间。如果为了嫌麻烦,也可以先计算好写在代码里。

  1. //**************************************************************************
  2. // *** 名称 : VGA_driver.v
  3. // *** 作者 : xianyu_FPGA
  4. // *** 博客 : https://www.cnblogs.com/xianyufpga/
  5. // *** 日期 : 2019-06-26
  6. // *** 描述 : VGA驱动模块,pixel_req和pixel_x、pixel_y信号一般不同时使用
  7. //**************************************************************************
  8.  
  9. module VGA_driver
  10. //========================< 端口 >==========================================
  11. (
  12. //system ----------------------------------------
  13. input wire clk , //时钟,25Mhz
  14. input wire rst_n , //复位,低电平有效
  15. //vga_display -----------------------------------
  16. input wire [:] pixel_data , //得到图像数据
  17. output wire pixel_req , //请求图像数据
  18. output wire [ :] pixel_x , //请求显示区域横坐标
  19. output wire [ :] pixel_y , //请求显示区域纵坐标
  20. //vga output ------------------------------------
  21. output reg vga_de , //VGA接口使能
  22. output wire vga_hsync , //VGA接口行信号
  23. output wire vga_vsync , //VGA接口场信号
  24. output wire [:] vga_data //VGA接口rgb数据信号
  25. );
  26. //========================< 参数 >==========================================
  27. //640x480 @60Hz 25Mhz -----------------------------------------
  28. parameter H_TOTAL = ; //行扫描周期
  29. parameter H_ADDR = ; //行有效数据
  30. parameter H_RIGHT_BORDER = ;
  31. parameter H_FRONT_PORCH = ;
  32. parameter H_FRONT = H_RIGHT_BORDER + H_FRONT_PORCH ; //行显示前沿
  33. parameter H_SYNC = ; //行同步
  34. parameter H_BACK_PORCH = ;
  35. parameter H_LEFT_BORDER = ;
  36. parameter H_BACK = H_BACK_PORCH + H_LEFT_BORDER ; //行显示后沿
  37. //-------------------------------------------------------------
  38. parameter V_TOTAL = ; //场扫描周期
  39. parameter V_ADDR = ; //场有效数据
  40. parameter V_BOTTOM_BORDER = ;
  41. parameter V_FRONT_PORCH = ;
  42. parameter V_FRONT = V_BOTTOM_BORDER + V_FRONT_PORCH ; //场显示前沿
  43. parameter V_SYNC = ; //场同步
  44. parameter V_BACK_PORCH = ;
  45. parameter V_TOP_BORDER = ;
  46. parameter V_BACK = V_BACK_PORCH + V_TOP_BORDER ; //场显示后沿
  47. //========================< 信号 >==========================================
  48. reg [ :] cnt_h ;
  49. wire add_cnt_h ;
  50. wire end_cnt_h ;
  51. reg [ :] cnt_v ;
  52. wire add_cnt_v ;
  53. wire end_cnt_v ;
  54. //==========================================================================
  55. //== 行、场计数
  56. //==========================================================================
  57. always @(posedge clk or negedge rst_n) begin
  58. if(!rst_n)
  59. cnt_h <= ;
  60. else if(add_cnt_h) begin
  61. if(end_cnt_h)
  62. cnt_h <= ;
  63. else
  64. cnt_h <= cnt_h + ;
  65. end
  66. end
  67.  
  68. assign add_cnt_h = ;
  69. assign end_cnt_h = add_cnt_h && cnt_h==H_TOTAL-;
  70.  
  71. always @(posedge clk or negedge rst_n) begin
  72. if(!rst_n)
  73. cnt_v <= ;
  74. else if(add_cnt_v) begin
  75. if(end_cnt_v)
  76. cnt_v <= ;
  77. else
  78. cnt_v <= cnt_v + ;
  79. end
  80. end
  81.  
  82. assign add_cnt_v = end_cnt_h;
  83. assign end_cnt_v = add_cnt_v && cnt_v==V_TOTAL-;
  84. //==========================================================================
  85. //== VGA display
  86. //==========================================================================
  87. //vga请求
  88. assign pixel_req = (cnt_h >= H_SYNC + H_BACK - ) && (cnt_h < H_SYNC + H_BACK + H_ADDR - ) &&
  89. (cnt_v >= V_SYNC + V_BACK ) && (cnt_v < V_SYNC + V_BACK + V_ADDR )
  90. ? : ;
  91. //vga坐标
  92. assign pixel_x = pixel_req ? (cnt_h - (H_SYNC + H_BACK - 'b1)) : 10'd0;
  93. assign pixel_y = pixel_req ? (cnt_v - (V_SYNC + V_BACK - 'b1)) : 10'd0;
  94. //==========================================================================
  95. //== VGA output
  96. //==========================================================================
  97. always @(posedge clk) begin
  98. vga_de <= pixel_req;
  99. end
  100.  
  101. assign vga_hsync = (cnt_h < H_SYNC) ? : ;
  102. assign vga_vsync = (cnt_v < V_SYNC) ? : ;
  103.  
  104. assign vga_data = vga_de ? pixel_data : 'b0;
  105.  
  106. endmodule

六、实例讲解

  最近使用的开发板带了一个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 [:] 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 [:] TFT_rgb //TFT像素输出
  24. );
  25. //=====================<参数定义>===========================================
  26. //480x272 @60 9Mhz --------------------------
  27. parameter H_TOTAL = ; //行扫描周期
  28. parameter H_ADDR = ; //行有效数据
  29. parameter H_FRONT = ; //行显示前沿
  30. parameter H_SYNC = ; //行同步
  31. parameter H_BACK = ; //行显示后沿
  32. parameter V_TOTAL = ; //场扫描周期
  33. parameter V_ADDR = ; //场有效数据
  34. parameter V_FRONT = ; //场显示前沿
  35. parameter V_SYNC = ; //场同步
  36. parameter V_BACK = ; //场显示后沿
  37.  
  38. //=====================<信号定义>===========================================
  39. //行场信号
  40. reg [:] cnt_h ;
  41. wire add_cnt_h ;
  42. wire end_cnt_h ;
  43. reg [:] 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 <= ;
  57. else if(add_cnt_h) begin
  58. if(end_cnt_h)
  59. cnt_h <= ;
  60. else
  61. cnt_h <= cnt_h + ;
  62. end
  63. end
  64.  
  65. assign add_cnt_h = ;
  66. assign end_cnt_h = add_cnt_h && cnt_h==H_TOTAL-;
  67.  
  68. always @(posedge clk or negedge rst_n) begin
  69. if(!rst_n)
  70. cnt_v <= ;
  71. else if(add_cnt_v) begin
  72. if(end_cnt_v)
  73. cnt_v <= ;
  74. else
  75. cnt_v <= cnt_v + ;
  76. end
  77. end
  78.  
  79. assign add_cnt_v = end_cnt_h;
  80. assign end_cnt_v = add_cnt_v && cnt_v==V_TOTAL-;
  81.  
  82. //--------------------------------------------------------------------------
  83. //-- TFT请求信号和使能信号,注意时序的对齐
  84. //--------------------------------------------------------------------------
  85. assign TFT_req = (cnt_h >= H_SYNC + H_BACK - ) && (cnt_h < H_SYNC + H_BACK + H_ADDR - ) &&
  86. (cnt_v >= V_SYNC + V_BACK ) && (cnt_v < V_SYNC + V_BACK + V_ADDR )
  87. ? : ;
  88.  
  89. always @(posedge clk) begin
  90. TFT_en <= TFT_req;
  91. end
  92.  
  93. //--------------------------------------------------------------------------
  94. //-- 行场信号
  95. //--------------------------------------------------------------------------
  96. assign TFT_hsync = (cnt_h < H_SYNC) ? : ;
  97. assign TFT_vsync = (cnt_v < V_SYNC) ? : ;
  98.  
  99. //--------------------------------------------------------------------------
  100. //-- 其他信号
  101. //--------------------------------------------------------------------------
  102. assign TFT_clk = clk;
  103. assign TFT_de = TFT_en;
  104. assign TFT_pwm = rst_n;
  105.  
  106. //--------------------------------------------------------------------------
  107. //-- rgb信号
  108. //--------------------------------------------------------------------------
  109. //assign TFT_rgb = TFT_en ? data : 0;
  110.  
  111. always @(*) begin
  112. if(TFT_en) begin
  113.  
  114. if(red_area) begin //红色区域
  115. TFT_rgb <= 'b11111_000000_00000;
  116. end
  117. else if(green_area) begin //绿色区域
  118. TFT_rgb <= 'b00000_111111_00000;
  119. end
  120. else if(blue_area) begin //蓝色区域
  121. TFT_rgb <= 'b00000_000000_11111;
  122. end
  123.  
  124. end
  125. else begin //非显示区域
  126. TFT_rgb <= ;
  127. end
  128. end
  129.  
  130. assign red_area = cnt_h >= (H_SYNC + H_BACK) && cnt_h < (H_SYNC + H_BACK + H_ADDR*/) &&
  131. cnt_v >= (V_SYNC + V_BACK) && cnt_v < (V_SYNC + V_BACK + V_ADDR);
  132. assign green_area = cnt_h >= (H_SYNC + H_BACK) && cnt_h < (H_SYNC + H_BACK + H_ADDR*/) &&
  133. cnt_v >= (V_SYNC + V_BACK) && cnt_v < (V_SYNC + V_BACK + V_ADDR);
  134. assign blue_area = cnt_h >= (H_SYNC + H_BACK) && cnt_h < (H_SYNC + H_BACK + H_ADDR*/) &&
  135. cnt_v >= (V_SYNC + V_BACK) && cnt_v < (V_SYNC + V_BACK + V_ADDR);
  136.  
  137. endmodule

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

七、后记

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

参考资料:

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

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

[3]威三学院FPGA教程

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

协议——VGA的更多相关文章

  1. Verilog HDL那些事_建模篇笔记(实验九:VGA驱动)

    1.了解VGA协议 VGA协议有5个输入信号,列同步信号(HSYNC Signal),行同步信号(VSYNC Signal),红-绿-蓝,颜色信号(RGB Signal). 一帧屏幕的显示是由行从上至 ...

  2. 基于FPGA的VGA显示实验设计

    基于FPGA的VGA显示实验设计 成果展示(优酷视频): 视频: 基于FPGA的VGA显示技术(手机控制) http://v.youku.com/v_show/id_XNjk4ODE3ODUy.htm ...

  3. 高清VGA编码器|上海视涛科技

    VGA编码器(E200)简介 高清VGA编码器是上海视涛科技出品的高性能VGA编码产品.该VGA编码器是上海视涛科技完全自主研发,并适用于VGA信号的编码采集及网络传输的专用硬件设备.可兼容各厂家的N ...

  4. VGA DVI HDMI区别

    VGA,DVI,HDMI是目前常用的3种不同显示接口的名称.在树莓派的边缘既有HDMI的接口,也有RCA的接口,而显示器上也是既有DVI,又有VGA.上个月买连接线,没有仔细检查买了一根HDMI对VG ...

  5. HDMI接口与协议

    深入了解HDMI接口 一.HDMI接口的工作原理这张图是HDMI接口的架构示意图.从左边的信号源中你可以看到,HDMI接口的信源可以是任何支持HDMI输出的设备,而接入端也可以是任何带有HDMI输 入 ...

  6. 屏幕分辨率(QQVGA、QVGA、VGA、XGA、WXGA、WUXGA和WSXGA+)

    TFT屏幕 TFT ( Thin Film Transistor 薄膜晶体管) ,是有源矩阵类型液晶显示器(AM-LCD)中的一种,TFT在液晶的背部设置特殊光管,能够“主动的”对屏幕上的各个独立的象 ...

  7. 单色VGA显示verilogHDL通用代码

    今天做VGA,真是拼凑了好久啊.唉,总算完成了. 本来想偷懒移植,最后还是自己写的代码. //2015/12/13 //designer : pengxiaoen //function : vga c ...

  8. VGA、DVI、HDMI、DP 接口介绍及优劣

    VGA.DVI.HDMI.DP 接口介绍及优劣   随着日新月异的发展,就目前显卡上面常见的输出接口而言,我们所熟知的有以下几种: VGA.DVI.HDMI和DP (DisplayPort). 这四种 ...

  9. 基于FPGA的VGA显示设计(一)

    前言 FPGA主要运用于芯片验证.通信.图像处理.显示VGA接口的显示器是最基本的要求了. 原理 首先需要了解 : (1)VGA接口协议:VGA端子_维基百科 .VGA视频传输标准_百度 引脚1 RE ...

随机推荐

  1. 如何防范web前端安全攻击

    一.对于XSS防御: 1.不要信任任何外部传入的数据,针对用户输入作相关的格式检查.过滤等操作,以及转义字符处理.最普遍的做法就是转义输入输出的内容,对于括号,尖括号,斜杠进行转义 function ...

  2. python 判断一个字符串组合后,是否在另一个字符串中

    code #coding=utf- def getdic(s): dic = {} for i in s: if (i not in dic): dic[i] = else: dic[i] += re ...

  3. [HAOI 2018]染色

    传送门 Description 一个长度为\(N\)的序列, 每个位置都可以被染成 \(M\)种颜色中的某一种. 出现次数恰好为 \(S\)的颜色种数有\(i\)种, 会产生\(w_i\)的愉悦度. ...

  4. 多维矩阵转一维数组(c++)【转载】

    在由二维矩阵转为一维数组时,我们有两种方式:以列为主和以行为主. 以列为主的二维矩阵转为一维数组时,转换公式为: index=column+row×行数 以行为主的二维矩阵转为一维数组时,转换公式为: ...

  5. C++之宏、extern关键字与多线程

    理解C++ 宏 1.特殊字符 考虑下面的需求,程序中多处使用文本字符串.我们知道文本字符串前后都要加上双引号,我很讨厌输入双引号.有没有好的办法呢?根据常识,使用下面的宏: #define Str(x ...

  6. 团队作业-Beta版本演示

    组长博客链接 https://www.cnblogs.com/cmlei/p/12063671.html 本组成员 031702431 陈明磊 组长 031702227 林镕炜 031702413 韩 ...

  7. 第09组 Alpha冲刺(4/4)

    队名:软工9组 组长博客:https://www.cnblogs.com/cmlei/ 作业博客:https://edu.cnblogs.com/campus/fzu/SoftwareEngineer ...

  8. PHP cURL 超时设置 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT 的区别

    PHP cURL 的超时设置有两个 CURLOPT_CONNECTTIMEOUT 和 CURLOPT_TIMEOUT,他们的区别是: CURLOPT_CONNECTTIMEOUT 用来告诉 PHP 在 ...

  9. 【转】Android系统中Fastboot和Recovery所扮演的角色。

    Android 刷机过程中 Fastboot 和 Recovery 的作用是什么? 自己在知乎的一篇回答,,现在翻出来放到博客,希望可以解答更多人的疑惑,抑或有什么理解上的错误,也望网友指出~ 今天恰 ...

  10. OpenTK学习笔记(1)-源码、官网地址

    OpenTK源码下载地址:https://github.com/opentk/opentk OpenTK使用Nuget安装命令:OpenTK:Install-Package OpenTK -Versi ...