VDMA IP核 vitis代码使用

/*****************************************************************************/
/**
*
* run_vdma_frame_buffer API
*
* 这个API是应用程序与其他API之间的接口。当应用程序使用正确的参数调用此API时,
* 该API将调用其他API来配置VDMA的读取和写入路径,基于ID。之后,它将启动VDMA的读取和写入路径。
*
* @param	InstancePtr 是XAxiVdma数据结构的句柄。
* @param	DeviceId 是当前VDMA的设备ID。
* @param	hsize 是帧的水平尺寸。它将以像素为单位。
* 		帧的实际大小将通过将此值与tdata宽度相乘来计算。
* @param 	vsize 是帧的垂直尺寸。
* @param	buf_base_addr 是帧将被VDMA写入和读取的缓冲区地址。
* @param 	number_frame_count 指定中断应在多少帧后发生。
* @param 	enable_frm_cnt_intr 用于启用帧计数中断
*		当设置为1时。
* @param    select 用于设置读取通道、写入通道或者读取和写入通道。
* @return
*		- XST_SUCCESS 如果示例成功完成
*		- XST_FAILURE 如果示例失败。
*
******************************************************************************/

int run_vdma_frame_buffer(XAxiVdma* InstancePtr, int DeviceId, int hsize,
		int vsize, int buf_base_addr, int number_frame_count,
		int enable_frm_cnt_intr,vdma_run_mode mode)
{
	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].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].buffer_address = 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 */
	if ((mode == BOTH) || (mode == ONLY_WRITE)) {
		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 */
	if ((mode == BOTH) || (mode == ONLY_READ)) {
		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,mode);
	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].WriteCfg.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;
}

一个比较经典的VDMA的初始化代码串,其原型是这个例程。

在例程的基础上添加了模式选择,也就是vdma_run_mode mode传入参数,可以选择只读、只写、读写模式。

例程中的代码是经典的三缓存VDMA函数,虽然函数名字写着三缓存,但其实VDMA的帧缓存数量不在代码中设置(也可能是我没发现),如果想改变帧缓存的设置,可以在BD设计中对VDMA IP核进行修改。

在两个读写通道的设置函数中,

vdma_context->InstancePtr->MaxNumFrames就是帧缓存数量,是平台自带的参数,由BD设计决定。而划线的部分则是缓存地址设置函数。

这部分设置我照抄例程了,没仔细看。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
VDMA(Video Direct Memory Access)是一种用于视频数据传输的硬件模块,它可以在FPGA和DDR内存之间进行高速数据传输。在Linux系统中,可以使用VDMA测试代码来验证VDMA模块的功能和性能。 以下是一个简单的Linux VDMA测试代码示例: ```c #include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> #define VDMA_BASE_ADDR 0x40000000 // VDMA模块的基地址 #define FRAME_SIZE 1920*1080*4 // 每帧图像的大小,假设为1920x1080像素,每个像素4字节 int main() { int fd; void *vdma_base; unsigned int *frame_buffer; // 打开/dev/mem设备文件 fd = open("/dev/mem", O_RDWR | O_SYNC); if (fd < 0) { perror("Failed to open /dev/mem"); return -1; } // 映射VDMA模块的物理地址到用户空间 vdma_base = mmap(NULL, FRAME_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, VDMA_BASE_ADDR); if (vdma_base == MAP_FAILED) { perror("Failed to mmap VDMA base address"); close(fd); return -1; } // 将void指针转换为unsigned int指针,方便操作 frame_buffer = (unsigned int *)vdma_base; // 在这里可以进行VDMA的测试操作,例如写入图像数据到帧缓冲区,或者从帧缓冲区读取图像数据 // 解除映射并关闭文件 munmap(vdma_base, FRAME_SIZE); close(fd); return 0; } ``` 上述代码中,首先通过`open`函数打开`/dev/mem`设备文件,然后使用`mmap`函数将VDMA模块的物理地址映射到用户空间。接下来,可以通过操作`frame_buffer`指针来进行VDMA的测试操作,例如写入图像数据到帧缓冲区或从帧缓冲区读取图像数据。最后,使用`munmap`函数解除映射并关闭文件。 请注意,上述代码只是一个简单的示例,实际的VDMA测试代码可能需要更多的配置和操作,具体的实现方式可能会因硬件平台和应用需求而有所不同。在实际使用中,建议参考相关的文档和资料,并根据具体情况进行适当的修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值