目录

一、前言

二、 原理介绍

三、 目标任务

四、 设计思路与Verilog代码编写


一、前言

之前自己分块写了一个VGA显示8色彩条RGB888_yh13572438258的博客-CSDN博客,感觉不是特别满意,下面分享一下大佬的设计【接口时序】7、VGA接口原理与Verilog实现 - jgliu - 博客园,对VGA介绍很详细,基本都是大佬的总结,主要采用RGB编码方式是RGB565,在此基础下我又改了一下我想要的编码方式RGB888。

二、 原理介绍

  VGA(Video Graphics Array)即视频图形阵列,是IBM在1987年推出的使用模拟信号的一种视频传输标准,在当时具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域得到了广泛的应用。这个标准对于现今的个人电脑市场已经十分过时。即使如此,VGA仍然是最多制造商所共同支持的一个标准,个人电脑在加载自己的特殊驱动程序之前,都必须支持VGA的标准。

VGA接口实物图如下图所示

  左边带针的叫VGA公头,右边带槽的叫VGA母头。

  VGA接口的特点:

  1、 VGA接口不支持热插拔

  VGA接口跟HDMI接口一样是不支持热插拔的。热插拔是指一般带电状态下对于接插件的插入或是拔除,并不只是针对有电源接口或者带供电的接口的接插件,而是所有。在运行状态时,插拔会产生耦合电流,电流不稳造成硬件烧坏,导致笔记本的接口端的保护受到冲击。就像U盘不能再一个时间段多次在一个端口插拔使用一样。各种电器的外露端子都会有金属的部分,它们都是要求接地的,但是不同的电器之间的地并不一定相同,比如一台DVD的地和一台电视机的接地都是相对于本身系统而言。

  当端子插入时,首先要建立共同的地来对传输的信号作参考,这就要依靠端子和传输线上的金属部分了,金属部分接地同时也是对信号的屏蔽和保护。两个地相接触一瞬间,会有很高的尖峰脉冲产生,这种脉冲如果不加以滤除可能会直达芯片并将其损坏。另外还有一种是ESD,即静电损坏,这种更难以避免,因为在电子产品上,只能去防护,ESD的持续时间会更短US级别。所以正规的电子产品对于金属端子的接地有比较高的要求,同时在信号线上增加ESD防护器件来避免热插拔的损坏。但实际上很多厂家为了节省成本而偷工减料,或者是对热插拔的防护意识不够导致设计不合理,使得用户会出现热插拔损坏电器的现象产生。

  2、  VGA不能传输音频

  因为视频是VGA信号,而音频信号不是,所以VGA不能传输音频,只能传输视频。相信这就是为什么这几年极度的需求创新转换器的原因。VGA不支持音频传输也是给很多消费者带来烦恼,这最好的办法其实就是购买一款转换器,VGA转HDMI或者HDMI转VGA,达到视频传输的同时还支持音频信号的输出,一举两得。但是不要只想着转换器的输入与输出成问题,同时想想音频输出口,3.5mm是音频输出信号的重要连接线。购买时可以考虑想转换器有没有带3.5mm的音频输出口,然后另外购买一条音频线。

  3、 VGA接口是一种D型接口,上面共有15针孔,分成三排,每排五个。 其中比较重要的是3根RGB彩色分量信号和2根扫描同步信号HSYNC和VSYNC针。其引脚编号图如下图所示:

  其中每个管脚的详细定义如下表所示

管脚

名称

定义

1

RED

红基色(75Ω,0.7Vp-p)

2

GREEN

绿基色(75Ω,0.7Vp-p)

3

BLUE

蓝基色(75Ω,0.7Vp-p)

4

ID2

地址码(显示器标识位2)

5

GND

6

RGND

红色地

7

GGND

绿色地

8

BGND

蓝色地

9

KEY

保留

10

SGND

同步信号地

11

ID0

地址码(显示器标识位0)

12

ID1

