1.了解VGA协议

VGA协议有5个输入信号,列同步信号(HSYNC Signal),行同步信号(VSYNC Signal),红-绿-蓝,颜色信号(RGB Signal)。

一帧屏幕的显示是由行从上至下扫描,列从左至右填充。

    以800x600x60Hz为例:

对于列填充信号:a是拉低的128个列像素,b是拉高的88个列像素,c是拉高的800个列像素,d是拉高的40个列像素。

对于行扫描信号:o是拉低的4个行像素,p是拉高的23个行像素,q是拉高的600个行像素,r是拉高的1个行像素。

    其中,橘色为有效显示区域

一个行像素是以列像素为单位来定义的:

1个行像素 = 1056个列像素 (即1行中有1056个像素需要填充)

一个列像素是以时间单位来定义的:

1个列像素 = 25ns。

2.VGA驱动建模

PLL是FPGA的重要硬件资源,PLL主要功能是对源时钟编程,翻频,分频。

同步模块实现对列填充信号与行扫描信号的控制,同时输出当前的地址(Column_Addr_Sig,Row_Addr_Sig)和有效区域信号(Ready_Sig)。

同步模块的输入只有CLK和RSTn信号,不需要外部输入其它信号,在模块里面编写一系列的驱动模型,并输出驱动信号。

首先,写一个列计数器与一个行计数器:

    注意:时钟频率经过PLL倍频后,时钟周期达到了25ns,对比列计数器与行计数器的写法,列计数器是每来一个时钟上升沿,计数增加1,即每隔25ns,计数增加1。而行计数器,是当列填充完毕后(if(Count_H == 11d1056)),计数增加1。这就解决了我刚才发现行扫描与列扫描不匹配的疑惑。

有效区域信号的产生:

根据有效区域产生有效区域信号(Ready_Sig)

首先定义了一个名为isRectangle的标志寄存器(有0和1两种状态),用来划定显示区域,即(Column_Addr_Sig>11’d0  && Row_Addr_Sig < 11’d100)当扫描到以上区域时,显示相应的颜色,其它区域则不显示。

3.总体描述

(1)整个系统由PLL模块将外部时钟倍频,得到同步扫描与填充模块与VGA显示控制模块所需要的时钟。

(2)同步扫描模块接收经过倍频后的时钟信号后,通过内部编写的行扫描计数器与列填充计数器来工作,通过编写Ready_Sig状态标志寄存器相关块语句(扫描到有效区域后置1,不在有效区域则置0),同时结合isReady与行扫描计数器,列扫描计数器,计算出Column_Addr_Sig(列地址),Row_Addr_Sig(行地址)信号。

(3)VGA显示控制模块中,需要接收Ready_Sig(有效区域信号),列地址,行地址信号。然后在相应的位置填充颜色。同时,我们也可以在有效区域内,自己划定显示区域(通过自定义状态标志寄存器和划定行地址与列地址的范围),并填充相应的颜色。

4.拓展一(向下兼容的概念)

640x480x60Hz的显示标准需要的时钟频率是25.175MHz,即填充1个列像素需要的时间是39.7ns。则可以用更高的源时钟求得39.7ns的定时。引出向下兼容的处理方法:将外部20MHz时钟源翻倍至100MHz,即1个时钟周期为10ns,因此可以用4个时钟周期40ns的时间来满足填充1个列像素所需要的时间。

