基于FPGA的VGA显示静态图片

时间:2022-02-19 15:42:09

  终于熬到暑假了,记过三四周的突击带考试,终于为我的大二画上了一个完整的句号,接下来终于可以静心去做自己想做的事情了,前一阵子报了一个线上培训班,学学Sobel边缘检测,之前一直在学习图像处理,但是因为一直看人家的代码,到后来难免有点空虚。所以说自己狠下心来,报了一个线上培训班,重新学习一下,自己设计Sobel边缘检测,势要摆脱抄别人代码的魔咒。所以这次图像显示部分和在彩色条纹中显示一副图片的代码,全部是我自己设计的,虽然不是什么大工程,但是还是满满的成就感,这次用的时间比较久,因为使用的是新板子,Xilinx的ZYBO,之前没用过,一直放在实验室里吃灰,所以不如把它用起来,想起来要学的东西还是很多的,慢慢学呗。

ZYNQ算是Xilinx的一款比较高端的板子了,上面有以太网接口、USB2.0/OTG、HDMI双向接口,SD卡槽,而且板子内部还嵌入了ARM,上面可以跑linux,价格也不菲。刚开始查了一下手册了解到板子晶振是50Mhz,然后试了半天就是没有把VGA驱动起来,后来在仔细查了一下手册,这款板子在某种情况下板子提供的是125Mhz引脚为L16,然而我不知道怎么用50Mhz,那就直接用125Mhz吧。前面没写过关于VGA的博客,这次就顺带写一下吧。

VGA显示其实就是两条线,一个是行扫描,一个是场扫描,在行有效和场有效的时候把数据发送给VGA即可显示了。显示标准就是@60hz即一秒屏幕刷新60次,拿640x480@60HZ做例子,即行为640个像素,场为480个像素。

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

基于FPGA的VGA显示静态图片

图 – VGA屏幕扫描原理

行消隐(HBlank)在将光信号转换为电信号的扫描过程中,扫描总是从图像的左上角开始,水平向前行进,同时扫描点也以较慢的速率向下移动。当扫描点到达图像右侧边缘时,扫描点快速返回左侧,重新开始在第1行的起点下面进行第2行扫描,行与行之间的返回过程称为水平消隐。一幅完整的图像扫描信号,由水平消隐间隔分开的行信号序列构成,称为一帧。扫描点扫描完一帧后,要从图像的右下角返回到图像的左上角,开始新一帧的扫描,这一时间间隔,叫做垂直消隐,也称场消隐(VBlank)。我们称行同步、场同步。

行场消隐信号:是针对老式显像管的成像扫描电路而言的。电子枪所发出的电子束从屏幕的左上角开始向右扫描,一行扫完需将电子束从右边移回到左边以便扫描第二行。在移动期间就必须有一个信号加到电路上,使得电子束不能发出。不然这个回扫线会破坏屏幕图像的。这个阻止回扫线产生的信号就叫作消隐信号,场信号的消隐也是一个道理。

基于FPGA的VGA显示静态图片

图 – 行扫描

基于FPGA的VGA显示静态图片

图 – 场扫描

基于FPGA的VGA显示静态图片

图 – VGA扫描时序

如上图的扫描参数已经有官方的标准了,这里我就不再做记录了,到时直接用就可以了。

  我这里选用的是640X480@60HZ分辨率显示,ZYBO的板子晶振是125Mhz,所以首先要先进行分频,我这里直接用Vivado调用PLL。还没有过用Vivado调用PLL的博客,现在总结一下吧,以防后面忘记。基于FPGA的VGA显示静态图片

点击IP catalog进行IP设置基于FPGA的VGA显示静态图片

为了快速找到想要的IP,在右上角直接搜索Clocking,然后就会出现如图所示界面,双击clocking wizard,进行PLL的配置基于FPGA的VGA显示静态图片

弹出如图所示界面后,一次按上图进行配置,在component name中写下IP的名字,把show disabled ports勾选为空,在primitive中选择MMCM,在input clock information中选择输入时钟。这里的MMCM我查了一下就是他包含了PLL,所以我们直接选择MMCM。但是有时候如果选择PLL也会出现错误,所以一般首选MMCM。基于FPGA的VGA显示静态图片

这里设置输出时钟,还可以设置相位和占空比。基于FPGA的VGA显示静态图片

选择复位为低电平触发、选择locked

基于FPGA的VGA显示静态图片

这里可以自定义端口名