地址码(显示器标识位1)

13

HSYNC

行同步信号

14

VSYNC

场同步信号

15

ID3

地址码(显示器标识位3)

  VGA接口时序详解

  VGA 显示器扫描方式从屏幕左上角一点开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT 对电子束进行消隐,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。完成一行扫描的时间称为水平扫描时间,其倒数称为行频率;完成一帧(整屏)扫描的时间称为垂直扫描时间,其倒数称为场频率,即屏幕的刷新频率,常见的有 60Hz,75Hz 等等,但标准的 VGA 显示的场频 60Hz。其扫描示意图如下图所示

  在对VGA扫描方式有一个直观的感受以后接下来在看一看VGA接口的详细时序与各个参数的定义。VGA的详细时序如下图所示:

  总的来说,VGA的时序主要包括行时序与场时序两个部分。

  其中行时序主要包括:行同步(Hor Sync) 、行消隐(Hor Back Porch) 、行视频有效(Hor Active Video)和行前肩(Hor Front Porch)这四个参数,行时序的时序图如下图所示

而场时序主要包括:场同步(Ver Sync) 、场消隐(Ver Back Porch) 、场视频有效(Ver Active Video)和场前肩(Ver Front Porch)这四个参数,场时序的时序图如下图所示

  需要注意的有三点:

  1、行时序是以”像素”为单位的, 场时序是以”行”为单位的。

  2、VGA 工业标准显示模式要求:行同步,场同步都为负极性,即同步脉冲要求是负脉冲。

  3、VGA 行时序对行同步时间、 消隐时间、 行视频有效时间和行前肩时间有特定的规范, 场时序也是如此。 常用VGA 分辨率时序参数如下表所示

  其中:

  Pixel Clock = (Screen Refresh Frequency)*(Hor Active Video + Hor Front Porch + Hor Synv Pulse + Hor Back Porch)* (Ver Active Video + Ver Front Porch + Ver Synv Pulse + Ver Back Porch)

  以640x480,60Hz这种分辨率格式来说,25.175MHz = 25175000Hz = 60*(640 + 16 + 96 + 48)*(480 + 11 + 2 + 31) = 60 * 800 * 525

三、 目标任务

  编写VGA驱动代码,并用VCS+Verdi对时序进行仿真,看时序是否能产生彩色条纹

四、 设计思路与Verilog代码编写

4.1、 VGA驱动模块的接口定义与整体设计

  Verilog编写的VGA模块除了Red,Green,Blue三基色、行同步HS以及场同步VS以外还要包括时钟、复位信号。其框图如下所示

  其中:

  I_clk是系统时钟;

  I_rst_n是系统复位;

  O_hs是行同步信号;

  O_vs是场同步信号;

  O_red是红色分量;

  O_green是绿色分量;

  O_blue是蓝色分量;

  上面的模块框图中没有看到测试数据(彩条或者图片)的输入端口,原因是由于VGA的逻辑比较简单,所以我准备把发送测试图案(彩条或者图片)的逻辑也直接集成到vga_driver模块中,这样可能更加方便理解。但是对于实际一个比较复杂的项目来说,最好还是把各个模块独立开来,这样更加方便二次移植。在写代码之前,先了解一个关于图片的分辨率与位深度的知识点。