//40ns_Count,main_source = 10ns
parameter T40NS = 'd3;
reg [:]count1;
always@(posedge CLK or negedge RSTn)
if(!RSTn)
count1 <= 'd0;
else if(count1 == T40NS)
count1 <= 'd0;
else
count1 <= count1 + 'b1;
reg [:]count_H;
always@(posedge CLK or negedge RSTn)
if(!RSTn)
count_H <= 'd0;
else if(count_H == 'd800)
count_H <= 'd0;
else if(count1 == T40NS)
count_H <= count_H + 'b1;
reg [:]count_V;
always@(posedge CLK or negedge RSTn)
if(!RSTn)
count_V <= 'd0;
else if(count_V == 'd625)
count_V <= 'd0;
else if(count_H == 'd800)
count_V <= count_V + 'b1; 

    在写代码的过程中,需要注意的是寄存器的位宽要定义好,在使用数据的时候也需要带上。计数器在进行加1操作的时候,加的是“1b1”,即二进制加法运算,因为起先我们定义的是 reg [10:0]count_V 位宽为11。

    还有,并不是所有更高时钟的频率就能向下兼容。

5.拓展二(点阵显示)

点阵编码的方式是:逐行显示,高位在前。

逐行显示:表示图像是逐行填充,完成完一行的填充后,再填充下一行。

高位在前:列填充从左往右填充,但最左边是列像素的最高位。即:

以上为一个16个列像素,它的编码为0xf738。

在点阵显示模型中,需要有图片ROM,存储图片(点阵)信息,VGA控制模块需要给出点阵地址,并读取点阵数据,点阵的数据是一行一行读取的,因此,每次从图片ROM模块中取一行的数据。

以下为部分VGA显示控制的代码,寄存器m存储的是同步扫描模块传过来的行地址,n存储的是同步扫描模块传过来的列地址。

行地址直接传给图片ROM模块,图片ROM模块接收到行地址后,给出相应行的像素信息ROM_Data,VGA控制模块根据传来的行像素信息,填充相应的颜色。

解释:

    Red_Sig = Ready_Sig ? Rom_Data[6d63 - n] : 1b0;

    VGA扫描控制模块接收到列地址后,读取Rom_Data中相应的列数据,即当n=0时,应该读取第0列的数据,即Rom_Data[63] 为第0列数据,符合高位在前的原则。

    给出图片ROM模块的实例化代码:

Wire [:] Rom_Data;
Rom_module U3
(
.clock(CLK_40MHz);
.address(Rom_Addr);
.q(Rom_Data)
);

6.拓展三(图层显示建模)

关于图层显示的概论理解如下:

黄色是由红色图层与绿色图层叠加得到。

黑色是由红色图层,绿色图层和蓝色图层得到。

如若显示以下4个列像素的信息:

此表应该竖着和横着同时看,第1个列像素为红色,则图层显示码为:(第四位)红色层:1,绿色层:0,蓝色层:0;第2个列像素为黄色,则图层显示码为:(第三位)红色层:1,绿色层:1,蓝色层:0。

红色层:4’b1101

绿色层:4’b0101

蓝色层:4’b0001

    在显示控制模块中,只需要将相同的行,相同的列,不同的层信息发送到相关的输出信号。

VGA控制模块给出行信号Rom_Addr,图片ROM(red),图片ROM(green),图片ROM(blue)给出对应行的数据。

    体会:对于图片ROM模块,需要同步时钟,不需要复位信号处理,里面应该事先存储好图片的数据信息,等待VGA显示控制模块来读取。

图层的概念,就是通过使用不同颜色叠加,来产生我们需要的颜色。

7.拓展四(帧的概念)

在VGA显示标准中,如:800x600x60Hz,最后的“60Hz”,表示显示标准,意味着在1s内可以显示60帧图像。

60Hz的来历:1个行像素为1056个列像素,一个列像素需要25ns,则1帧的图像需要628*1056*25ns的时间,则1s内显示(1/(628*1056*25ns) = 60)帧图片。

显示动态图片的时候,对于图片ROM模块怎样存放图片的点阵信息,我们需要做如下处理:

    假设每张图片都是16x16x1Bit,共有6张图片。则,一张图片有16行,16列,保持这6张图片列对齐,0~15行放置第一张图片,16~31行放置第二张图片.....以此类推。

    等待显示完第一张图片后,再显示第二张图片,怎样判断一帧图片是否显示完全呢?需要同步扫描填充模块输出一个显示完成信号(Frame_Sig,)。

assign  Frame_Sig  =  (Count_V == 11d628)  ?  1b1  :  1b0;

    Frame_Sig并没有在always块语句中做处理,只是需要使用已经经过处理的信号,做出判断就可以得出准确的Frame_Sig(也算是一种算法吧)。

在VGA显示控制模块中,定义了一个FRAME常量,和一个Count_Frame计数器,每当Frame_Sig高电平时,计数器加1,计数周期为60个,表明,每张图片需要显示60次。

   以上always块语句的作用是一个图片翻页模块,自带状态机与处理功能。初始化状态为i = 0,rAddr = 0,表示显示第一张图片。

对比以前实验的写法:状态机与处理分开写。

     不同点:状态跳变条件与需要处理的动作条件相同,即状态跳变时刻,应当有一个响应对应状态的变化。本实验的状态变化不是一个完整的回路。分析本实验case里面的语句,实质上还是一个查表的思想,当条件Count_Frame == FRAME;条件满足时,状态发生跳变,而没有做出相应的响应。而rAddr <= 7d0,是当Count_Frame == FRAME;这一条件不满足时,做出的响应。

    额外体会:本实验中的case/endcase模块中:

’d0:

If( Count_Frame == FRAME ) i <= ’d1;

else rAddr <= ’d0;

    之所以两条语句不分开写(状态机与响应分开的形式),还有一部分原因是里面是一个if/else条件判断语句,两条语句只执行其中的一条,并不是都会执行。

assign Rom_Addr = rAddr + m;

    rAddr表示为显示第几张图片,即ROW的区域。

    m表示行偏移量,从同步扫描填充模块获得。

    总结:

    对于动态图片的显示(多张图片)形成的动画,在同步行扫描,列填充的模块中,需要对一副图画扫描完成与否做出处理,最后提供一个扫描完成信号。

    在VGA显示控制模块中,首先要划定显示区域,根据行与列扫描地址(确定一个显示范围)。如果对同一副图片扫描次数有要求,则需要用到Frame_Sig扫描完成信号,设定一个计数器,记录扫描完成信号产生的次数。在设定不同图片行地址时,使用了case/endcase结构,集中包含了状态机。

Verilog HDL那些事_建模篇笔记(实验九:VGA驱动)的更多相关文章

  1. Verilog HDL那些事_建模篇笔记(实验一,实验二)

    实验一:永远的流水灯 扫描频率配置为100Hz,即是说扫描周期为10ms.这里需要注意的是扫描周期的概念.流水灯嘛,顾名思义,扫描周期指的是流水灯扫一轮所需要的时间.听到说周期,就应该想到在建模的时候 ...

  2. Verilog HDL那些事_建模篇笔记(实验八:键盘解码)

    1.PS2接口与协议时序图 对于PS2的接口来说,需要额外关注的是PIN5与PIN1,一个是时钟,一个是数据.PS2协议对数据的移位是“CLOCK下降沿”有效,其CLOCK的频率通常在10KHz左右. ...

  3. Verilog HDL那些事_建模篇笔记(实验七:数码管电路驱动)

    1.同步动态扫描 多个数码管的显示采用的是同步动态扫描方法,同步动态扫描指的是:行信号和列信号同步扫描,是一种并行操作. 2.数码管驱动电路实现思路      如果要求数码管显示我们想要的数字,首先需 ...

  4. Verilog HDL那些事_建模篇笔记(实验三:按键消抖)

    实验三:按键消抖 首先将按键消抖功能分成了两个模块,电平检查模块和10ms延迟模块.电平检测模块用来检测按键信号的变化(是否被按下),10ms延迟模块用来稳定电平检查模块的输入,进而稳定按键信号,防止 ...

  5. 基于Verilog HDL 的数字时钟设计

    基于Verilog HDL的数字时钟设计 一.实验内容:     利用FPGA实现数字时钟设计,附带秒表功能及时间设置功能.时间设置由开关S1和S2控制,分别是增和减.开关S3是模式选择:0是正常时钟 ...

  6. 【黑金教程笔记之003】【建模篇】akuei2的Verilog hdl心路

    Verilog hdl不是“编程”是“建模” Verilog hdl语言是一种富有“形状”的语言. 如果着手以“建模”去理解Verilog hdl语言,以“形状”去完成Verilog hdl语言的设计 ...

  7. 【转】Verilog HDL常用建模方式——《Verilog与数字ASIC设计基础》读书笔记(四)

    Verilog HDL常用建模方式——<Verilog与数字ASIC设计基础>读书笔记(四) Verilog HDL的基本功能之一是描述可综合的硬件逻辑电路.所谓综合(Synthesis) ...

  8. Verilog HDL实用教程笔记

    Verilog HDL实用教程笔记 DRC - Design Rule Check 几何规则检查ERC - Electrical Rule Check 电学规则检查自动参数提取LVS - Logic ...

  9. 【黑金教程笔记之003】【建模篇】【Lab 02 闪耀灯和流水灯】—笔记

    (1)       扫描频率和闪耀频率? 模块: /**************************************** module name:flash_module function ...

随机推荐

  1. ASP.NET Repeater 控件分页

    protected void Page_Load(object sender, EventArgs e) { HttpContext context = HttpContext.Current; co ...

  2. SpringMVC接收Post的实体/JSon数据

    接口代码: @ResponseBody @RequestMapping(value = "/test",method = RequestMethod.POST)/*只允许POST方 ...

  3. PHP与Golang如何通信?

    PHP与Golang如何通信? 最近遇到的一个场景:php项目中需要使用一个第三方的功能(结巴分词),而github上面恰好有一个用Golang写好的类库.那么问题就来了,要如何实现不同语言之间的通信 ...

  4. Sunny-Code Beta版总结会议

    时间:2015-6-12 地点:基教601 参会人员:Sunny-Code全体成员 设想和目标 我们的软件要解决什么问题?是否定义得很清楚? 我们打算做一款集成小蝴蝶功能.Ip快速修改功能.WiFi共 ...

  5. supervisord 小记

    此篇仅用作supervisord的用法,不涉及理论说明和基础介绍 supervisor(一)基础篇 使用supervisord来管理process 进程的守护神 - Supervisor superv ...

  6. CSS3新特性学习

    1.一些实用规范:盒子模型,列表模块,超链接方式,语言模块,背景和边框,文字特效,多栏布局: 2:新增的选择器selctor eg: 1) 子元素过滤伪类:div:first-child  (自动识别 ...

  7. 【科普】为什么WiFi自动信道选到的信道多数在1/6/11

    http://bbs.hiwifi.com/thread-4126-1-1.html 论坛上不少朋友很困惑,为什么小极的自动信道选择选到的信道只会在1.6.11这三个信道呢?WiFi不是一共有10几个 ...

  8. MySQL使用正则表达式比较字段中的数字

    今天遇到一个问题,需要对表中的一个类json字段的内容进行筛选,而筛选的条件是值要大于某个值.因为值的位数并不确定,考虑使用正则表达式进行筛选. 字段格式 类json的key-value字段,示例如下 ...

  9. 第六章第一个linux个程序:统计单词个数

    第六章第一个linux个程序:统计单词个数 从本章就开始激动人心的时刻——实战,去慢慢揭开linux神秘的面纱.本章的实例是统计一片文章或者一段文字中的单词个数.  第 1 步:建立 Linu x 驱 ...

  10. CE创建进程和线程

    创建进程: HWND hWnd = NULL; PROCESS_INFORMATION pi = {}; if(NULL==hWnd) { hWnd=FindWindow(NULL,_T(" ...