基于FPGA的VGA显示静态图片

基于FPGA的VGA显示静态图片

点击OK,Generate,即可生成PLL IP Core基于FPGA的VGA显示静态图片

点击IP source、找到后缀为.veo的文件,双击打开基于FPGA的VGA显示静态图片

里面的内容就是可以直接实例化调用的端口生成。

这样便完成了VGA驱动时钟的生成,这里我把其他几种显示格式的参数和RGB显示的参数贴出来,这样便省去了不少事情。然后就是把你要显示的数据在行扫描有效和场扫描有效的时候输出,即可在显示屏显示了。其实这个显示并不难,那我为什么要专门写篇博客记录呢?因为以前老是看别人的代码,看的多了,自己的能力还是没有多大提升,但这部分显示图片是完全我自己分析时序显示出来的,所以有很大的成就感。学习这个东西还是得有人教导,从我学习FPGA以来,都是自己一个人瞎琢么,学习了一年了还没有一个好的画时序图的习惯,到仿真的时候再凑出时序图,还是要从基础抓起,不能只会敲代码。时序设计是关键,设计思想必须有。

要显示一个彩色条纹也是比较简单的,例如在前一百五十行给VGA的数据为白色的,中间180行给VGA的数据为绿色,后面相同的方法。我这里要做的实验是在显示屏的左上角开一个200x200的框,最后将一幅200x200的图片显示进去,首先开一个200x200的正方形框,实现的方法就是控制行有效计数器计到需要显示正方形框的时候紫色的数据给lcd_data,行计数器为0-200,其他情况还是前面显示条纹的数据,同样的场有效计数器也从0-200计数时显示紫色数据带lcd_data,这样就会在显示屏左上角形成一个正方形的框。如下图所示。基于FPGA的VGA显示静态图片

要显示一张图片到VGA就需要调用IP Core,我这里需要调用一个单口RAM IP,使用软件将图片生成十六进制的数据,可以用MATLAB,我这里推荐一款软件,是一个业界名人自己写的十分好用,如下图所示,只需要将图片加载进去,就可以生成你想要的图像数据格式了,这里要注意生成的图像数据RGB的位宽,一定要和你板子的VGA位宽一致,否则显示不出来的。

基于FPGA的VGA显示静态图片

基于FPGA的VGA显示静态图片

  使用这个软件转化之前,除了阅读板子手册看你的板子RAM的容量能装下多大的图像数据,需要找一张合适的图片,这里小提示一下,可以用windows自带的画图软件将图片打开,右键重新调整大小去掉保持纵横比,选择像素,这样就可以任意修改图像大小了!RAM配置可参考我前面的相关博文:基于Vivado调用ROM IP core设计DDS

注:Xilinx是.coe文件、Intel (Altera)是.mif文件,这两种文件只是格式不同但本质上是一样的。

基于FPGA的VGA显示静态图片

  RAM/ROM读取有延时,要在扫描第一个点的前两个时钟周期读取RAM/ROM,我这里用的是双口RAM,在Vivado这里显示的是有两个时钟的周期的延时,也就是当你给读命令时,RAM会把读出来的数据缓存两级在才会输出给你想给数据的地方。基于FPGA的VGA显示静态图片

  我这里遗留一个问题,在学习开源骚客的教程的时候,上面说的需要提前两个时钟周期给RAM地址,这样出来的数据才能同步,我试了好久都没有成功,在这个问题上浪费的时间太长了,后面有机会再去解决吧。我要进行下面的课程学习了。我认为RAM数据出来的端口是一直有数据的,而且我最终显示出来的静态图片也是完整的,没有观察到像素点的缺失,所以这里这个问题保留,后面我在学习的过程中再想办法把它搞清楚解决掉。

  这次的基于FPGA的图像显示部分代码,完全是我自主设计,虽然不是很高的技术含量,但是总算摆脱了抄别人代码的魔咒了,最后所有工作都做好后,下载板子就会呈现下面这一幅图的样子,这样看来显示效果还挺不错的呢!基于FPGA的VGA显示静态图片

基于FPGA的VGA显示静态图片

转载请注明出处:NingHeChuan(宁河川)

个人微信订阅号:NingHeChuan

如果你想及时收到个人撰写的博文推送,可以扫描左边二维码(或者长按识别二维码)关注个人微信订阅号

知乎ID:NingHeChuan

微博ID:NingHeChuan

原文地址:http://www.cnblogs.com/ninghechuan/p/7260383.html