4.2、 图片的分辨率、图片的尺寸与位深度

  图片的分辨率指图像中存储的信息量,是每英寸图像内有多少个像素点,它决定了位图图像细节的精细程度。描述分辨率的单位有:dpi(dots per inch)点每英寸、lpi(line per inch)线每英寸和ppi(pixel per inch)像素每英寸。

  图片的尺寸是指一幅图片长度和宽度各占多少像素,我们平常说的一张640×480的图片指的就是这张图片的长度有640个像素点,宽度有480个像素点

  位深度是指图片的每个像素是用多少位(bit)来表示的。比如黑白二色的图像是数字图像中最简单的一种,它只有黑、白两种颜色,也就是说它的每个像素只有1位颜色,位深度是1,用2的零次幂来表示;考虑到位深度平均分给R, G, B和Alpha,而只有RGB可以相互组合成颜色。所以4位颜色的图,它的位深度是4,只有2的4次幂种颜色,即16种颜色或16种灰度等级 )。8位颜色的图,位深度就是8,用2的8次幂表示,它含有256种颜色 ( 或256种灰度等级 )。24位颜色可称之为真彩色,位深度是24,它能组合成2的24次幂种颜色,即:16777216种颜色 ( 或称千万种颜色 ),超过了人眼能够分辨的颜色数量。当我们用24位来记录颜色时,实际上是以2^(8×3),即红、绿、蓝 ( RGB ) 三基色各以2的8次幂,256种颜色而存在的,三色组合就形成一千六百万种颜色。除了上面这几种情况以外,有的图片的位深度是16位,其中红基色占5位,绿基色占6位,蓝基色占5位,他们一共可以组成2^16中颜色。

  下面以这张图片为例来说明如何在电脑上查看图片的大小,分辨率以及位深度等信息。

  在电脑上用选中图片以后,然后鼠标右键在菜单中点击属性,然后在详细信息选项卡中就能查看图片的各个详细信息了,上面这张图片的信息如下图所示

  由上面的信息可知这张图片的大小为128*128。水平分辨率与垂直分辨率为96dpi(dots per inch),位深度为24-bit。

4.4、 vga_driver模块显示彩条Verilog代码编写

  有了上面的基础之后就可以开始着手编写代码,现在在回过头去看行时序与场时序,其实可以发现VGA的时序真的是非常简单。

  对行时序来说,只需要定义一个计数器,当计数器在像素时钟的作用下计满一行的总点数后清零,然后利用assign语句在计数值为Hor Sync期间把行时序信号拉低产生一个低脉冲就可以了。场时序与行时序非常类似,当行计数器计满一行了场计数器才加1,当计满一场的时间后,计数值清零,然后利用assign语句在Ver Sync期间把场时序信号拉低产生一个低脉冲就OK了。

  有了行时序与场时序以后,接下来就是在Hor Active Video和Ver Active Video均有效的期间往Red,Green,Blue三个分量送数据,数据就会在在屏幕上显示出来了。而Hor Active Video有效的期间正是行计数器的计数值在大于(Hor Sync + Hor Back Porch),小于(Hor Sync + Hor Back Porch + Hor Active Video)的时候,而Ver Active Video有效的期间正是场计数器的计数值在大于(Ver Sync + Ver Back Porch),小于(Ver Sync + Ver Back Porch + Ver Active Video)的时候,所以在代码里面可以利用assign语句产生一个激活标志,当激活标志为高的时候给Red,Green,Blue三个分量送数据,数据就会在屏幕显示出来了。

  下面以分辨率为640x480为例来编写vga_driver的代码,由前面的分辨率时序参数表可知,640x480分辨率的像素时钟为25.175Hz,但实际并不需要这么精确的时钟频率,我们取25MHz就可以了,我的开发板的时钟频率为50MHz,所以只需要简单的写一个二分频逻辑就可以得到这个像素时钟了。如果你想显示其他分辨率的图片,比如800x600分辨率的时钟频率是40MHz,这时候就需要用FPGA内部的Clocking Wizard IP核来得到这个40MHz的时钟,Clocking Wizard IP核内部回调用FPGA的PLL资源对输入频率进行处理来得到想要的输出频率。

  下面是VGA接口产生彩条的完整代码:

