• FPGA-VGA成像原理与时序


    什么是VGA:

    VGA, Video Graphics Array。即视频图形阵列,具有分辨率高、显示速率快、颜色丰富等优点。VGA接口不但是CRT显示设备的标准接口,同样也是LCD液晶显示设备的标准接口,具有广泛的应用范围。在FGPA中,常广泛用于图像处理等领域。

    VGA 显示器成像原理

    在 VGA 标准刚兴起的时候,常见的 VGA 接口彩色显示器一般基于 CRT(阴极射线管) 实现,色彩由 RGB 三基色组成,显示是用逐行扫描的方式。下图为基于 CRT 的显示器实物图。

    阴极射线枪发出的电子束打在涂有荧光粉的荧光屏上,产生 RGB 三基色,合成一个彩 色像素,扫描从屏幕的左上方开始,从左到右,从上到下进行扫描,每扫完一行,电子束都 回到屏幕的下一行左边的起始位置。

    在回扫的过程中,电子枪不能发射电子,否则会影响荧光屏上既有图像的颜色,所以 回扫期间,需要进行行消隐,简单来说就是关闭电子枪。每行结束时,用行同步信号进行行 同步,图中从右上方向左下方的斜向虚线就是其回行扫示意图。

    当整个屏幕的所有行都扫描完后,使用场同步信号进行场同步,并使扫描回到屏幕的 左上方。同样的,为了避免电子枪在回到左上方的过程中发出的电子破坏荧光屏上既有的图 像内容,这个回扫的过程也需要关闭电子枪,即场消隐。

    随着显示技术的发展,出现了液晶显示器,液晶显示器让显示设备彻底摆脱了厚重的 机身,也为便携式计算机的出现创造了可能。

    液晶显示器的成像原理与 CRT 不同。液晶显示器是通过改变对液晶像素点单元施加电 压的电压大小,来改变液晶单元的透光性。在液晶单元背后发射白光,并添加三色滤光片, 分别使 R、G、B 这 3 种光线透过滤光片,最后通过 3 个像素点合成一个彩色像素点,从而 实现彩色显示。

    由于液晶技术晚于 CRT 显示技术诞生,在液晶显示器出现的时候,计算机显示接口已 经确定,很难再突然改变。所以为了能够兼容传统的显示接口,液晶显示器通过内部电路实 现了对 VGA 接口的完全兼容。因此,在使用显示器时,只要该显示器带有标准的 VGA 接口, 就不用去关注其成像原理,直接使用标准的 VGA 时序即可驱动。

    当使用 VGA 接口传输图像时,显示驱动芯片(如显卡)输出的 RGB 数据先要经过 DAC 转换为 3 路分别代表 R、G、B 颜色分量的模拟信号,送到 VGA 接口,这些模拟信号经由 VGA 线缆到达显示器的 VGA 接口,对于模拟的 CRT 显示器,这些信号会直接被放大后用于驱动 电子枪发射电子,而对于液晶显示器,则需要显示器使用专门的模拟数字转换芯片将模拟信 号再转换为数字信号后,去驱动 RGB 接口的液晶显示屏显示图像。

    VGA 时序

    CRT 行扫描过程

    对于 CRT 显示器,虽然扫描的时候是按照一行一行的方式进行的,但不是扫描完一行 有效数据段之后就立马返回,而是会继续向右扫描一段区域,这个区域称为右边界区域 (horizontal right border),该区域已经不在有效的显示范围内,如果从物理结构的角度来说, 这一段对应的荧光屏玻璃上就不再有荧光粉了,但是电子枪还在继续向右走,可以形象理解为显示器右边的黑边。同样的,显示器左边也有这样一段黑边,在开始显示有效数据之 前,电子枪扫描到的这段区域同样也是没有荧光粉的,不会显示图像, 这个区域称为左边界区域(horizontal left border)

    那么,电子枪什么时候会到最左侧准备开始新一行图像的扫描呢?当电子枪扫描一行 图像到达荧光屏的最右端后,其并不会自动回到最左边准备下一行,而是需要有一个通知信 号,通知其回去,这个通知信号就是行同步信号脉冲(horizontal sync pulse)。行同步信号是 一个脉冲,当该脉冲出现后,电子枪的指向会在一定时间内从最右侧回到显示屏的最左侧。 而这个回去的过程需要耗费一定的时间,这个时间就称为 horizontal back porch。这也是这个名词中 back 的意义所在,即出现行同步信号后,电子枪从显示屏最右侧回到最左侧的时间。 

    当电子枪扫描过了右侧没有荧光粉的区域后,还没有收到回到最左侧的命令(行同步信号脉冲)之前,电子枪需要关闭以实现消隐,这个消隐的时间段就称为 horizontal front porch, 直观一点理解就是完成了一行图像的扫描,但还没收到回到最左侧命令之前的一段时间。这也是这个名词中 front 的意义所在。

    CRT 场扫描过程

    一幅完整的图像可以看作是多行图像平铺构成的,所以理解了行扫描的过程中每个时间段对应的时间参数名称之后,再来理解场扫描中的名词就非常简单了。

    首先来讲,CRT 在扫描一行图像的时候,电子枪的水平位置是保持稳定不变的,而当一 行图像扫描完成,开始扫描下一行图像的时候,电子枪的水平位置会向下调整一定的值。因此,我们可以认为,场时序就是在垂直方向上从上往下依次扫描。

    其次来说,对于 CRT 显示器来说,其不是扫描完所有行的图像后就立马返回最上方, 而是会继续向下扫描一段区域,这个区域称为下边界区域(vertical bottom border),该区域 已经不在有效的显示范围内,如果从物理结构的角度来说,这一段对应的荧光屏玻璃上就不 再有荧光粉了,但是电子枪还在继续向下走,大家可以形象理解为显示器下边的黑边。同样 的,显示器上边也有这样一段黑边,在开始显示有效数据之前,电子枪扫描到的这段区域同 样也是没有荧光粉的,不会显示图像, 这个区域称为上边界区域(vertical top border)

    再来说说,电子枪什么时候会到最上方准备开始新一场图像的扫描。当电子枪扫描一场图像到达荧光屏的最下方后,其并不会自动回到最上边准备下一场,而是需要有一个通知 信号,通知其回去,这个通知信号就是场同步信号脉冲(vertical sync pulse)。场同步信号是 一个脉冲,当该脉冲出现后,电子枪的指向会在一定时间内从最下方回到显示屏的最上方。 而这个回去的过程需要耗费一定的时间,这个时间就称为 vertical back porch。即出现场同步信号后,电子枪从显示屏最下方回到最上方的时间。

    当电子枪扫描过了下方没有荧光粉的区域后,还没有收到回到最上方的命令(场同步信号脉冲)之前,电子枪需要关闭以实现消隐,这个消隐的时间段就称为 vertical front porch, 直观一点理解就是完成了一场图像的扫描,但还没收到回到最上方命令之前的一段时间。、

    行扫描时序图 

    场扫描时序图

    上述两幅图中,都只给出了时序参数的名称,并没有给出每个参数具体的值是多少。 而每个参数具体的值是多少,并不是固定的,而是根据需要扫描的有效图像区域的大小确定 的。需要扫描的有效图像区域的大小,一般用分辨率来表示。

     下表给出了若干个常见分辨率对应的行场时序中各个参数的具体数值,注意,这些参 数值中,行相关的参数都是以像素的更新频率,也就是像素时钟作为单位而场相关的参数, 则是以行作为单位。

    分析

    以800x480为例  行同步信号分析

    场同步信号分析

    编写逻辑代码:

    1. `timescale 1ns / 1ps
    2. //800x480
    3. //H_Right_Borde = 0 V_Bottom_Bord = 8
    4. //H_Front_Porch = 40 V_Front_Porch = 2
    5. //H_Sync_Time = 128 V_Sync_Time = 2
    6. //H_Back_Porch = 88 V_Back_Porch = 25
    7. //H_Left_Border = 0 V_Top_Border = 8
    8. //H_Data_Time = 800 V_Data_Time = 480
    9. //H_Total_Time = 1056 V_Total_Time = 525
    10. module VGA_CTRL(
    11. Clk_33M ,
    12. Reset_n ,
    13. Data_in ,
    14. hcount , //行扫描位置(显示图像行扫描地址)
    15. vcount , //场扫描位置(显示图像场扫描地址)
    16. VGA_HS , //行同步信号
    17. VGA_VS , //场同步信号
    18. VGA_BLK , //有效数据输出
    19. VGA_CLK ,
    20. VGA_DATA //红绿蓝三色 分别8位量化 R[7:0]G[7:0]B[7:0]
    21. );
    22. input Clk_33M;
    23. input Reset_n;
    24. input [23:0] Data_in;
    25. output [10:0] hcount;
    26. output [10:0] vcount;
    27. output VGA_HS;
    28. output VGA_VS;
    29. output VGA_BLK;
    30. output VGA_CLK;
    31. output [23:0] VGA_DATA; //红绿蓝三色 分别8位量化 R[7:0]G[7:0]B[7:0]
    32. parameter VGA_HS_end = 11'd127 ,
    33. hdat_begin = 11'd216 ,
    34. hdat_end = 11'd1016 ,
    35. hpixel_end = 11'd1055 ,
    36. VGA_VS_end = 11'd1 ,
    37. vdat_begin = 11'd35 ,
    38. vdat_end = 11'd515 ,
    39. vline_end = 11'd524 ;
    40. reg [10:0] hcount_r;
    41. reg [10:0] vcount_r;
    42. always@(posedge Clk_33M or negedge Reset_n)
    43. if(!Reset_n)
    44. hcount_r <= 0;
    45. else if(hcount_r == hpixel_end )
    46. hcount_r <= 0;
    47. else
    48. hcount_r <= hcount_r + 1'b1;
    49. always@(posedge Clk_33M or negedge Reset_n)
    50. if(!Reset_n)
    51. vcount_r <= 0;
    52. else if(hcount_r == hpixel_end)
    53. if(vcount_r == vline_end )
    54. vcount_r <= 0;
    55. else
    56. vcount_r <= vcount_r + 1'b1;
    57. else
    58. vcount_r <= vcount_r;
    59. assign VGA_BLK = ((hcount_r >= hdat_begin) && (hcount_r < hdat_end)&&
    60. (vcount_r >= vdat_begin) && (vcount_r < vdat_end)) ? 1'b1 : 1'b0;
    61. assign hcount = VGA_BLK ? (hcount_r - hdat_begin) : 10'd0;
    62. assign vcount = VGA_BLK ? (vcount_r - vdat_begin) : 10'd0;
    63. assign VGA_HS = (hcount_r > VGA_HS_end)? 1'b1 :1'b0;
    64. assign VGA_VS = (vcount_r > VGA_VS_end)? 1'b1 :1'b0;
    65. assign VGA_DATA = (VGA_BLK) ? Data_in : 24'h000000;
    66. assign VGA_CLK = ~Clk_33M;
    67. endmodule

    编写测试程序:

    1. `timescale 1ns / 1ps
    2. module VGA_CTRL_tb;
    3. reg Clk_33M;
    4. reg Reset_n;
    5. reg [23:0] Data_in;
    6. wire [10:0] hcount;
    7. wire [10:0] vcount;
    8. wire VGA_HS;
    9. wire VGA_VS;
    10. wire VGA_BLK;
    11. wire VGA_CLK;
    12. wire [23:0] VGA_DATA; //红绿蓝三色 分别8位量化 R[7:0]G[7:0]B[7:0]
    13. VGA_CTRL VGA_CTRL(
    14. .Clk_33M (Clk_33M ) ,
    15. .Reset_n (Reset_n ) ,
    16. .Data_in (Data_in ) ,
    17. .hcount (hcount ) , //行扫描位置(显示图像行扫描地址)
    18. .vcount (vcount ) , //场扫描位置(显示图像场扫描地址)
    19. .VGA_HS (VGA_HS ) , //行同步信号
    20. .VGA_VS (VGA_VS ) , //场同步信号
    21. .VGA_BLK (VGA_BLK ) , //有效数据输出
    22. .VGA_CLK (VGA_CLK ) ,
    23. .VGA_DATA (VGA_DATA) //红绿蓝三色 分别8位量化 R[7:0]G[7:0]B[7:0]
    24. );
    25. initial Clk_33M = 1;
    26. always #15 Clk_33M = ~ Clk_33M;
    27. initial begin
    28. Reset_n = 0;
    29. #201;
    30. Reset_n = 1;
    31. #200000000;
    32. $stop;
    33. end
    34. always@(posedge Clk_33M or negedge Reset_n)
    35. if(!Reset_n)
    36. Data_in <= 1'b0;
    37. else if(!VGA_BLK)
    38. Data_in <= Data_in;
    39. else
    40. Data_in <= Data_in + 1'b1;
    41. endmodule

    仿真波形:

    第一行开始时波形:

    第一行结束时波形:

    具体分析波形还需要从行同步脉冲时间,场同步脉冲时间,行消隐时间,场消隐时间,行数据传输时间,场数据传输结束时间等等,分析波形验证逻辑代码的正确性。

  • 相关阅读:
    OpenJudge NOI 1.13 51:古代密码
    批量制作公司出入证
    WRFDA资料同化实践技术应用
    【Git】Git常用操作命令大全(笔记)
    vue3实现表格数据导出Excel
    数据结构(栈和队列)
    华为L410上制作内网镜像模板02
    letsencrypt + centsos7.9 + docker + express 搭建https环境
    对象混入的实现方式
    JVM篇---第三篇
  • 原文地址:https://blog.csdn.net/weixin_46897065/article/details/136386813