8.1 概述本课程将对Xilinx提供的一款IP核——AXI VDMA(Video Direct Memory Access) 进行详细讲解,为后续的学习和开发做好准备。内容安排如下:首先分析为什么要使用VDMA、VDMA的作用;然后详细介绍VDMA的特点、寄存器作空间; 最后阐述如何使用VDMA,包括IP核的配置方法、代码编写流程等。 本章主要是理论学习,学习完本章,会对VDMA有全面的认识,有利于学习后续的图像生成、视频采集处理系统。由于VDMA主要用于视频流数据的存取,单独测试的意义不大,所以在接下来的章节会提供一些样例设计,进一步学习如何使用VDMA。 8.2 为什么要用VDMA 在讲解VDMA之前,先来探讨一下为什么要学习和使用VDMA,以明确学习目的。由于使用VDMA可以方便地实现双缓冲和多缓冲机制,所以本小节引入了帧缓存和缓冲机制的概念。VDMA本身能够高效地实现数据存取,所以在图像、视频处理系统中,VDMA可谓是必不可少的。 8.2.1 什么是帧缓存帧缓冲存储器(Frame Buffer):简称帧缓存或显存,它是屏幕所显示画面的一个直接映象,又称为位映射图(Bit Map)或光栅。帧缓存的每一存储单元对应屏幕上的一个像素,整个帧缓存对应一帧图像。 在开发者看来,FrameBuffer 是一块显示缓存,往显示缓存中写入特定格式的数据就意味着向屏幕输出内容。所以说FrameBuffer就是一块画布,系统在画布上绘制好画面之后,就可以通知显示设备读取Frame Buffer进行显示了。 注意,笔者这里所说的Frame Buffer和Linux的Frame Buffer不是同一个概念,这里仅指显示缓存(画布)本身,并不是Linux下的一个设备。 8.2.2 双缓冲机制最早解释多缓冲区如何工作的方式,是通过一个现实生活中的实例来解释的。在一个阳光明媚的日子,你想将水池里的水打满,而又找不到水管的时候,就只能用手边的木桶来灌满水池。水桶满了之后,关掉水龙头,将水提到水池旁边,倒进去,然后走回到水龙头。重复上述工作,如此往复直到将水池灌满。这就类似单缓冲工作过程,当你想将木桶里的水倒出的时候,你必须关掉水龙头。 现在假设你用两个木桶来做上面的工作。你会注满第一个木桶然后将第二个木桶换到水龙头下面,这样,在第二个水桶注满的时间内,你就可以将第一个木桶里面的水倒进水池里面,当你回来的时候,你只需要再将第一个木桶换下第二个注满水木桶,当第一个木桶开始注水的时候你就将第二个木桶里面的水倒进水池里面。重复这个过程直到水池被注满。很容易看得到用这种技术注满水池将会更快,同时也节省了很多等待木桶被注满的时间,而这段时间里你什么也做不了,而水龙头也就不用等待从木桶被注满到你回来的这段时间了。 当你雇佣另外一个人来搬运一个被注满的木桶时,这就有点类似于三个缓冲区的工作原理。如果将搬运木桶的的时间很长,你可以用更多的木桶,雇佣更多的人,这样水龙头就会一直开着注满木桶了。 在计算机图形学中,双缓冲是一种画图技术,使用这种技术可以使得画图没有(至少是减少)闪烁、撕裂等不良效果,并减少等待时间。 双缓冲机制的原理大概是:所有画图操作将它们画图的结果保存在一块系统内存区域中,这块区域通常被称作“后缓冲区(back buffer)”,当所有的绘图操作结束之后,将整块区域复制到显示内存中,这个复制操作通常要跟显示器的光栈束同步,以避免撕裂。双缓冲机制必须要求有比单缓冲更多的显示内存和CPU消耗时间,因为“后缓冲区”需要显示内存,而复制操作和等待同步需要CPU时间。 基于双缓冲机制可以实现页交换,页交换初始状态如下图所示: 如上图所示,此时由于处于初始状态,画图操作的结果都在后缓冲区中,而屏幕上显示的则是前缓冲区中的内容。此时画图操作尚未完成,画图操作完成之后,页转换操作开始执行,示意图如下图所示: 如上图所示,画图操作结束,下一个画图操作的结果保存对象指向前缓冲区,屏幕的显示对象指向后缓冲区,此时前缓冲区变成实际意义上的后缓冲区,后缓冲区变成实际意义上的前缓冲去,即实现“页交换”操作。 有时候也在页交换链中设置多个“后缓冲区”,这是就需要多缓冲区机制的支持。 8.2.3 VDMA的作用VDMA数据接口可以分为读、写通道,用户可以通过写通道将AXI-Stream类型的数据流写入DDR3,通过读通道可以从DDR3读取数据,并以AXI-Stream类型的格式输出。由此可知,VDMA本质上是一个数据搬运IP,为数据进、出DDR3提供了一种便捷的方案。 将数据存入DDR之后,CPU就可以进行一些处理(缩放、裁剪等),然后再送至显示设备,达到期望的应用目的。当然,也可能是简单地对捕获的视频进行解析,将数据存入帧缓存,以供显示。 VDMA可以控制多达32个帧存,并可以自由地进行帧存切换,所以就能够轻松地实现双缓冲和多缓冲操作。这也是一个很重要的特性,在后续进行系统设计的时候,通常是采用多缓冲的方式实现显示。 由以上分析可以发现,在图像、视频处理系统中使用VDMA是十分有必要的。 8.3 VDMA概述AXI VDMA是Xilinx提供的软核IP,用于将AXI Stream格式的数据流转换为Memory Map格式或将Memory Map格式的数据转换为AXI Stream数据流,从而实现与DDR3进行通信。 许多视频类应用都需要帧缓存来处理帧率变化或者进行图像的缩放、裁剪等尺寸变换操作。AXI VDMA设计的初衷就是用于高效地实现AXI4-Stream视频流接口和AXI4接口之间的数据传输。 VDMA的关键特性&优势有以下几点:
AXI VDMA框图如下所示。 主要有以下几种接口类型:
从框图中可以看出,VDMA主要由控制和状态寄存器、数据搬运模块、行缓冲这几部分构成。数据进出DDR要经过行缓冲进行缓存,然后由数据搬运模块写入或者读出数据。数据搬运模块具体如何工作,由相关寄存器负责控制。VDMA的工作状态可以通过读取状态寄存器进行获取。 8.4 VDMA详细介绍8.4.1 接口8.4.1.1 时钟和复位各种总线都有自己的时钟信号,不用特别说明,需要指出的是,这些时钟是异步的,并不需要用同一个时钟。但在设计过程中,如无特别需求,可以使用相同的时钟,以降低设计难度。 同步复位信号axi_resetn,同步时钟为s_axi_lite_aclk,低电平有效(至少要保持16个时钟周期的低电平,才能够生效),有效时复位整个IP核。 8.4.1.2 AXI总线相关信号
前缀S_、M_分别表示Slave和Master;后缀MM2S、S2MM说明数据流向是从memory map到stream还是从stream到memory map。具体每个接口所包含的信号,在基础篇第20章已有介绍,此处不再重复。 8.4.1.3 视频同步接口信号
8.4.1.4 GenLock相关信号在下一节将详细介绍这些信号的作用和应用场合。
8.4.2 VDMA帧存格式在讲述寄存器时,需要设定和显示(帧存)相关的参数,为了方便读者的理解,这里先介绍VDMA数据存放框架,如下图所示,黑色实线内的区域为实际存储画面的帧存。 图中H_STRIDE代表水平方向上的跨度,H_SIZE表示水平方向数据总量,V_SIZE表示竖直方向总共有多少行。 至于帧存内部数据如何组织,就取决于软件代码和硬件逻辑如何匹配了,通常来讲,数据存放格式为RGB+Alpha或者Alpha+RGB。 8.4.3 读写通道工作时序清晰地理解VDMA读写通道的工作时序,对以后的设计有很大的帮助,很多设计都是根据本小节所示的样例时序设计出来的。在下一章,读者就能够有所体会。 8.4.3.1 读通道(MM2S)时序下图描述了读通道的时序,5行,每行16字节,跨度为32字节。 从图中可以看出:在收到mm2s_fsync信号后,VDMA在m_axi_mm2s_araddr的起始地址处发出m_axi_mm2s_arvalid信号。M_axi_mm2s_arvalid总共有效5次,分别获取一帧的5行数据。从MM读取的数据存储在行缓存里,当收到来自axi-stream端的m_axis_mm2s_tvalid信号后,将数据发送到axi-stream端。每一行的结束,axi-stream端会使m_axis_mm2s_tlast有效。 8.4.3.2 写通道(S2MM)时序下图描述了写通道的时序,5行,每行16字节,跨度为32字节。 从图中可以看出:在收到s2mm_fsync信号后,VDMA发出s2mm_fsync_out和s_axis_s2mm_tready表明已经准备好接收来自axi-stream端的数据。读取到的数据存储在行缓存里,m_axi_s2mm_awvalid有效后,紧接着有效m_axi_s2mm_wvalid信号,同时将数据放至m_axi_s2mm_wdata。 8.4.4 寄存器VDMA的寄存器如下表所示。所有寄存器都被映射到非缓存内存空间。该内存空间必须按照AXI字(32位)进行对齐,换句话说,寄存器偏移地址至少间隔4个字节。
所有寄存器字节序都是小端格式,如下图所示。 各个寄存器的名称和大致作用从上表就可以看出,接下来,笔者会详细介绍重要寄存器的具体bit的作用。明白了每个bit的作用之后,自然就知道写入什么值能够达到自己的控制目的。 从上表可以看出,寄存器可以分为两组,分别对应MM2S通道和S2MM通道,两组寄存器的功能是相似的,区别仅在于偏移地址和所服务的对象。因此,在学习完MM2S通道的所有寄存器之后,只要大致浏览一下S2MM通道对应的寄存器的关键位即可(个别位不相同),在使用高级功能时,再仔细查阅VDMA用户手册。 8.4.4.1 MM2S VDMA 控制寄存器(00h)顾名思义,该寄存器用于控制VDMA,具体可以实现复位、使能锁相同步、设定帧存切换模式、启动VDMA读写通道等操作。每一位作用如下图所示,低4位是最重要的,接下来会详细介绍。
8.4.4.2 MM2S VDMA 状态寄存器(04h)该寄存器用于获取VDMA工作状态。每一位作用如下图所示,低4位是最重要的,接下来会详细介绍。
8.4.4.3 PARK_PTR_REG停留指针寄存器(28h)该寄存器用于管理读、写通道的数据传输。
学习了这个寄存器之后,就可以发现:当VDMA工作在Parked模式下,通过操作该寄存器,就能够实现帧缓存的切换,建立自己想要的缓存切换机制。 8.4.4.4 MM2S 帧存起始地址(0x5C~0x98)有最多32个寄存器用于存放帧存起始地址,其分别存在于两个寄存器bank上:bank0和bank1,每个bank上有16个寄存器。这两个bank上有相同的起始偏移地址(0x5C),选择这两个bank可以通过MM2S_REG_INDEX的值进行选择。假如想访问第1个寄存器,则给MM2S_REG_INDEX赋值为0,并设定偏移地址为0x5C;如果想访问第17个寄存器,需要将MM2S_REG_INDEX设为1,并设定初始偏移地址为0x5C。 8.4.4.5 MM2S_FRMDLY_STRIDE MM2S帧延迟和跨度(58h)该寄存器有两个作用,第一是bit24~bit28指定帧延迟,仅用于Genlock从模式,指定从接口比主接口至少要延迟多少个帧;第二是低16位指定水平方向的跨度,同样以字节为单位。所谓跨度是指每两行第一个像素之间间隔的数据个数,具体请参考22.3.2小节,VDMA帧存格式。 8.4.4.6 MM2S_HSIZE MM2S水平方向尺寸(54h)该寄存器的低16位用于指定每一行有多少字节的数据需要传输。例如显示分辨率为640*480,每个像素4个字节(RGB+Alpha),该值应该设定为640*4。 8.4.4.7 MM2S_VSIZE MM2S垂直方向尺寸(50h)该寄存器有两个作用,第一是用低13位指定总共有多少行;第二是启动MM2S的传输。当MM2S_VDMACR.RS=1,对该寄存器的写操作会将所有设定参数传递给VDMA内部寄存器模块,用于VDMA控制。对某个通道进行配置时,必须在最后一步设置该寄存器。 8.4.4.8 S2MM VDMA 控制寄存器(30h)顾名思义,该寄存器用于控制VDMA S2MM通道,具体可以实现复位、使能锁相同步、设定帧存切换模式、启动VDMA读写通道等操作。每一位作用如下图所示,低4位是最重要的,接下来会详细介绍。
8.4.4.9 S2MM VDMA 状态寄存器(34h)该寄存器用于获取S2MM工作状态。每一位作用如下图所示,低4位是最重要的,接下来会详细介绍。
8.4.4.10 S2MM 帧存起始地址(0xAC~0xE8)有最多32个寄存器用于存放帧存起始地址,其分别存在于两个寄存器bank上:bank0和bank1,每个bank上有16个寄存器。这两个bank上有相同的起始偏移地址(0x5C),选择这两个bank可以通过S2MM_REG_INDEX的值进行选择。假如想访问第1个寄存器,则给S2MM_REG_INDEX赋值为0,并设定偏移地址为0x5C;如果想访问第17个寄存器,需要将MM2S_REG_INDEX设为1,并设定初始偏移地址为0x5C。 8.4.4.11 S2MM_FRMDLY_STRIDE S2MM帧延迟和跨度(A8h)该寄存器有两个作用,第一是bit24~bit28指定帧延迟,仅用于Genlock从模式,指定从接口比主接口至少要延迟多少个帧;第二是低16位指定水平方向的跨度,同样以字节为单位。所谓跨度是指每两行第一个像素之间间隔的数据个数,具体请参考22.3.2小节,VDMA帧存格式。 8.4.4.12 S2MM_HSIZE S2MM水平方向尺寸(A4h)该寄存器的低16位用于指定每一行有多少字节的数据需要传输。例如显示分辨率为640*480,每个像素4个字节(RGB+Alpha),该值应该设定为640*4。 8.4.4.13 S2MM_VSIZE S2MM垂直方向尺寸(A0h)该寄存器有两个作用,第一是用低13位指定总共有多少行;第二是启动S2MM的传输。当S2MM_VDMACR.RS=1,对该寄存器的写操作会将所有设定参数传递给VDMA内部寄存器模块,用于VDMA控制。对某个通道进行配置时,必须在最后一步设置该寄存器。 8.4.5帧同步选项VDMA支持以下三种帧同步源:
8.4.6 Genlock同步机制8.4.6.1 什么是Genlock?Genlock,同步锁相,可以使一套或多套系统与同一同步源实现同步。能够使视频的刷新和外部视频源保持一致。当提供了一个适当的信号后,系统就会把它的显示刷新率和这个信号进行锁定 。 在许多视频应用中,输入端产生数据的速率往往不同于输出端数据速率,为了避免由速率不一致导致的潜在错误,帧缓冲的使用是很有必要的。帧缓冲机制开辟多个缓冲页,用于保存数据,输入和输出端分别操作不同的帧存,从而避免了冲突。 VDMA的锁相同步特性正是用于阻止读、写通道同时操作同一个帧存。VDMA的每个通道都可以选择自己的操作类型(同步锁相主/从或者动态同步锁相主/从),利用该特性,禁止主从接口同时访问同一缓存,从而保持同步。 VDMA支持四种模式的锁相同步,分别为:
8.4.6.2 Genlock Master读通道(MM2S):当配置为Genlock Master时,该通道不会跳过或者重复任一帧数据,并把当前帧的编号输出在mm2s_frame_ptr_out端口。通道不会检测mm2s_frame_ptr_in端口提供的帧编号。Genlock Slave通道应跟随Genlock Master通道变化,但有一定的延迟。延迟大小预定义在寄存器中(*frmdly_stride[28:24])。 写通道(S2MM):当配置为Genlock Master时,该通道不会跳过或者重复任一帧数据,并把当前帧的编号输出到s2mm_frame_ptr_out端口。通道不会检测s2mm_frame_ptr_in端口提供的帧编号。Genlock Slave通道应跟随Genlock Master通道变化,但有一定的延迟。延迟大小预定义在寄存器中(*frmdly_stride[28:24])。 8.4.6.3 Genlock Slave读通道(MM2S):当配置为Genlock Slave时,该通道会通过跳过或者重复一些帧的方式,尝试与Genlock Master同步。通道会对mm2s_frame_ptr_in端口进行采样,获取Genlock Master的帧编号。为了实现状态反馈,通道会把当前帧的编号输出到mm2s_frame_ptr_out端口。 指定通道工作在Genlock Slave模式,必须进行如下操作。
写通道(S2MM):当配置为Genlock Slave时,该通道会通过跳过或者重复一些帧的方式,尝试与Genlock Master同步。通道会对s2mm_frame_ptr_in端口进行采样,获取Genlock Master的帧编号。为了实现状态反馈,通道会把当前帧的编号输出到s2mm_frame_ptr_out端口。 指定通道工作在Genlock Slave模式,必须进行如下操作。
8.4.6.4 Dynamic Genlock Master动态Genlock Master与Genlock Master的区别在于,主通道会跳过从通道正在操作的帧。举例而言,对于三帧存而言,动态Genlock Master会按照0,1,2,0,1,2的顺序循环使用帧存,一旦检测到Master即将操作Slave正在操作的帧,就会跳过该帧继续循环。因此,如果Slave通道一直在操作帧存1,那么Master通道就会在帧0和帧2之间来回切换。 8.4.6.5 Dynamic Genlock SlaveDynamic Genlock Slave通道会操作Dynamic Genlock Master通道上一周期操作的帧。 下图描述了一种简单的Genlock操作时序。在这个示例中,S2MM通道是Genlock Master,MM2S通道是Genlock Slave,并且写通道帧率高于读通道帧率。 由于读通道帧率慢于写通道,所以读通道仅处理帧2和帧0,跳过帧1不做处理。 8.5 本章小结本章为大家详细的介绍了VDMA这一款IP,在下一章当中,我们将通过一些实际的项目案例帮助大家加深对VDMA的理解。在图像处理领域,VDMA是使用的很多的一个IP,大家要对其熟练的掌握。 |
扫描关注,了解最新资讯