module vga_driver
(input                   I_clk   , // 系统50MHz时钟input                   I_rst_n , // 系统复位output   reg   [7:0]    O_red   , // VGA红色分量output   reg   [7:0]    O_green , // VGA绿色分量output   reg   [7:0]    O_blue  , // VGA蓝色分量output                  O_hs    , // VGA行同步信号output                  O_vs      // VGA场同步信号
);// 分辨率为640*480时行时序各个参数定义
parameter       C_H_SYNC_PULSE      =   96  , C_H_BACK_PORCH      =   48  ,C_H_ACTIVE_TIME     =   640 ,C_H_FRONT_PORCH     =   16  ,C_H_LINE_PERIOD     =   800 ;// 分辨率为640*480时场时序各个参数定义
parameter       C_V_SYNC_PULSE      =   2   , C_V_BACK_PORCH      =   33  ,C_V_ACTIVE_TIME     =   480 ,C_V_FRONT_PORCH     =   10  ,C_V_FRAME_PERIOD    =   525 ;parameter       C_COLOR_BAR_WIDTH   =   C_H_ACTIVE_TIME / 8  ;  reg [11:0]      R_h_cnt         ; // 行时序计数器
reg [11:0]      R_v_cnt         ; // 列时序计数器
reg             R_clk_25M       ;wire            W_active_flag   ; // 激活标志,当这个信号为1时RGB的数据可以显示在屏幕上//
//功能: 产生25MHz的像素时钟
//
always @(posedge I_clk or negedge I_rst_n)
beginif(!I_rst_n)R_clk_25M   <=  1'b0        ;elseR_clk_25M   <=  ~R_clk_25M  ;
end
////
// 功能:产生行时序
//
always @(posedge R_clk_25M or negedge I_rst_n)
beginif(!I_rst_n)R_h_cnt <=  12'd0   ;else if(R_h_cnt == C_H_LINE_PERIOD - 1'b1)R_h_cnt <=  12'd0   ;elseR_h_cnt <=  R_h_cnt + 1'b1  ;
end                assign O_hs =   (R_h_cnt < C_H_SYNC_PULSE) ? 1'b0 : 1'b1    ;
////
// 功能:产生场时序
//
always @(posedge R_clk_25M or negedge I_rst_n)
beginif(!I_rst_n)R_v_cnt <=  12'd0   ;else if(R_v_cnt == C_V_FRAME_PERIOD - 1'b1)R_v_cnt <=  12'd0   ;else if(R_h_cnt == C_H_LINE_PERIOD - 1'b1)R_v_cnt <=  R_v_cnt + 1'b1  ;elseR_v_cnt <=  R_v_cnt ;
end                assign O_vs =   (R_v_cnt < C_V_SYNC_PULSE) ? 1'b0 : 1'b1    ;
//  assign W_active_flag =  (R_h_cnt >= (C_H_SYNC_PULSE + C_H_BACK_PORCH                  ))  &&(R_h_cnt <= (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_H_ACTIVE_TIME))  && (R_v_cnt >= (C_V_SYNC_PULSE + C_V_BACK_PORCH                  ))  &&(R_v_cnt <= (C_V_SYNC_PULSE + C_V_BACK_PORCH + C_V_ACTIVE_TIME))  ;                     //
// 功能:把显示器屏幕分成8个纵列,每个纵列的宽度是80
//
always @(posedge R_clk_25M or negedge I_rst_n)
beginif(!I_rst_n) beginO_red   <=  8'b00000000    ;O_green <=  8'b00000000   ;O_blue  <=  8'b00000000    ; endelse if(W_active_flag)     beginif(R_h_cnt < (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_COLOR_BAR_WIDTH)) // 红色彩条beginO_red   <=  8'b11111111    ; // 红色彩条把红色分量全部给1,绿色和蓝色给0O_green <=  8'b00000000   ;O_blue  <=  8'b00000000    ;endelse if(R_h_cnt < (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_COLOR_BAR_WIDTH*2)) // 绿色彩条beginO_red   <=  8'b00000000    ;O_green <=  8'b11111111   ; // 绿色彩条把绿色分量全部给1,红色和蓝色分量给0O_blue  <=  8'b00000000    ;end else if(R_h_cnt < (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_COLOR_BAR_WIDTH*3)) // 蓝色彩条beginO_red   <=  8'b00000000    ;O_green <=  8'b00000000   ;O_blue  <=  8'b11111111    ; // 蓝色彩条把蓝色分量全部给1,红色和绿分量给0end else if(R_h_cnt < (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_COLOR_BAR_WIDTH*4)) // 白色彩条beginO_red   <=  8'b11111111    ; // 白色彩条是有红绿蓝三基色混合而成O_green <=  8'b11111111   ; // 所以白色彩条要把红绿蓝三个分量全部给1O_blue  <=  8'b11111111    ;end else if(R_h_cnt < (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_COLOR_BAR_WIDTH*5)) // 黑色彩条beginO_red   <=  8'b00000000    ; // 黑色彩条就是把红绿蓝所有分量全部给0O_green <=  8'b00000000   ;O_blue  <=  8'b00000000    ;end else if(R_h_cnt < (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_COLOR_BAR_WIDTH*6)) // 黄色彩条beginO_red   <=  8'b11111111    ; // 黄色彩条是有红绿两种颜色混合而成O_green <=  8'b11111111   ; // 所以黄色彩条要把红绿两个分量给1O_blue  <=  8'b00000000    ; // 蓝色分量给0end else if(R_h_cnt < (C_H_SYNC_PULSE + C_H_BACK_PORCH + C_COLOR_BAR_WIDTH*7)) // 紫色彩条beginO_red   <=  8'b11111111    ; // 紫色彩条是有红蓝两种颜色混合而成O_green <=  8'b00000000   ; // 所以紫色彩条要把红蓝两个分量给1O_blue  <=  8'b11111111    ; // 绿色分量给0end else                              // 青色彩条beginO_red   <=  8'b00000000    ; // 青色彩条是由蓝绿两种颜色混合而成O_green <=  8'b11111111   ; // 所以青色彩条要把蓝绿两个分量给1O_blue  <=  8'b11111111    ; // 红色分量给0end                   endelsebeginO_red   <=  8'b00000000    ;O_green <=  8'b00000000   ;O_blue  <=  8'b00000000    ; end
end
/*// 功能:产生黑白相间的格子图案always @(posedge R_clk_25M or negedge I_rst_n)
beginif(!I_rst_n) beginO_red   <=  8'b00000000    ;O_green <=  8'b00000000   ;O_blue  <=  8'b00000000    ; endelse if(W_active_flag)     beginif((R_h_cnt[4]==1'b1) ^ (R_v_cnt[4]==1'b1))beginO_red   <=  8'b00000000    ;O_green <=  8'b00000000   ;O_blue  <=  8'b00000000    ;endelsebeginO_red   <=  8'b11111111    ;O_green <=  8'b11111111   ;O_blue  <=  8'b11111111    ;end                   endelsebeginO_red   <=  8'b00000000    ;O_green <=  8'b00000000   ;O_blue  <=  8'b00000000    ; end
end
*/endmodule

