基于FPGA的VGA显示静态图片

    之前学习了半年的图像处理,所以计划将自己学过的几个图像处理的基础算法,做过的设计记录下来,在OpenHW论坛上发表,计划是这样的,用VGA做显示,使用PC端上位机通过串口发送一幅图片数据到FPGA开发板,FPGA接收数据并做处理最终发送给VGA显示屏显示,计划要写的算法有彩色图像转灰度、均值/中值滤波、Sobel边缘检测等。那么现在这是第一篇,先来写VGA显示的驱动、以及将一幅图片显示到VGA显示屏上。

  第一步是硬件平台的选取,我身边正好有一块Xilinx的ZYNQ开发板,ZYNQ算是Xilinx的一款比较高端的板子了,上面有以太网接口、USB2.0/OTG、HDMI双向接口,SD卡槽,而且板子内部还嵌入了双核ARM Cortex-A9处理器,上面可以跑linux,价格也不菲。ZYNQ是一款全可编程逻辑开发板(All Programmable)。什么是全可编程逻辑开发板,就是可以用硬件描述语言变成,可用C语言、Python等软件编程语言编程。这款开发板有PS(Processor Subsystem)和PL(Programmable Logic)两部分,当然我这里这回用到PL部分资源。通过查阅手册和实验确定ZYNQ在PL(Programmable Logic)模式下,开发板引脚L16连接系统时钟晶振为125Mhz,VGA为16位RGB565显示。

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

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

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

 

图 – VGA屏幕扫描原理

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

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

图 – 行扫描

图 – 场扫描

图 – VGA扫描时序

        那么扫描时钟是多少呢?这个其实是可以计算出来的,根据一帧(即扫描一次屏幕需要60分之1秒)需要的时间可以计算出每一个像素点需要的时间。我这里就不计算了直接用官方给出的数据就行了,我这里直接给出官方手册,可以自己查阅。如图所示的一些参数和其几种显示格式的显示参数还有RGB的几种颜色的显示组合,我都会给出来,

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

点击IP catalog进行IP设置

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

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

这里设置输出时钟,还可以设置相位和占空比。

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

这里可以自定义端口名

点击OK,Generate,即可生成PLL IP Core

点击IP source、找到后缀为.veo的文件,双击打开

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

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

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

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

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

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

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

  我这里将RAM读取设置为always enable, RAM数据出来的端口是一直有数据的,而且我最终显示出来的静态图片也是完整的,没有观察到像素点的缺失,所以先不管这两个时钟周期的延时。

         这次的基于FPGA的图像显示部分代码,完全是我自主设计,虽然不是很高的技术含量,但是总算摆脱了抄别人代码的魔咒了,最后所有工作都做好后,下载板子就会呈现下面这一幅图的样子,这样看来显示效果还挺不错的呢!(lena美女很漂亮,这里看不出是200x200的图片是因为,显示器自动调节合适的显示宽度)

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

  如果你想获得本文的所有课件和工程代码,请关注本人的个人微信订阅号:开源FPGANingHeChuan或扫描下方二维码关注订阅号,在后台回复图像处理,即可获得本文的所有课件、资料、和工程源码哦!

 

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

个人微信订阅号:开源FPGANingHeChuan

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

知乎ID:NingHeChuan

微博ID:NingHeChuan

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

转载于:https://www.cnblogs.com/ninghechuan/p/7260383.html

### FPGA VGA 图像消隐实现方法 在FPGA设计中,VGA接口通常用于显示静态或动态图像。为了实现图像的消隐效果,可以通过控制像素时钟信号以及同步信号来调整屏幕上特定区域的内容。以下是关于如何在FPGA中实现VGA图片消隐的具体说明: #### 1. 像素位置判断 通过计算当前扫描线的位置(水平和垂直坐标),可以确定屏幕上的每一个像素点是否位于可见区域内。如果某个像素超出了指定的有效范围,则将其设置为黑色或其他背景颜色以达到消隐的效果。 对于标准640×480分辨率下的VGA信号来说,其水平总周期为800个像素,其中只有前640个像素被实际显示;而垂直方向上则有525行数据传输时间,但仅前480行为有效视频行[^1]。因此,在程序逻辑里需定义好这些边界条件以便于后续处理操作。 ```verilog always @(posedge clk or negedge reset_n) begin : pixel_position_calculation if (!reset_n) begin h_count <= 0; v_count <= 0; end else begin if (h_count == H_TOTAL - 1) begin // 当到达一行结束时重置计数器并增加列索引 h_count <= 0; if (v_count == V_TOTAL - 1) begin // 如果已经到了最后一行也重新开始新的一帧渲染过程 v_count <= 0; else v_count <= v_count + 1'b1; end else h_count <= h_count + 1'b1; end end ``` 此段代码片段展示了如何利用状态机更新每一帧中的横纵坐标的数值变化情况,并据此决定何时进入新的扫描阶段或是完成整个画面刷新循环的过程[^1]。 #### 2. 控制RGB输出值 一旦确认某一点处于非活动区即超出预设界限之外之后就可以简单地把对应的颜色分量全部赋零从而形成所谓的“黑屏”现象也就是我们所说的消除功能的一部分表现形式之一: ```verilog assign red = (valid_pixel)? image_data[23:16] : 4'd0 ; assign green = (valid_pixel)? image_data[15: 8] : 4'd0 ; assign blue = (valid_pixel)? image_data[ 7: 0] : 4'd0 ; // valid_pixel 是基于之前提到过的 h/v_counts 来判定的一个布尔表达式, // 它表明当前正在访问的是不是有效的可视范围内的一位象素单元。 ``` 以上Verilog模块实现了根据不同条件下切换不同色彩强度的功能,当检测到该位置不属于正常展示部分的时候就强制关闭光源使得看起来就像是隐藏掉了这部分图形信息一样[^1]. #### 总结 综上所述, 若要实现在FPGAs项目里的VGA端口支持下对某些特殊场合需求所提出的所谓'消影'(Blanking)机制的话就需要从两个方面入手分析解决问题方案——一方面要精确把握住各个关键时间节点关系进而合理安排各路数字脉冲序列走向趋势规律特点等等因素相互配合协作共同作用最终达成目标要求;另一方面也要善于运用高级硬件描述语言编写简洁明了易于维护扩展升级可能性较高的源文件架构体系结构模式框架等内容物项资源素材资料档案记录文档等形式载体呈现方式展现形态等方面加以综合考量权衡取舍择优录取采纳实施执行落地生根开花结果繁荣昌盛兴旺发达起来才行啊!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值