Block Design
搭建如下图所示的硬件系统:
该硬件系统的数据流向为:
DDR–>AXI VDMA–>AXI DATA FIFO–>AXI VDMA–>DDR
即将一幅图像由一段地址空间搬运至另一段地址空间。
其中,AXI VDMA配置如下:
地址位宽32,缓存3帧,读写通道的配置如上图所示。
写通道Fsync Options选择s2mm tuser,读通道选择None,即保持默认。
AXI4-Stream DATA FIFO配置如下:
此外,为了更直观地感受整个数据传输过程,我们还在硬件系统中加入了ILA,以实时抓取波形观察。
SDK设计
vdma_api.c
/******************************************************************************
*
* Copyright (C) 2014 - 2018 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file vdma_api.c
*
* This file has high level API to configure and start the VDMA.The file assumes that:
* The design has VDMA with both MM2S and S2MM path enable.
* The API's has tested with hardware that has tow VDMA and MM2S to S2MM are back
* to back connected for each VDMA.
*
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 4.0 adk 11/26/15 First release
****************************************************************************/
#define DEBUG_MODE 0
/******************** Include files **********************************/
#include "xaxivdma.h"
#include "xparameters.h"
#include "xil_exception.h"
/******************** Data structure Declarations *****************************/
typedef struct vdma_handle
{
/* The device ID of the VDMA */
unsigned int device_id;
/* The state variable to keep track if the initialization is done*/
unsigned int init_done;
/** The XAxiVdma driver instance data. */
XAxiVdma* InstancePtr;
/* The XAxiVdma_DmaSetup structure contains all the necessary information to
* start a frame write or read. */
XAxiVdma_DmaSetup ReadCfg;
XAxiVdma_DmaSetup WriteCfg;
/* Horizontal size of frame */
unsigned int hsize;
/* Vertical size of frame */
unsigned int vsize;
/* Buffer address from where read and write will be done by VDMA */
unsigned int src_buffer_address;
unsigned int dest_buffer_address;
/* Flag to tell VDMA to interrupt on frame completion*/
unsigned int enable_frm_cnt_intr;
/* The counter to tell VDMA on how many frames the interrupt should happen*/
unsigned int number_of_frame_count;
}vdma_handle;
/******************** Constant Definitions **********************************/
/*
* Device related constants. These need to defined as per the HW system.
*/
vdma_handle vdma_context[XPAR_XAXIVDMA_NUM_INSTANCES];
static unsigned int context_init=0;
/******************* Function Prototypes ************************************/
static int ReadSetup(vdma_handle *vdma_context);
static int WriteSetup(vdma_handle *vdma_context);
static int StartTransfer(XAxiVdma *InstancePtr);
/*****************************************************************************/
/**
*
* run_triple_frame_buffer API
*
* This API is the interface between application and other API. When application will call
* this API with right argument, This API will call rest of the API to configure the read
* and write path of VDMA,based on ID. After that it will start both the read and write path
* of VDMA
*
* @param InstancePtr is the handle to XAxiVdma data structure.
* @param DeviceId is the device ID of current VDMA
* @param hsize is the horizontal size of the frame. It will be in Pixels.
* The actual size of frame will be calculated by multiplying this
* with tdata width.
* @param vsize is the Vertical size of the frame.
* @param buf_base_addr is the buffer address where frames will be written
* and read by VDMA.
* @param number_frame_count specifies after how many frames the interrupt
* should come.
* @param enable_frm_cnt_intr is for enabling frame count interrupt
* when set to 1.
* @return
* - XST_SUCCESS if example finishes successfully
* - XST_FAILURE if example fails.
*
******************************************************************************/
int run_triple_frame_buffer(XAxiVdma* InstancePtr, int DeviceId, int hsize,
int vsize, int src_buf_base_addr,int dest_buf_base_addr, int number_frame_count,
int enable_frm_cnt_intr)
{
int Status,i;
XAxiVdma_Config *Config;
XAxiVdma_FrameCounter FrameCfgPtr;
/* This is one time initialization of state machine context.
* In first call it will be done for all VDMA instances in the system.
*/
if(context_init==0) {
for(i=0; i < XPAR_XAXIVDMA_NUM_INSTANCES; i++) {
vdma_context[i].InstancePtr = NULL;
vdma_context[i].device_id = -1;
vdma_context[i].hsize = 0;
vdma_context[i].vsize = 0;
vdma_context[i].init_done = 0;
vdma_context[i].src_buffer_address = 0;
vdma_context[i].dest_buffer_address = 0;
vdma_context[i].enable_frm_cnt_intr = 0;
vdma_context[i].number_of_frame_count = 0;
}
context_init = 1;
}
/* The below initialization will happen for each VDMA. The API argument
* will be stored in internal data structure
*/
/* The information of the XAxiVdma_Config comes from hardware build.
* The user IP should pass this information to the AXI DMA core.
*/
Config = XAxiVdma_LookupConfig(DeviceId);
if (!Config) {
xil_printf("No video DMA found for ID %d\r\n",DeviceId );
return XST_FAILURE;
}
if(vdma_context[DeviceId].init_done ==0) {
vdma_context[DeviceId].InstancePtr = InstancePtr;
/* Initialize DMA engine */
Status = XAxiVdma_CfgInitialize(vdma_context[DeviceId].InstancePtr,
Config, Config->BaseAddress);
if (Status != XST_SUCCESS) {
xil_printf("Configuration Initialization failed %d\r\n",
Status);
return XST_FAILURE;
}
vdma_context[DeviceId].init_done = 1;
}
vdma_context[DeviceId].device_id = DeviceId;
vdma_context[DeviceId].vsize = vsize;
vdma_context[DeviceId].src_buffer_address = src_buf_base_addr;
vdma_context[DeviceId].dest_buffer_address = dest_buf_base_addr;
vdma_context[DeviceId].enable_frm_cnt_intr = enable_frm_cnt_intr;
vdma_context[DeviceId].number_of_frame_count = number_frame_count;
vdma_context[DeviceId].hsize = hsize * (Config->Mm2SStreamWidth>>3);
/* Setup the write channel */
Status = WriteSetup(&vdma_context[DeviceId]);
if (Status != XST_SUCCESS) {
xil_printf("Write channel setup failed %d\r\n", Status);
if(Status == XST_VDMA_MISMATCH_ERROR)
xil_printf("DMA Mismatch Error\r\n");
return XST_FAILURE;
}
/* Setup the read channel */
Status = ReadSetup(&vdma_context[DeviceId]);
if (Status != XST_SUCCESS) {
xil_printf("Read channel setup failed %d\r\n", Status);
if(Status == XST_VDMA_MISMATCH_ERROR)
xil_printf("DMA Mismatch Error\r\n");
return XST_FAILURE;
}
/* The frame counter interrupt is enabled, setting VDMA for same */
if(vdma_context[DeviceId].enable_frm_cnt_intr) {
FrameCfgPtr.ReadDelayTimerCount = 1;
FrameCfgPtr.ReadFrameCount = number_frame_count;
FrameCfgPtr.WriteDelayTimerCount = 1;
FrameCfgPtr.WriteFrameCount = number_frame_count;
XAxiVdma_SetFrameCounter(vdma_context[DeviceId].InstancePtr,&FrameCfgPtr);
/* Enable DMA read and write channel interrupts. The configuration for interrupt
* controller will be done by application */
XAxiVdma_IntrEnable(vdma_context[DeviceId].InstancePtr,
XAXIVDMA_IXR_ERROR_MASK |
XAXIVDMA_IXR_FRMCNT_MASK,XAXIVDMA_WRITE);
XAxiVdma_IntrEnable(vdma_context[DeviceId].InstancePtr,
XAXIVDMA_IXR_ERROR_MASK |
XAXIVDMA_IXR_FRMCNT_MASK,XAXIVDMA_READ);
} else {
/* Enable DMA read and write channel interrupts. The configuration for interrupt
* controller will be done by application */
XAxiVdma_IntrEnable(vdma_context[DeviceId].InstancePtr,
XAXIVDMA_IXR_ERROR_MASK,XAXIVDMA_WRITE);
XAxiVdma_IntrEnable(vdma_context[DeviceId].InstancePtr,
XAXIVDMA_IXR_ERROR_MASK ,XAXIVDMA_READ);
}
/* Start the DMA engine to transfer */
Status = StartTransfer(vdma_context[DeviceId].InstancePtr);
if (Status != XST_SUCCESS) {
if(Status == XST_VDMA_MISMATCH_ERROR)
xil_printf("DMA Mismatch Error\r\n");
return XST_FAILURE;
}
#if DEBUG_MODE
xil_printf("Code is in Debug mode, Make sure that buffer addresses are at valid memory \r\n");
xil_printf("In triple mode, there has to be six consecutive buffers for Debug mode \r\n");
{
u32 pixels,j,Addr = vdma_context[DeviceId].buffer_address;
u8 *dst,*src;
u32 total_pixel = vdma_context[DeviceId].stride * vdma_context[DeviceId].vsize;
src = (unsigned char *)Addr;
dst = (unsigned char *)Addr + (total_pixel * vdma_context->InstancePtr->MaxNumFrames);
for(j=0;j<vdma_context->InstancePtr->MaxNumFrames;j++) {
for(pixels=0;pixels<total_pixel;pixels++) {
if(src[pixels] != dst[pixels]) {
xil_printf("VDMA transfer failed: SRC=0x%x, DST=0x%x\r\n",
src[pixels],dst[pixels]);
exit(-1);
}
}
src = src + total_pixel;
dst = dst + total_pixel;
}
}
xil_printf("VDMA transfer is happening and checked for 3 frames \r\n");
#endif
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function sets up the read channel
*
* @param vdma_context is the context pointer to the VDMA engine.
*
* @return XST_SUCCESS if the setup is successful, XST_FAILURE otherwise.
*
* @note None.
*
******************************************************************************/
static int ReadSetup(vdma_handle *vdma_context)
{
int Index;
u32 Addr;
int Status;
vdma_context->ReadCfg.VertSizeInput = vdma_context->vsize;
vdma_context->ReadCfg.HoriSizeInput = vdma_context->hsize;
vdma_context->ReadCfg.Stride = vdma_context->hsize;
vdma_context->ReadCfg.FrameDelay = 0; /* This example does not test frame delay */
vdma_context->ReadCfg.EnableCircularBuf = 1;
vdma_context->ReadCfg.EnableSync = 1; /* Gen-Lock */
vdma_context->ReadCfg.PointNum = 0;
vdma_context->ReadCfg.EnableFrameCounter = 0; /* Endless transfers */
vdma_context->ReadCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */
/* Configure the VDMA is per fixed configuration, This configuration is being used by majority
* of customer. Expert users can play around with this if they have different configurations */
Status = XAxiVdma_DmaConfig(vdma_context->InstancePtr, XAXIVDMA_READ, &vdma_context->ReadCfg);
if (Status != XST_SUCCESS) {
xil_printf("Read channel config failed %d\r\n", Status);
return XST_FAILURE;
}
/* Initialize buffer addresses
*
* These addresses are physical addresses
*/
Addr = vdma_context->src_buffer_address;
for(Index = 0; Index < vdma_context->InstancePtr->MaxNumFrames; Index++) {
vdma_context->ReadCfg.FrameStoreStartAddr[Index] = Addr;
/* Initializing the buffer in case of Debug mode */
#if DEBUG_MODE
{
u32 i;
u8 *src;
u32 total_pixel = vdma_context->stride * vdma_context->vsize;
src = (unsigned char *)Addr;
xil_printf("Read Buffer %d address: 0x%x \r\n",Index,Addr);
for(i=0;i<total_pixel;i++)
{
src[i] = i & 0xFF;
}
}
#endif
Addr += vdma_context->hsize * vdma_context->vsize;
}
/* Set the buffer addresses for transfer in the DMA engine
* The buffer addresses are physical addresses
*/
Status = XAxiVdma_DmaSetBufferAddr(vdma_context->InstancePtr, XAXIVDMA_READ,
vdma_context->ReadCfg.FrameStoreStartAddr);
if (Status != XST_SUCCESS) {
xil_printf(
"Read channel set buffer address failed %d\r\n", Status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function sets up the write channel
*
* @param dma_context is the context pointer to the VDMA engine..
*
* @return XST_SUCCESS if the setup is successful, XST_FAILURE otherwise.
*
* @note None.
*
******************************************************************************/
static int WriteSetup(vdma_handle *vdma_context)
{
int Index;
u32 Addr;
int Status;
vdma_context->WriteCfg.VertSizeInput = vdma_context->vsize;
vdma_context->WriteCfg.HoriSizeInput = vdma_context->hsize;
vdma_context->WriteCfg.Stride = vdma_context->hsize;
vdma_context->WriteCfg.FrameDelay = 0; /* This example does not test frame delay */
vdma_context->WriteCfg.EnableCircularBuf = 1;
vdma_context->WriteCfg.EnableSync = 1; /* Gen-Lock */
vdma_context->WriteCfg.PointNum = 0;
vdma_context->WriteCfg.EnableFrameCounter = 0; /* Endless transfers */
vdma_context->WriteCfg.FixedFrameStoreAddr = 0; /* We are not doing parking */
/* Configure the VDMA is per fixed configuration, This configuration
* is being used by majority of customers. Expert users can play around
* with this if they have different configurations
*/
Status = XAxiVdma_DmaConfig(vdma_context->InstancePtr, XAXIVDMA_WRITE, &vdma_context->WriteCfg);
if (Status != XST_SUCCESS) {
xil_printf(
"Write channel config failed %d\r\n", Status);
return Status;
}
/* Initialize buffer addresses
*
* Use physical addresses
*/
Addr = vdma_context->dest_buffer_address;
/* If Debug mode is enabled write frame is shifted 3 Frames
* store ahead to compare read and write frames
*/
#if DEBUG_MODE
Addr = Addr + vdma_context->InstancePtr->MaxNumFrames * \
(vdma_context->stride * vdma_context->vsize);
#endif
for(Index = 0; Index < vdma_context->InstancePtr->MaxNumFrames; Index++) {
vdma_context->WriteCfg.FrameStoreStartAddr[Index] = Addr;
#if DEBUG_MODE
xil_printf("Write Buffer %d address: 0x%x \r\n",Index,Addr);
#endif
Addr += (vdma_context->hsize * vdma_context->vsize);
}
/* Set the buffer addresses for transfer in the DMA engine */
Status = XAxiVdma_DmaSetBufferAddr(vdma_context->InstancePtr,
XAXIVDMA_WRITE,
vdma_context->WriteCfg.FrameStoreStartAddr);
if (Status != XST_SUCCESS) {
xil_printf("Write channel set buffer address failed %d\r\n",
Status);
return XST_FAILURE;
}
/* Clear data buffer
*/
#if DEBUG_MODE
memset((void *)vdma_context->buffer_address, 0,
vdma_context->ReadCfg.Stride * vdma_context->ReadCfg.VertSizeInput * vdma_context->InstancePtr->MaxNumFrames);
#endif
return XST_SUCCESS;
}
/*****************************************************************************/
/**
*
* This function starts the DMA transfers. Since the DMA engine is operating
* in circular buffer mode, video frames will be transferred continuously.
*
* @param InstancePtr points to the DMA engine instance
*
* @return
* - XST_SUCCESS if both read and write start successfully
* - XST_FAILURE if one or both directions cannot be started
*
* @note None.
*
******************************************************************************/
static int StartTransfer(XAxiVdma *InstancePtr)
{
int Status;
/* Start the write channel of VDMA */
Status = XAxiVdma_DmaStart(InstancePtr, XAXIVDMA_WRITE);
if (Status != XST_SUCCESS) {
xil_printf("Start Write transfer failed %d\r\n", Status);
return XST_FAILURE;
}
/* Start the Read channel of VDMA */
Status = XAxiVdma_DmaStart(InstancePtr, XAXIVDMA_READ);
if (Status != XST_SUCCESS) {
xil_printf("Start read transfer failed %d\r\n", Status);
return XST_FAILURE;
}
return XST_SUCCESS;
}
vdma.c
/******************************************************************************
*
* Copyright (C) 2014 - 2018 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/*****************************************************************************/
/**
*
* @file vdma.c
*
* This file comprises sample application to usage of VDMA APi's in vdma_api.c.
* .
*
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 4.0 adk 11/26/15 First release
* 4.1 adk 01/07/16 Updated DDR base address for Ultrascale (CR 799532) and
* removed the defines for S6/V6.
* ms 04/05/17 Modified Comment lines in functions to
* recognize it as documentation block for doxygen
* generation of examples.
****************************************************************************/
/*** Include file ***/
#include "xparameters.h"
#include "xstatus.h"
#include "xil_exception.h"
#include "xil_assert.h"
#include "xaxivdma.h"
#include "xaxivdma_i.h"
#include "xil_io.h"
#include <stdio.h>
#include "xil_cache.h"
#ifdef XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#define MEMORY_BASE XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#elif XPAR_MIG7SERIES_0_BASEADDR
#define MEMORY_BASE XPAR_MIG7SERIES_0_BASEADDR
#elif XPAR_MIG_0_BASEADDR
#define MEMORY_BASE XPAR_MIG_0_BASEADDR
#elif XPAR_PSU_DDR_0_S_AXI_BASEADDR
#define MEMORY_BASE XPAR_PSU_DDR_0_S_AXI_BASEADDR
#else
#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \
DEFAULT SET TO 0x01000000
#define MEMORY_BASE 0x01000000
#endif
/*** Global Variables ***/
unsigned int srcBuffer = (MEMORY_BASE + 0x1000000);
unsigned int destBuffer = (MEMORY_BASE + 0x2000000);
int run_triple_frame_buffer(XAxiVdma* InstancePtr, int DeviceId, int hsize,
int vsize, int src_buf_base_addr, int dest_buf_base_addr, int number_frame_count,
int enable_frm_cnt_intr);
/*****************************************************************************/
/**
* Main function
*
* This is main entry point to demonstrate this example.
*
* @return None
*
******************************************************************************/
//void vdma_test(){
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x30, 0x4); //reset S2MM VDMA Control Register
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x30, 0x8); //genlock
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xAC, 0x08000000);//S2MM Start Addresses
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xAC+4, 0x0A000000);
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xAC+8, 0x09000000);
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA4, 16*3);//S2MM Horizontal Size
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA8, 0x01002000);//S2MM Frame Delay and Stride
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x30, 0x3);//S2MM VDMA Control Register
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0xA0, 16);//S2MM Vertical Size start an S2MM transfer
//
// //AXI VDMA1
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x0, 0x4); //reset MM2S VDMA Control Register
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x0, 0x8); //gen-lock
//
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x5C, 0x08000000); //MM2S Start Addresses
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x5C+4, 0x0A000000);
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x5C+8, 0x09000000);
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x54, 16*3);//MM2S HSIZE Register
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x58, 0x01002000);//S2MM FRMDELAY_STRIDE Register 1920*3=5760 ����֮��Ϊ8192=0x2000
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x0, 0x03);//MM2S VDMA Control Register
// Xil_Out32(XPAR_AXI_VDMA_0_BASEADDR + 0x50, 16);//MM2S_VSIZE ��������
//
//}
int main(){
int Status;
Xil_DCacheDisable();
XAxiVdma InstancePtr;
//
printf("\n--- Entering main() --- \r\n");
printf("Starting the VDMA \n\r");
for(int i=0;i<16*16*3/4;i++){
Xil_Out32(srcBuffer+i*4,(u32)i);
Xil_Out32(destBuffer+i*4,(u32)0);
u32 x=Xil_In32(destBuffer+i*4);
printf("%d\n",x);
}
Status = run_triple_frame_buffer(&InstancePtr, 0, 16, 16,
srcBuffer, destBuffer, 1, 0);
//
if(Status != XST_SUCCESS) {
xil_printf("Transfer of frames failed with error = %d\r\n",Status);
return XST_FAILURE;
}
else {
xil_printf("Transfer of frames started \r\n");
}
for(int i=0;i<16*16*3/4;i++){
u32 x=Xil_In32(destBuffer+i*4);
printf("%d\n",x);
}
}
其中,函数
int run_triple_frame_buffer(XAxiVdma* InstancePtr, int DeviceId, int hsize,
int vsize, int src_buf_base_addr, int dest_buf_base_addr, int number_frame_count,
int enable_frm_cnt_intr);
用于启动vdma传输,这里,hsize是图像的宽度,vsize是图像的高度,src_buf_base_addr和dest_buf_base_addr分别是读通道起始地址和写通道起始地址。
实验与观察
将SDK程序烧写至开发板,串口打印如下:
可以看到,VDMA成功将srcBuffer处的数据搬运至了destBuffer,表明我们搭建的回环测试硬件平台无误。
实时抓取的波形如下
可以看到,图像的第一个数据,tuser信号为高
上图中,共有16行数据,每一行的最后一个数据在发送时,tlast信号也需要拉高。
上述两点也是AXI VDMA和AXI DMA的区别。