整个代码的编写思路与上面的分析基本一致。除了显示彩条以外,还可以显示黑白格子,代码在上面也已经给出。可以用VCS或者ModelSim对整个逻辑进行一下仿真,在测试激励文件里面只需要给时钟和复位加上激励就可以了,也可以参考VGA显示8色彩条RGB888_yh13572438258的博客-CSDN博客

VGA原理详解与verilog实现RGB888彩条(二)相关推荐

  1. CORDIC算法原理详解及其Verilog实现

    CORDIC算法原理详解及其Verilog实现 本文的verilog代码 链接:https://pan.baidu.com/s/1GGbRjxO5CxoIODQAg1l6Lw 提取码:jo0h *本文 ...

  2. Android涂鸦画板原理详解——从初级到高级(二)

    前言 前面写了<Android涂鸦画板原理详解--从初级到高级(一)>,讲了涂鸦原理初级和中级的应用,现在讲解高级应用.如果没有看过前面一篇文章的同学,建议先去看看哈. 准备 高级涂鸦涉及 ...

  3. 8B/10B编码原理详解、Verilog实现及在JESD204B中的应用

    目录 1.8B/10B介绍 2.原理 3.Verilog实现 4.实例:在JESD204B中的应用 参考资料: 1.8B/10B介绍 8B/10B编码的目的是防止串行的数据出现长时间的连0连1,因为这 ...

  4. 扰码器原理详解及verilog实现

    什么是扰码 扰码就是对原始的用户数据进行扰乱,得到随机化的用户数据.连续扰码两次就能得到原始数据,通常是发送电路在发送数据时先对数据进行随机扰乱,接收电路使用相同的扰乱算法就可以重新恢复出原始的数据. ...

  5. FPGA——用VGA时序显示图像原理详解(2)

    目录 VGA时序 VGA显示 大家结合上一篇: FPGA--用VGA时序显示图像原理详解(1)_居安士的博客-CSDN博客 VGA时序 首先我们下载数据手册,我们可以根据自己的需求,选择图像大小,以及 ...

  6. FPGA学习之路—接口(3)—SPI详解及Verilog源码分析

    FPGA学习之路--SPI详解及Verilog源码分析 概述 SPI = Serial Peripheral Interface,是串行外围设备接口,是一种高速,全双工,同步的通信总线. 优点 支持全 ...

  7. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  8. LVS原理详解(3种工作方式8种调度算法)--老男孩

    一.LVS原理详解(4种工作方式8种调度算法) 集群简介 集群就是一组独立的计算机,协同工作,对外提供服务.对客户端来说像是一台服务器提供服务. LVS在企业架构中的位置: 以上的架构只是众多企业里面 ...

  9. jQuery中getJSON跨域原理详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp28 jQuery中getJSON跨域原理详解 前几天我再开发一个叫 河蟹工 ...

