利用AXI VDMA实现OV5640摄像头采集

导读:摄像头采样图像数据后经过VDMA进入DDR,通过PS部分控制,经过三级缓存,将DDR中保持的图形数据通过VDMA发送出去。在FPGA的接收端口产生VID OUT时序驱动HDMI显示器显示图形。

一、          基础知识点

1、OV5640和VDMA之间同步信号的配置,输入端采样视频流协议中的tuser作为同步信号。

2、VDMA主要端口:

(1)、S_AXI_Lite:寄存器配置接口,用于软件配置VDMA,并读取状态信息。

(2)、S_AXI_S2MM:视频流入端,接收外来的视屏数据。

(3)、M_AXI_MM2S:AXI4全协议主端,从DDR中读取数据给M_AXI_MM2S。

(4)、M_AXI_S2MM:AXI4全协议主端,从DDR中读取的数据给M_AXI_S2MM

(5)、M_AXIS_MM2S:视频流接口,向外发送数据。

3、PL中的DMA IP对于DDR和PL存储资源来说是主机(Master),DMA对于PS来说是从机(Slave),PS通过AXI_Lite配置DMA的寄存器从原地址向目的地址转移多少数据,DMA通过AHP读写DDR,通过AXI读写PL资源。

4、在ZYNQ芯片内部,PS和PL是共享DDR控制器的,PS访问DDR只要操作DDR虚拟地址的应设计可,对于PL,要接入DDR,必须通过AXI_HP端口。

二、          框架分析

1、PS配置

(1)、processing_system7_0

PS模块处理单元,选择的是端口M_AXI_GP0,用于通过AXI-Lite总线配置外设,引出IIC总线,硬件中已经将其搭到IIC总线,同时引出两个时钟FCLK_CLK0(100Mhz)作为系统时钟,FCLK_CLK1(25Mhz)作为OV640摄像头驱动时钟,同时引出FCLK_RESET_N复位信号,用于系统中断时对系统进行复位。引出PS侧的DDR管脚,由此可以通过DMA读写DDR,同时PL侧DMA可以通过AXI-HP总线读取DDR的数据。对于两个AXI总线(S_AXI_HP0和M_AXI_GP0),两个时钟工作在相同的时钟下,都连接到FCLK_CLK0(100Mhz)。

此外,PS侧开启中断输入,检测中断。

(2)VDMA

输出部分:

VDMA数据接口可以分为读写通过,通过M_AXI_S2MM端口将数据流写入DDR3。通过M_AXI_MM2S端口可以从DDR3读取数据,并通过M_AXI_MM2S端口将DDR3中读取出的数据以AXIS_Stream类型输出。

VDMA与Zynq processor通过AXI_Interconnect进行连接。

输入部分:

在VDMA的IP配合部分,通过ZYNQ processor的M_AXI_GP接口进行配置。

视频数据输入是OV5640的数据经过video to Stream核实现的数据输入。对于这些AXI协议类型的总线,需要同步于ZYNQ自带的GP时钟,也就是ACLK,S00_ACLK,M00_ACLK,S01_ACLK都要用FCLK_CLK0时钟。

(3)Processor System Reset

输入信号:

系统复位处理器,slowest_sync_clk最小同步时钟,复位信号与时钟进行同步。复位输入信号是ZYNQ processor的FCLK_RESET_N。

输出信号

interconnect_aresetn:互联复位信号,连接到各个AXI connect连接模块的复位信号输入。

peripheral_aresetn:外围模块复位信号,作为其他各个外设模块的AXI总线复位信号输入。

三、          代码分析

1、 关于XiixPs_MasterSendPolled()函数

该函数在主模式下启动轮循(Polled)模式发送,讲数据发送到Fifo,并等待从机接收数据,如果设备无法送fifo中读取数据,导致发送超时而失败。

1.1     传入参数:

s32 XIicPs_MasterSendPolled(XIicPs *InstancePtr, u8 *MsgPtr, s32 ByteCount, u16 SlaveAddr)

@ 指向XiicPs实例结构的指针

@指向发送缓存区的指针

@要发送的字节数

@从设备的地址

1.2 语句1

