基于Zynq的图像增强系统之图像输出篇(使用Zybo开发板)

 

从标题中你大概就能够猜到,这个项目的主要目的是使用Zynq ApSOC制作一个图像增强系统。更具体地说,我们希望建立一个能清除图片或者视频中模糊影像的系统。该系统将以恶劣条件下的视觉数据作为输入,利用图像增强技术进行处理,然后输出结果。...

来源 | DIGILENT中文技术社区
翻译贡献:DIGILENT翻译团成员 - 追随我心
❖ 
从标题中你大概就能够猜到,这个项目的主要目的是使用Zynq ApSOC制作一个图像增强系统。更具体地说,我们希望建立一个能清除图片或者视频中模糊影像的系统。该系统将以恶劣条件下的视觉数据作为输入,利用图像增强技术进行处理,然后输出结果。



该项目是在Digilent Zybo开发板上进行创建和测试的,也能够应用于其它的ZYNQ设备。我们把这个项目划分为三部分:

1) INPUT = 通过计算机或者摄像机以以太网进行图像的输入;

2)PROCESS = 图像处理;

3)OUTPUT = 通过HDMI接口进行图像输出。

以一种违反常理的方式,项目的第一步我们将先从图像输出部分开始,第二步来操作输入部分,最后再完成图像处理部分——主要是因为这样的先后顺序会给我们提供更多地调试机会。今天我们主要分享的是图像输出部分。
1
项目材料的准备

为了完成这个项目,你需要准备:

1. 硬件

  • 具有HDMI和以太网接口的ZYNQ开发板(我们用的是Diligent Zybo)
  • USB数据线
  • HDMI线
  • 以太网线
  • 具有HDMI接口的输入显示屏
2. 软件

  • Xilinx Vivado
  • Xilinx SDK
2
VGA控制器(1)



我们将使用板载的HDMI接口来进行图像数据的输出。HDMI接口与ZYNQ上的PL端(即Programmable Logic = FPGA)相连,因此我们需要使用VHDL设计一个控制器来控制HDMI接口。如果你曾经设计过VGA控制器,你会发现两者的设计非常相似。HDMI和VGA时序上是一致的,事实上你可以在现有的VGA控制器的基础上进行设计以获得一个HDMI控制器。

为了更好地帮助大家了解这是怎么一回事儿,在此我们会先设计一个VGA控制器。首先,我们需要的输出分辨率为1920*1080。VGA控制器主要是用来负责像素数据的传输(以RGB格式),从而使像素逐一显示。1920*1080的实际显示区域外也有一些“边界”区域,也就是:前廓、后廓和回描。对于任意一种分辨率而言,这些“边界”区域的像素大小都是标准的并且是具体的。事实上,这些区域不会出现在屏幕上,但它们是受命令控制的,并且这个区域的像素颜色必须是黑色的。那么问题来了:为什么我们需要这些“额外”的区域呢?这个问题恰好与本文的教学目的相反,但如果你感兴趣的话,我会鼓励你去进一步探索。关于这个问题,在这里分享一个很好的解释VGA接口的视频教程,链接如下:www.digilent.com.cn/studyinfo/61.html

在我们的这一项目中,需要的显示分辨率为1920*1080,以下是相关的时序参数

  • 水平显示区域 = 1920 像素
  • 水平前廓 = 88 像素
  • 水平后廓 = 148 像素
  • 水平回描 = 44 像素
  • 垂直显示区域 = 1080 像素
  • 垂直前廓 = 4 像素
  • 垂直后廓 = 36 像素
  • 垂直回描 = 5 像素
