zoukankan      html  css  js  c++  java
  • VDMA搭建视频通路总结

    全局观查,对整个工程的搭建的关键是要保证PL部分搭建成功,PS部分搭建成功,而且两者配合的很好。

    我理解的PL部分涉及到模块的组合以及模块或者IP之间的逻辑的整理,PL部分困扰我比较久的是自动生成的wrapper总是会把一些自己需要特殊考虑的信号全部综合成端口,所以需要我们设计的部分就是把实现的wrapper的特殊要求端口的时序编写好(VDMA工程中的FLC_CLK怎么处理的呢?)PS部分则主要实现的是对与ZYNQ这个PS模块相连接模块IP的接口的配置。要牢记的是,如果IP没有与PS部分连接的话,就不需要在SDK部分配置接口函数,因为我之前一点也没有接触过ARM相关的嵌入式的开发,所以对这一部分纠结了好久。其实只要心里不要害怕,就会发现这一块特别简单,就是一些写好的函数的调用而已,不需要自己编写具体的实现API。

    视频通路中因为其大的数据流AXI_stream协议需要用的到,VDMA应运而生,VDMA相当于二维的DMA。VDMA相比DMA增加了自动循环和自动切换帧缓存的功能,通过保证图像系统有多幅帧缓存来实现输出数据不被撕裂,协调图像的输入输出速率。VDMA可以最多支持32个帧缓存,并且经过配置能够自动的在各个帧存之间进行切换,并自动互相避让,从而保证图像稳定。

    VDMA

    VDMA硬件部分配置比较简单,基础部分只需要选择好对应的stream流数据宽度,所需的帧缓存个数即可。值得注意的是同步信号的配置。如图,由于输入端是采用视频流协议中的tuser作为同步信号的,所以选择s2mm tuser,而输出端默认采用视频流协议,不采用额外手段同步,所以配置为None即可。关键点在于GenLock Mode,及输入输出时序匹配模式,图中为推荐配置,及动态选择关系。如此配置VDMA输入输出端会自动避让,如果输入帧数与输出帧数相同可以尝试其他配置,但不同时必须采取如下配置,此配置风险小,兼容性更高。

           VDMA主要端口有5个:

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

                  S_AXIS_S2MM:视频流从端,接收外来视频流数据

                  M_AXI_MM2S:AXI4全协议主端,从DDR中读取数据给M_AXIS_MM2S

                  M_AXI_S2MM:AXI4全协议主端,从DDR中读取数据给S_AXIS_S2MM

                  M_AXIS_MM2S:视频流主端,向外发怂视频流数据

           其中5个总线接口最好采用同一总线频率,其中除了两个Stream接口与视频输入输出设备相连外,其他均与PS相连(需在PS端使能至少一个一个AFI接口)。

           VDMA配置比较简单,除了分配帧缓存地址外,只需要配置两个寄存器0x00和0x30,分别对应输出配置和输入配置,在动态模式下,均配置为0x8b即可,具体可以查阅官方手册。

           需要注意的是,VDMA一旦打开,接收端就开始等待第一个tuser,如果输入设备先开启,几乎不可能刚好对齐,VDMA就会混乱,所以顺序应该是先开启VDMA再开启输入设备,通过对OvSensor2AXIS中使能端的控制即可以做到。

    六、注意事项

    AXIS2VGA 和OvSensor2AXIS中fifo都需要配置为first word fall through的模式,否则会很尴尬。

    S2MM:stream to memory mapped,即流转地址顺序存放MM2S相反。

    (1.)图像通路的DMA搭建(SDK部分接口配置) 

    需要在工程中加入dma_init.c和dma_init.h文件,作为DMA相关的头文件

    #include "dma_intr.h"

    其他的相关头文件

    #include "sys_intr.h"
    #include "I2C_8bit.h"
    #include "xgpio.h"

    变量以及参数的配置

    volatile int TxDone;
    volatile int RxDone;
    volatile int Error;
    
    volatile u8 tx_buffer_index;
    volatile u8 rx_buffer_index;
    
    u32 *BufferPtr[3];
    
    static XScuGic Intc; //GIC
    static  XAxiDma AxiDma;
    static XGpio Gpio;
    
    #define AXI_GPIO_DEV_ID            XPAR_AXI_GPIO_0_DEVICE_ID

    核心配置部分:注意需要配置中断部分

    int init_intr_sys(void)//中断初始化部分
    {
        DMA_Intr_Init(&AxiDma,0);//initial interrupt system
        Init_Intr_System(&Intc); // initial DMA interrupt system
        Setup_Intr_Exception(&Intc);
        DMA_Setup_Intr_System(&Intc,&AxiDma,TX_INTR_ID,RX_INTR_ID);//setup dma interrpt system
        DMA_Intr_Enable(&Intc,&AxiDma);
    }
    
    
    int main(void)
    {
    
        u32 Status;
        BufferPtr[0] = (u32 *)BUFFER0_BASE;
        BufferPtr[1] = (u32 *)BUFFER1_BASE;
        BufferPtr[2] = (u32 *)BUFFER2_BASE;
    
        tx_buffer_index = 0;
        rx_buffer_index = 0;
        TxDone = 0;
        RxDone = 0;
        Error = 0;
    //GPIO配置
        XGpio_Initialize(&Gpio, AXI_GPIO_DEV_ID);//指定GPIO的设备号,初始化
        XGpio_SetDataDirection(&Gpio, 1, 0);//指定GPIO的方向,0为输出,也就是说该IO方向为从PS输出到PL
    //中断初始化    
    init_intr_sys(); //IIC配置 I2C_config_init(); XGpio_DiscreteWrite(
    &Gpio, 1, 1);//指定要写入GPIO的数据
    //DMA配置 Status
    = XAxiDma_SimpleTransfer(&AxiDma, (u32)BufferPtr[rx_buffer_index], MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA); Status = XAxiDma_SimpleTransfer(&AxiDma, (u32)BufferPtr[tx_buffer_index], MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE); while (1) ; return XST_SUCCESS; }

    (2.)图像通路的VDMA搭建(SDK部分配置)

    需要在工程中加入vdma_api.c文件

    VDMA涉及到的头文件主要有:

    #include "xaxivdma.h"
    #include "xaxivdma_i.h"

    此外涉及到系统初始化以及驱动OV772 摄像头的IIC驱动配置,有一个与PS端相连接的AXI_GPIO,这个IP主要作用就是链接PS和PL,相当于PS控制AXI向GPIO发送一个使能信号控制什么时候开始产生AXIS相关的视频传输时序信号。

    #include "sys_intr.h"
    #include "I2C_8bit.h"
    #include "xgpio.h"
    

      然后当以涉及到的变量和参数

    #define AXI_GPIO_DEV_ID            XPAR_AXI_GPIO_0_DEVICE_ID
    #define IMAGE_WIDTH     640
    #define IMAGE_HEIGHT    480
    
    static XScuGic Intc; //GIC
    static XGpio Gpio;
    
    unsigned int srcBuffer = (XPAR_PS7_DDR_0_S_AXI_BASEADDR  + 0x1000000);//PS7所分配内存的的基地址0x00100000

    然后就是配置的核心部分,配置如下

    int main(void)
    {
        u32 Status;
        XGpio_Initialize(&Gpio, AXI_GPIO_DEV_ID);//GPIO初始化
        XGpio_SetDataDirection(&Gpio, 1, 0);//GPIO设置方向
    
        ///中断的配置
        Init_Intr_System(&Intc); // initial DMA interrupt system
        Setup_Intr_Exception(&Intc);
        //IIC驱动配置
        I2C_config_init();
        XGpio_DiscreteWrite(&Gpio, 1, 1);
        //VDMA配置
        XAxiVdma InstancePtr;//VDMA实例化指针
        xil_printf("Starting the first VDMA 
    
    ");
    
        Status = run_triple_frame_buffer(&InstancePtr, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
                                srcBuffer, 2, 0);
            if (Status != XST_SUCCESS) {
                xil_printf("Transfer of frames failed with error = %d
    ",Status);
                return XST_FAILURE;
            } else {
                xil_printf("Transfer of frames started 
    ");
            }
        print("TEST PASS
    ");
    
        while (1) ;//程序设定为无限循环
            return XST_SUCCESS;
    }

    (1)DMA通路的逻辑部分的设计

    逻辑部分设定:

    @关键信号1
    assign s_axis_s2mm_tlast = m_axis_video_tvalid & s_axis_s2mm_tready & m_axis_video_tlast &(vid_in_v_cnt == VID_IN_VS);// dma in last signal m_axis_video_tvalid:此信号是vid in IP输出的,代表输出数据有效 s_axis_s2mm_tready:此信号是DMA IP 输出的,代表DMA可以接收数据 m_axis_video_tlast:这是每一行图像数据的最后一个像素的信号标志 vid_in_v_cnt == VID_IN_VS:表示一副图像的最后一个像素输出。
    s_axis_s2mm_tlast:所有这些信号有效的时候代表DMA的最后一个数据s_axis_s2mm_tlast信号有效。

    @关键信号2
    assign s_axis_video_tuser = m_axis_mm2s_tvalid & s_axis_video_tready & (vid_out_h_cnt == 11'd0) & (vid_out_v_cnt == 11'd0); //vid out user m_axis_mm2s_tvalid:是M_AXIS_MM2S接口(读DMA接口)的数据有效标志。 s_axis_video_tready:vid out IP 准备好了,可以接收数据 (vid_out_h_cnt == 11'd0) & (vid_out_v_cnt == 11'd0);行计数器为0场计数器也为0说明要么这副图像已经结束,也可以理解为下一副图像开始前。这样结合s_axis_video_tready,m_axis_mm2s_tvalid为1,基于FPGA时序,下一个时钟输出s_axis_video_tuser为1正好是一副图像的第一个像素。 s_axis_video_tuser:因此s_axis_video_tuser代表了每一副图像开始的第一个像素。
    @关键信号3
    assign s_axis_video_tlast = m_axis_mm2s_tvalid & s_axis_video_tready & (vid_out_h_cnt == VID_OUT_HS);//vid out last signal m_axis_mm2s_tvalid:是M_AXIS_MM2S接口(读DMA接口)的数据有效标志。 s_axis_video_tready:vid out IP 准备好了,可以接收数据 vid_out_h_cnt == VID_OUT_HS):图像一行数据的最后一个像素。

    (2)VDMA通路的block设计(加入了HLS生成的图像处理的的IP)

    可以忽略端口之间的接通方法为AXI_Stream,因此省略了逻辑部分的指定。

     AXI协议相关

    AXI4:适用于要求数据高速传输的场合。

    AXI-Stream:如FIFO,数据传输不需要地址,而是主从设备间直接进行数据的读写,主要用于高速数据传输的场合,如视频、高速AD等。

    AXI-lite:可用于单个数据传输,主要用于访问一些低速外设。主要用于主机对从机控制的配置信息传递。

    4) 读/写通道并行地进行数据交互,明显提高了数据吞吐量,对写数据,从设备会返回确认信号,这样可以保证写数据通道的安全,读/写模型分别如图1-1、图1-2。

     

     

    读模型:主设备发送读地址占用信号给从设备→从设备将数据写入主设备,实现读操作。

    写模型:主设备发送写地址占用信号给从设备→主设备将数据写入从设备→从设备回复确认收到信号,实现写操作。

    5) AXI协议严格来讲是一个点对点的主/从接口协议,当多个外设需要互相交互数据时,我们需要加入一个AXI Interconnect模块,也就是AXI互联矩阵,AXI Interconnect的作用是将一个或多个AXI主设备连接到一个或多个AXI 从设备。

    6) AXI Interconnect IP核最多支持16个主设备和16个从设备,如果需要更多的接口可以在设计中加入多个IP核。

    7) ZYNQ中的AXI接口包含三个类型,共9个,主要用于PS与PL的互联。

    (1)AXI_HP接口(PL模块作为主设备)

    包括4个,主要用于PL访问PS上的存储器。每个接口都有两个FIFO缓冲器,一个是读缓冲,一个是写缓冲。

    【实例:设计视频处理时,高清的图像可由FPGA直接完成采集、预处理,然后通过AXI_HP接口将数据高速传输至DDR中,供APU(加速处理器)完成进一步的图像处理】

    (2)AXI_ACP接口(PS端是从设备端)

    只有1个,又叫加速器一致性端口,适合做专用指令加速器模块接口。PL端可直接从PS部分的Cache中拿到CPU的计算结果,同时也可以第一时间将逻辑加速运算的结果送至Cache中,延时很小。

    (3)AXI_GP接口(PS端是从设备端)

    通用AXI接口,总共有4个。可用于控制电机运转,获取传感器信号等逻辑模块的连接接口。

     出现的问题总结:

    1.错误原因是多驱动源,出错的模块都是主机端的底层模块。但是Synthesis时系统没有报错啊?Reset Implementation Run然后Reset Synthesis Run(操作入口如下)后,清除整个编译过程,然后重新Run Synthesis。

    image057.png

    image059.png

    2.出现部分端口未指定管脚,问题在于,在block文件中把需要指定时序的管脚引了出来,是想着要在V文件中规定其时序,而不需要分配管脚,所以这一点要注意。

    3.修改了block文件后,必须要进行的步骤——reset然后generate output product然后generate wrapper,但是wrapper休要注意修改。

    知识点:

    AXI接口具有5个独立通道:WriteAddress通道、Write Data通道、Write Response通道、Read Address通道、Read Address通道、Read Data通道。写相关通道一共有3个,多一个响应的原因在于读写的主从性。

    现在还比较困扰我的一个问题就是:出现显示超出视频区域的根源原因是什么了?查阅发现可能会是显示图像的分辨率太大,或者图像帧频太快,但是后来发现好像也不是那么回事,指定的大小和频率都没有超出显示的要求。

  • 相关阅读:
    web前端面试题
    Delphi控制摄像头
    表达式计算
    web services基础知识二
    soap和web services
    IdTCPClient和IdTCPServer主要属性
    工控控件组iocomp的iplot控件的使用
    编译开关
    delphi web services控件组
    將FastReport存入數據庫,讀出并更新
  • 原文地址:https://www.cnblogs.com/Dinging006/p/9326352.html
Copyright © 2011-2022 走看看