if (((InstancePtr->IsRepeatedStart) != 0) ||

((ByteCount > XIICPS_FIFO_DEPTH) != 0U)) {

XIicPs_WriteReg(BaseAddr, XIICPS_CR_OFFSET,

XIicPs_ReadReg(BaseAddr, (u32)XIICPS_CR_OFFSET) |

(u32)XIICPS_CR_HOLD_MASK);

}

作用:

判断实例结构中时都设置为重复启动或者要放的数据的长度大于FIFO的深度。

由于条件1、2不成立,所以不会执行将IIC控制寄存器的bit4置一,该位的作用是:

0:在接收、发送完毕后,允许主机终止发送

1:在没有数据接收与发送时,保持时钟线为低直到主机操作

1.2     语句2 建立主机模式

(void)XIicPs_SetupMaster(InstancePtr, SENDING_ROLE);

SENDING_ROLE=1;

1.3     将所有的错误中断进行关联

Intrs = (u32)XIICPS_IXR_ARB_LOST_MASK | (u32)XIICPS_IXR_TX_OVR_MASK |      (u32)XIICPS_IXR_NACK_MASK;

1.4     启用中断前将所有中断标志位清除

IntrStatusReg = XIicPs_ReadReg(BaseAddr, XIICPS_ISR_OFFSET);

XIicPs_WriteReg(BaseAddr, XIICPS_ISR_OFFSET, IntrStatusReg);

采用的方式为先读取中断标志寄存器,然后将读出的数据再进行写入,寄存器类型为wtc,即write true clear,由此清除标志位。

1.5     清空发送fifo

(void)TransmitFifoFill(InstancePtr);

然后写入0V5640的地址,再将要发送的数据经过fifo发送出去。

1.6     等待发送完毕

while (XIicPs_BusIsBusy(InstancePtr));

查询IIC状态寄存器的发送标志位,0x04,改为为1的话表示发送完毕,结束该部分。

2、 对于VDMA的配置

(1)、Xil_Out32((VDMA_BASEADDR + 0x030), 0x108B);// enable circular mode

该地址对应的是S2MM VDMA控制寄存器,写入0x108B,即0x1000_1000_1010。该寄存器用于控制VDMA S2MM,可以实现复位、使能锁相同步、设定帧存切换模式、启动VDMA读写通道等操作。

bit3使能锁相同步或者动态锁相同步模式

0:关闭Genlocken和动态Genlock同步。

1:开启Genlock或Genlock同步

该位仅在通道配置为锁相同步从接口或者动态锁相从接口时才起作用。配置成锁相同步主接口时,该位为保留位,恒为0.

bit2:先将通道进行复位

0:正常操作

1:复位S2MM通道。

bit1:制定帧存为循环模式还是停留模式。

0:停留模式,显示用缓存也将停留在指定的帧存

1:循环模式,循环切换显示用缓存页。

bit0:控制VDMA的运行和停止,开始任何VDMA操作前,该位必须置一。

0:停止

1:运行

(2)、设置帧存的起始地址

Xil_Out32((VDMA_BASEADDR + 0x0AC), VIDEO_BASEADDR0);  // start address

Xil_Out32((VDMA_BASEADDR + 0x0B0), VIDEO_BASEADDR1);  // start address

Xil_Out32((VDMA_BASEADDR + 0x0B4), VIDEO_BASEADDR2);  // start address

S2MM_START_ADDRESS(1-16):Ach~E8h

以上几位用于设置S2MM的帧存地址。有最多32个寄存器用于存放帧存的起始地址,其分布在两个bank上:bank0和bank1,每个bank上有16个寄存器。

存储地址如何配置:

本次例程中用到了三帧缓存,采用了VIDEO_BASEADDR0、VIDEO_BASEADDR1、VIDEO_BASEADDR2三个地址,三个基地址的分配取决于输入和输出的位宽,DDR3的地址是0x0000_0000,实际使用时最好偏移0x0100_00000的地址来存储应用的数据,因为程序在运行过程中需要一些内存来运行,为了保证不冲突,对其加一个偏移量。设置的空间还要保证可以存储一帧数据,例如使用1280*720*4=3,686,400,转换成16进制为384,000,0x0100_0000+0x0138_4000,小于VIDEO_BASEADDR1的基地址0x0200_0000,因此分配是合理的。