最新文章

  1. hive replace替换多个_详解Mysql数据库中replace与replace into的用法及区别
  2. 三种工厂模式的分析以及C++实现
  3. 使用.Net访问Office编程接口
  4. P4389-付公主的背包【生成函数,多项式exp】
  5. 判断form表单里面的元素属性是否有数据_html form标签的action属性是什么意思?又有哪些用法?(附实例)...
  6. oracle 查看动态性能视图,Oracle 中的V$ 动态性能视图
  7. 二叉查找树--插入、删除、查找
  8. [SHELL]判断一个命令是否存在
  9. 大学生创新创业 /互联网+ 大赛 商业计划书目录(模板)
  10. 高性能的java的ip资源扫描和端口分析
  11. python大规模获取豆瓣影评_python自动获取豆瓣电影评分和影评
  12. F1C100S自制开发板调试过程
  13. 中国高新技术企业名单数据
  14. Ubuntu18.04安装GoldenDict词典【词库】
  15. 采购与供应链管理 读书笔记一
  16. Assembler如何把跳转汇编变成机器码的(四)
  17. 什么无线桥接一直正在链接服务器失败,无线桥接网络常见问题故障排除
  18. debian系统服务器读不出来,Debian10局域网服务器使用踩坑笔记
  19. WPS Office 2019文字组件插入和改写状态的切换
  20. 视频号小程序也能投放朋友圈引流变现了;附带视频号运营手册丨国仁网络

热门文章

  1. 搭载“鸿蒙”的华为Watch 3,是智能手表的标准答案吗?
  2. 信息学奥赛一本通2066
  3. c语言中doubt和double,doubt的用法
  4. NYOJ 427 Number Sequence
  5. Android代码设置APN
  6. 【SemiDrive源码分析】【X9芯片启动流程】12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析
  7. 计算机画图学生作品小学,电脑绘画作品_需要一件小学生电脑绘画作品
  8. C语言常用语句之-循环语句
  9. WMS item与LPN的关系
  10. 画论17 邓椿《画继》