(想要了解其它分辨率的参数设置,可参考:http://goo.gl/hFNRVb)因此从上面可以看出,我们的实际分辨率将达到 2200*1125。我们需要每秒传输60帧,所以我们所需要的时钟频率为60*2200*1125=148.5MHz。在Zybo开发板上有一个为125Mhz的时钟源。我们可以使用一个MMCM IP核产生我们所需要的148.5Mhz的像素时钟。
3
VGA控制器(2)

根据前面的理论背景资料,看到这里相信你应该能够设计出属于你自己的VGA控制器了。在这里,我们为你提供了一个做好的Vivado项目工程(点击「阅读原文」下载),但建议你至少自己动手做一遍(而不是直接伸手拿来使用)。

大多数的VGA端口不会给你8位真彩输出(见上图),因此你需要根据所用板子所提供的每种颜色的引脚数来调整设计。在所提供的工程文档中,除了左上角像素是红色,其余整个屏幕将是蓝色。需要指出来的是,这个项目使用了ZYBO的约束文件。因此,如果你想在其它开发板上运行这个项目,你应该更新约束文件并且调整每种颜色的引脚数。从上图中可知,当我们的VGA控制器每种颜色输出为5/6位时,对于每一种颜色通道而言(红色、绿色、蓝色),在通过电线之前,这些位都会被转换成一个模拟信号。
4
HDMI控制器(1)
到这里,我们已经知道了VGA控制器是怎么工作的,并且我们已经有了一个设计好的工程,接下来,我们将开始HDMI控制器的设计部分。实际上,HDMI控制器将使用我们已经开发的VGA控制器的所有代码。HDMI和VGA使用相同的时序和信号,不同之处在于输出引脚上。在VGA的传输上,每种颜色通道使用一根线并把信号通过电线转换为模拟信号;而HDMI则通过数字传输数据的方式,对每种颜色一次传输1位,并且使用差分信号。差分信号意味着每位HDMI有两个引脚与另外一个相反。因此,如果我们想传递一个信号“1”,我们将信号“1”传输到一根线上并且在另外一根线上取消信号“1”的传输,这样便确保了信号的完整性。想要了解这一部分的更多资料,请点击:https://goo.gl/6CPCzB。对于每种颜色(红色,绿色,蓝色)以及时钟而言,都有一个这样的通道。由于差分信号的特性,我们通过HDMI所发送的信号必须是稳定的直流信号,这意味着在相同的时间内1和0的数量必须大致相等。要实现这一部分,我们将使用8b/10b进行编码。想要了解到很多关于差分信号和8b/10b编码工作,请点击:http://goo.gl/hhh8Ge(DVI和HDMI使用相同的视频信号)。
5
HDMI控制器(2)有了足够的理论基础,现在让我们开始我们的项目吧! 在VGA控制器中,我们只需要148.5MHz的时钟频率。而针对HDMI控制器,我们则需要10倍的时钟频率,这是由于我们需要让每种颜色传输8位并且使用8b/10b编码让每个像素传输10位,因此我们需要的时钟信号频率为148.5*10=1485MHz。这是一个相当大的时钟信号,在Zybo开发板上并不能获得。幸运的是,在这里我们有自己的锦囊妙计。我们能够实现5*148.5MHz=742.5MHz的时钟信号,并使用OSERDES (serializer) IP核来传输742.5MHz时钟信号的上升沿和下降沿,通过这一方法我们实际上就能够获得1485MHz的时钟信号。在实际设计中,Vivado会为此跳出一些时序警告,这里我们无需在意这些警告(注:实际上上述这一方法很管用,这些警告的跳出只是由于时序缓存官方定义上并不支持大于464MHz的频率)。当然如果你愿意牺牲图像分辨率的话,你也可以使用一些更小的时钟信号。因此基于上述,这里我们所需做的是将我们的VGA控制器输出以8b/10b方式进行数据编码,然后通过之前提到的方式将其串行化。此外,我们需要为项目增加一个MMCM来产生742.5MHz的时钟以用于串行化。在主贴中,我们上传了编码器和串行器的VHDL文件(可点击「阅读原文」下载)。你需要先对RGB信号通道进行编码,然后再进行串行化。以红色信号通道为例:

TMDS_encoder_RED : TMDS_encoder

port map(clk148, red_channel_8bits, c_red, video_on, encoded_red_10bits);

Serialiser_RED : Serialiser10_1

port map(clk148, clk742, encoded_red_10bits, reset, red_serial_1bit);对于红色和绿色信号通道来说,TMDS_encoder的输入“c”就是“00”,而针对蓝色则是“vsync和hsync”(若想更多的了解DVI规范,请点击:http://goo.gl/hhh8Ge)。
6
CDMA和分组设计(1)



HDMI控制器的目的是显示处理后的图像。到这一步,随着控制器的实现和准备就绪,是时候考虑该如何为这一控制器传送数据了。考虑到大量的图像增强处理将在PS(Processing System=ARM处理器)部分完成,并存储在DDR内存中,所以在这里我们需要实现从RAM中获得数据并将之传输到HDMI控制器。实际上,在这里可以有很多实现方式的选项,包括:

  • VDMA IP with a AXI STREAM to Video out IP
  • DMA IP with AXI STREAM to Video out IP
  • The DMA in the PS (visible in the scheme above)
  • CDMA IP
第一种和第二种方法都是比较好的选择,但是他们会使用相当多的FPGA资源。第三种方法在表现上不是特别理想,因为它只能使用GP端口而不能使用HP端口。第四种方法是我们这个项目所使用的方法,CDMA较少地占用FPGA逻辑,并且它能使用HP端口
7
CDMA和分组设计(2)

因此,我们的计划是在PS端通过AXI LITE接口对CDMA进行编程,以从DDR内存中的HP0端口读入4行图像信息,并在PL端使用AXI BRAM IP核(这个IP核主要用于CDMA的AXI Master接口和BRAM接口之间的转化),把数据写到BRAM中。这些图像数据一旦存储在BRAM中,他们很容易被HDMI读取并在显示屏上显示出来。需要注意的是,在我们完成上述4行对CDMA的重新编程并开始转至接下去的几行后,我们必须为CPU提供一个中断。我们还需要为图像的结束提供一个额外的中断,以便图像信息整齐。我们必须给HDMI控制器增加这项功能,并将其整合到IP中,以便在使用分组设计中更容易使用。在HDMI控制器产生的中断将与PS端的共享IRQ_F2P中断相连(若要了解更多关于中断的信息,请点击:http://goo.gl/nEQrBv)。

我们也需要增加时钟信号(FCLK_CLK0)频率。在分组设计中,这个时钟信号用于所有的AXI IP。该时钟信号同时被用于将数据写到BRAM中,因此我们需要它比读取的时钟信号(像素的时钟频率=148.5Mhz)要快。这里我们将把频率调整到一个安全的时钟频率即250Mhz。

我们需要计算我们所需的BRAM数量。在BRAM中,每次传输4行图像数据,因此我们所需要的字节:4行*1920像素*3基色=23040字节。然后,我们可以在Vivado中使用地址编辑将BRAM的字节宽度设置为32KB。

随着硬件配置的完成,我们将进入软件部分。
8
SDK

随着硬件的设置完成,我们将开始在PS中完成软件设计部分。在SDK软件中,生成比特流文件并下载到开发板上,运行程序即可。

1) File -> Export -> Export Hardware -> 勾选Include Bitstream并点击OK

2) File -> Launch SDK

在SDK创建一个新的应用项目:

3) File -> New -> Application Project

4) 为你的项目选择一个名字并点击 Next

5) 选择“Hello World” 模板并点击Finish这一SDK应用项目需要给CDMA编写程序,并响应早先在PL中设置好的中断。此外我们需要配置GIC(通用中断控制器)以执行常规中断。为了实现这个功能我们使用了一些通用函数,使得代码持续执行而不中断。为了测试我们的设计,我们使用了SDK Restore(Xilinx Tools ->Dump/Resotre)功能将图像特征信息存储到DDR内存中,并将处理后的图像通过HDMI控制器在显示屏上输出。你可以将图像存储在任何地方(除了内存开始处的一些小的限制区域)。例如,我们选择地址16777216,文件大小8294400 = 1920*1080*4(4通道 = RGB + alpha)。

最终,我们的测试结果看上去非常不错!在这里,我们也同时将C代码与存储到闪存中的图像文件分享给到大家,您可点击「阅读原文」下载未完待续...

DIGILENT是Xilinx大学计划开发板的原厂

对项目技术有任何问题或建议,敬请关注以下微信公众号询问“开源硬件创客坊”或加入我们的QQ群探讨:536477292


    关注 FPGA开发圈


微信扫一扫关注公众号

0 个评论

要回复文章请先登录注册