(3)、设置帧延迟和跨度寄存器

Xil_Out32((VDMA_BASEADDR + 0x0A8), (H_STRIDE*3)); //h offset (H_STRIDE* 3) bytes

S2MM帧延迟和跨度寄存器,该寄存器有两个作用,

bit24~bit28:

仅用于Genlock从模式,bit24~bit28指定从接口要比主接口延迟多少个帧。

bit15~bit0:

低16位指定水平方向的跨度,同样以字节为单位。跨度指的是每两行第一个像素之间间隔的数据个数,可参见VDMA帧存格式。

(4)、设置S2MM_HSIZE S2MM水平方向尺寸

该寄存器的低16bit用于指定每一行有多少个字节的数据要传输,例如显示分辨率为640*480,每个像素4个字节(RGB+Alpha),其值应该设置为640*4

Xil_Out32((VDMA_BASEADDR + 0x0A4), (H_ACTIVE*3));     // h size (H_ACTIVE * 3) bytes

对于纯24bit的RGB数据,每一行有1280x3个字节,所以向寄存器写入行有效数x3。

(5)、设置S2MM_VSIZE垂直方向尺寸

Xil_Out32((VDMA_BASEADDR + 0x0A0), V_ACTIVE);         // v size (V_ACTIVE)

该寄存器的低13bit用于指定总共有多少行。

3、 对于DDR3读取数据的配置

3.1 MM2S VDMA控制寄存器配置

Xil_Out32((VDMA_BASEADDR + 0x000), 0x8B);     // enable circular mode

0x8B:  0x1000_1010

bit3:使能锁相同步或者动态锁相同步模式。

0:关闭锁相同步或者动态锁相同。

1:开启锁相同步或者动态锁相同。

bit2:复位控制

0:正常操作

1:复位MM2S通道

bit1:指定帧存为循环模式还是停留模式

0:停留模式,显示用的缓存页将停留在指定的帧存。

1:循环模式,循环切换显示用缓存页。

bit0:运行/停止控制,控制VDMA通道的停止和运行。

0:停止。

1:运行。

3.2 设置MM2S帧存起始地址

Xil_Out32((VDMA_BASEADDR + 0x05c), VIDEO_BASEADDR0); // start address

Xil_Out32((VDMA_BASEADDR + 0x060), VIDEO_BASEADDR1); // start address

Xil_Out32((VDMA_BASEADDR + 0x064), VIDEO_BASEADDR2); // start address

3.3 设置MM2S帧延迟和跨度寄存器

该寄存器仅适用于Genlock从模式,指定从接口要比主接口至少延迟多少个帧。低16位指定水平方向上的跨度,以字节为单位。

Xil_Out32((VDMA_BASEADDR + 0x058), (H_STRIDE*3));         // h offset (H_STRIDE * 3) bytes

3.4 MM2S水平方向显示大小寄存器设置

低16bit指定每一行有多少字节的数据要进行传输。

Xil_Out32((VDMA_BASEADDR + 0x054), (H_ACTIVE*3));         // h size (H_ACTIVE * 3) bytes

3.5 MM2S垂直方向显示大小寄存器配置

该寄存器的低13位指定总共有多少行要进行显示

Xil_Out32((VDMA_BASEADDR + 0x050), V_ACTIVE);         // v size (V_ACTIVE)

利用AXI VDMA实现OV5640摄像头采集的更多相关文章

  1. 利用AXI VDMA实现OV5640摄像头采集笔记(二)

    导读:摄像头采样图像数据后经过VDMA进入DDR,通过PS部分控制,经过三级缓存,将DDR中保持的图形数据通过VDMA发送出去.在FPGA的接收端口产生VID OUT时序驱动HDMI显示器显示图形. ...

  2. 利用ffmpeg一步一步编程实现摄像头采集编码推流直播系统

    了解过ffmpeg的人都知道,利用ffmpeg命令即可实现将电脑中摄像头的画面发布出去,例如发布为UDP,RTP,RTMP等,甚至可以发布为HLS,将m3u8文件和视频ts片段保存至Web服务器,普通 ...

  3. 基于AXI VDMA的图像采集系统

    基于AXI VDMA的图像采集系统 转载 2017年04月18日 17:26:43 标签: framebuffer / AXIS / AXI VDMA 2494 本课程将对Xilinx提供的一款IP核 ...

  4. 第46章 DCMI—OV5640摄像头—零死角玩转STM32-F429系列

    第46章     DCMI—OV5640摄像头 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com ...

  5. ov5640摄像头设备驱动

    http://www.cnblogs.com/firege/p/5806121.html  (驱动大神) http://blog.csdn.net/yanbixing123/article/detai ...

  6. FPGA配置OV5640摄像头及RGB图像数据采集

    本文设计思想采用明德扬至简设计法.在做摄像头数据采集处理之前,需要配置OV5640传感器内部寄存器使其按要求正常工作,详细内容请参见<OV5640自动对焦照相模组应用指南>.首先要关注OV ...

  7. Linux 下V4l2摄像头采集图片,实现yuyv转RGB,RGB转BMP,RGB伸缩,jpeglib 库实现压缩RGB到内存中,JPEG经UDP发送功(转)

    ./configure CC=arm-linux-gnueabihf-gcc LD=arm-linux-gnueabihf-ld --host=arm-linux --prefix=/usr/loca ...

  8. [转]GStreamer资料(摄像头采集,视频保存,远程监控)DVR

    http://blog.csdn.net/wzwxiaozheng/archive/2010/12/26/6099397.aspx GStreamer资料整理(包括摄像头采集,视频保存,远程监控,流媒 ...

  9. 基于opencv和mfc的摄像头采集代码(GOMFCTemplate2)

            编写带界面的图像处理程序,选择opencv+mfc是一种很好的选择:在读取摄像头数据方面,网上的方法很多,其中shiqiyu的camerads的方法是较好的.       基于现有资料 ...

随机推荐

  1. 实战build-react(三)+ style-components

    npm install --save style-components https://www.jianshu.com/p/27788be90605(copy) "axios": ...

  2. UVa 10603 Fill (BFS && 经典模拟倒水 && 隐式图)

    题意 : 有装满水的6升的杯子.空的3升杯子和1升杯子,3个杯子中都没有刻度.不使用道具情况下,是否可量出4升水呢? 你的任务是解决一般性的问题:设3个杯子的容量分别为a, b, c,最初只有第3个杯 ...

  3. Selenium 控制浏览器

    webdriver提供了操作浏览器的一些基本方法,例如:打开,前进,后退,刷新,设置窗口大小,截屏,退出等 一.打开网页 代码: # coding = utf-8 from time import s ...

  4. 7.Python编码规范(PEP 8)

    在讲解具体的 Python 编码规范之前,先来看看图 1 中的代码: 图 1 两段功能相同的 Python 代码 对比图 1 中的两段代码你会发现,它们所包含的代码时完全相同的,但很明显,右侧的代码编 ...

  5. Thymeleaf 2-基础语法

    三.基础语法 1.创建HTML 由上文也可以知道需要在html中添加: <html xmlns:th="http://www.thymeleaf.org"> 这样,下文 ...

  6. rollup的学习

    概述(Overview) Rollup 是一个 JavaScript 模块打包器,可以将小块代码编译成大块复杂的代码,例如 library 或应用程序.Rollup 对代码模块使用新的标准化格式,这些 ...

  7. 进程间通信(IPC)-管道、匿名管道

    每个进程都有各自的地址空间,任何一个进程的全局变量在另一个进程中都看不到 所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读 ...

  8. 多层全连接神经网络实现minist手写数字分类

    import torch import numpy as np import torch.nn as nn from torch.autograd import Variable import tor ...

  9. linux inotify 监控文件系统事件

    https://blog.csdn.net/cheng_fangang/article/details/41075515

  10. ES6正则拓展

    字符串的正则方法 字符串对象共有 4 个方法,可以使用正则表达式:match().replace().search()和split(). ES6 将这 4 个方法,在语言内部全部调用RegExp的实例 ...