【ZYNQ7000学习之旅 - 02】CDMA练习

参考

  1. xilinx ug1165
  2. pynq z-2 用户手册
  3. Cache:zynq的cache

准备

  1. Vivado2020.1
  2. Vitis2020.1
  3. pynq z-2

功能

在DDR中,一段内存中的数据搬到另一段。

生成XSA文件

基于上一章的工程,PS端的中断由原来的AXI TIMER改为CDMA的中断。

设置HP接口,HP0作为DMA的源地址,HP2作为DMA的目的地址,选择64位:

在这里插入图片描述
设置HP的地址,此处需要注意,因为在设置地址的过程中会造成地址冲突,只要右键点击,选择unassign(不分配),设置完一个之后再回来设置这个,注意所有的AXI外设都需要assign地址,不然launch vitis的时候不会为外设分配地址:
在这里插入图片描述
综合生成.xsa文件,launch vitis。

编写APP

直接参考ug的代码:

#include <stdio.h>
#include "platform.h"
#include "xaxicdma.h"
#include "xdebug.h"
#include "xil_exception.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "xscugic.h"

#define NUMBER_OF_TRANSFERS	2	/* Number of simple transfers to do */
#define DMA_CTRL_DEVICE_ID 	XPAR_AXICDMA_0_DEVICE_ID
#define INTC_DEVICE_ID		XPAR_SCUGIC_SINGLE_DEVICE_ID
#define DMA_CTRL_IRPT_INTR	XPAR_FABRIC_AXI_CDMA_0_CDMA_INTROUT_INTR

volatile static int Done = 0;	/* Dma transfer is done */
volatile static int Error = 0;	/* Dma Bus Error occurs */

static u32 SourceAddr 	= 0x10000000;
static u32 DestAddr 	= 0x18000000;

static XAxiCdma AxiCdmaInstance;	/* Instance of the XAxiCdma */
static XScuGic IntcController;	/* Instance of the Interrupt Controller */



static int Array_3[32][16];
static int Array_4[32][16];

static int Array_1[32][16];
static int Array_2[32][16];

int const input[16] = {0xb504f33, 0xabeb4a0, 0xa267994, 0x987fbfc, 0x8e39d9c, 0x839c3cc, 0x78ad74c, 0x6d743f4, 0x61f78a8, 0x563e6a8, 0x4a5018c, 0x3e33f2c, 0x31f1704, 0x259020c, 0x1917a64, 0xc8fb2c};
/* Length of the buffers for DMA transfer */
static u32 BUFFER_BYTESIZE	= (XPAR_AXI_CDMA_0_M_AXI_DATA_WIDTH * XPAR_AXI_CDMA_0_M_AXI_MAX_BURST_LEN);


static int CDMATransfer(XAxiCdma *InstancePtr, int Length, int Retries);

static void DisableIntrSystem(XScuGic *IntcInstancePtr , u32 IntrId)

{
		XScuGic_Disable(IntcInstancePtr ,IntrId );
		XScuGic_Disconnect(IntcInstancePtr ,IntrId );

}
//Multiply and Shift
int MUL_SHIFT_30(int x, int y)
{
  return ((int) (((long long) (x) * (y)) >> 30));
}


void MULT_SHIFT_LOOP(int Value )
{
   int i, j;
   for (i = 0; i < 32; i++) {

      for (j = 0; j < 16; j++) {

    	  Array_3[i][j] = (int)((MUL_SHIFT_30(input[j],Array_1[j][i])) + Value);
    	  Array_4[i][j] = (int)((MUL_SHIFT_30(input[j],Array_2[j][i])) + Value);
      }
   }
}

void TestPattern_Initialization(void)
{
	 int i, j;
	   for (i = 0; i < 32; i++)
	   {
	      for (j = 0; j < 16; j++)
	      {
	    	  Array_1[i][j] =  (int ) ((0xA5A5A5A5 >> 1) * i );
	    	  Array_2[i][j] =  (int ) ((0xA5A5A5A5 << 1) * i );
	      }
	   }
}
/*****************************************************************************/
/*
* Callback function for the simple transfer. It is called by the driver's
* interrupt handler.
*
* @param	CallBackRef is the reference pointer registered through
*		transfer submission. In this case, it is the pointer to the
* 		driver instance
* @param	IrqMask is the interrupt mask the driver interrupt handler
*		passes to the callback function.
* @param	IgnorePtr is a pointer that is ignored by simple callback
* 		function
*
* @return	None
*
* @note		None
*
******************************************************************************/
static void Cdma_CallBack(void *CallBackRef, u32 IrqMask, int *IgnorePtr)
{

	if (IrqMask & XAXICDMA_XR_IRQ_ERROR_MASK) {
		Error = TRUE;
		printf("\r\n--- Transfer Error --- \r\n");
	}

	if (IrqMask & XAXICDMA_XR_IRQ_IOC_MASK) {
		printf("\r\n--- Transfer Done --- \r\n");
		Done = TRUE;
	}

}
//初始化GIC,u32 IntrId应该是中断
static int SetupIntrSystem(XScuGic *IntcInstancePtr, XAxiCdma *InstancePtr,
			u32 IntrId)
{
	int Status;


	/*
	 * Initialize the interrupt controller driver
	 */
	XScuGic_Config *IntcConfig;


	/*
	 * Initialize the interrupt controller driver so that it is ready to
	 * use.
	 */
	IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
	if (NULL == IntcConfig) {
		return XST_FAILURE;
	}

	Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
					IntcConfig->CpuBaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	XScuGic_SetPriorityTriggerType(IntcInstancePtr, IntrId, 0xA0, 0x3);

	/*
	 * Connect the device driver handler that will be called when an
	 * interrupt for the device occurs, the handler defined above performs
	 * the specific interrupt processing for the device.
	 */
	Status = XScuGic_Connect(IntcInstancePtr, IntrId,
				(Xil_InterruptHandler)XAxiCdma_IntrHandler,
				InstancePtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	/*
	 * Enable the interrupt for the DMA device.
	 */
	XScuGic_Enable(IntcInstancePtr, IntrId);




	Xil_ExceptionInit();

	/*
	 * Connect the interrupt controller interrupt handler to the hardware
	 * interrupt handling logic in the processor.
	 */
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
				(Xil_ExceptionHandler)XScuGic_InterruptHandler,
				IntcInstancePtr);


	/*
	 * Enable interrupts in the Processor.
	 */
	Xil_ExceptionEnable();


	return XST_SUCCESS;
}

//初始化CDMA
int XAxiCdma_Interrupt(XScuGic *IntcInstancePtr, XAxiCdma *InstancePtr,
	u16 DeviceId, u32 IntrId)
{
	{
		XAxiCdma_Config *CfgPtr;
		int Status;
		int SubmitTries = 1;		/* Retry to submit */
		int Tries = NUMBER_OF_TRANSFERS;
		int Index;

		/* Initialize the XAxiCdma device.
		 */
		CfgPtr = XAxiCdma_LookupConfig(DeviceId);
		if (!CfgPtr) {
			return XST_FAILURE;
		}

		Status = XAxiCdma_CfgInitialize(InstancePtr, CfgPtr, CfgPtr->BaseAddress);
		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}

		/* Setup the interrupt system
		 */
		Status = SetupIntrSystem(IntcInstancePtr, InstancePtr, IntrId);
		if (Status != XST_SUCCESS) {
			return XST_FAILURE;
		}

		/* Enable all (completion/error/delay) interrupts
		 */
		XAxiCdma_IntrEnable(InstancePtr, XAXICDMA_XR_IRQ_ALL_MASK);

		for (Index = 0; Index < Tries; Index++) {
			Status = CDMATransfer(InstancePtr,
				   BUFFER_BYTESIZE, SubmitTries);

			if(Status != XST_SUCCESS) {
				DisableIntrSystem(IntcInstancePtr, IntrId);
				return XST_FAILURE;
			}
		}

		/* Test finishes successfully, clean up and return
		 */
		DisableIntrSystem(IntcInstancePtr, IntrId);

		return XST_SUCCESS;
	}
}
/*****************************************************************************/
/*
*
* This function does  CDMA transfer
*
* @param	InstancePtr is a pointer to the XAxiCdma instance
* @param	Length is the transfer length
* @param	Retries is how many times to retry on submission
*
* @return
*		- XST_SUCCESS if transfer is successful
*		- XST_FAILURE if either the transfer fails or the data has
*		  error
*
* @note		None
*
******************************************************************************/
static int CDMATransfer(XAxiCdma *InstancePtr, int Length, int Retries)
{

	int Status;

	Done = 0;
	Error = 0;


	printf("Start Transfer \n\r");
	/* Try to start the DMA transfer
	 */
		Done = 0;
		Error = 0;

		/* Flush the SrcBuffer before the DMA transfer, in case the Data Cache
		 * is enabled
		 */
		Xil_DCacheFlushRange((u32)SourceAddr, Length);//刷新cache

		Status = XAxiCdma_SimpleTransfer(InstancePtr,
										(u32)(u8 *) (SourceAddr ),
										(u32)(DestAddr),
										Length,
										Cdma_CallBack,
										(void *)InstancePtr);

		if (Status == XST_FAILURE) {
			printf("Error in Transfer  \n\r");
			return 1;
		}



		/* Wait until the DMA transfer is done
			 */
			while (!Done && !Error) {
				/* Wait */
			}

			if (Error) {
				return XST_FAILURE;
				return 1;
			}
		/* Invalidate the DestBuffer before receiving the data, in case the
		 * Data Cache is enabled
		 */
		Xil_DCacheInvalidateRange((u32)DestAddr, Length);

	return XST_SUCCESS;
}
int main()
{
	int Status;
	u32  *SrcPtr;
	u32  *DestPtr;
	unsigned int  Index;
	int i, j;

    printf("\r\n--- Entering main() --- \r\n");

	/*********************************************************************************
		Step : 1 : Intialization of the SOurce Memory with the Specified test pattern
			   	   Clear Destination memory
	**********************************************************************************/
    TestPattern_Initialization();

    /* Initialize the source buffer bytes with a pattern and the
    	 * the destination buffer bytes to zero
   	 */
   	SrcPtr = (u32*)SourceAddr;
   	DestPtr = (u32 *)DestAddr;
   	for (Index = 0; Index < (BUFFER_BYTESIZE/1024); Index++)
   	{
   		MULT_SHIFT_LOOP((Index*100));
   		for (i = 0; i < 32; i++)
   		{
   			for (j = 0; j < 16; j++)
   			{
   				SrcPtr[((i+j))*(Index+1)] 		= Array_3[i][j];
   				SrcPtr[((i+j)*(Index+1)) + 1] 	= Array_4[i][j];
   				DestPtr[(i+j)*(Index+1)] 		= 0;
   				DestPtr[((i+j)*(Index+1)) + 1] = 0;
   			}

   		}

   	}
	/*********************************************************************************
		Step : 2 : AXI CDMA Intialization
				   Association of the CDMA ISR with the Interrupt
				   Enable the CDMA Interrupt
			   	   Provide Source and destination location to CDMA
			   	   Specified Number of byte to be transfer to CDMA register
			       Start the CDMA
			   	   Wait for the Interrupt and return the status
	**********************************************************************************/

    Status = XAxiCdma_Interrupt( &IntcController,
    							&AxiCdmaInstance,
    							DMA_CTRL_DEVICE_ID,
   								DMA_CTRL_IRPT_INTR
   								);

   	if (Status != XST_SUCCESS) {

    		printf("XAxiCdma_Interrupt: Failed\r\n");
    		return XST_FAILURE;
    	}

    	xil_printf("XAxiCdma_Interrupt: Passed\r\n");


    /*********************************************************************************
		Step : 3 : Compare Source memory with Destination memory
				   Return the Status
	**********************************************************************************/
    	for (Index = 0; Index < (BUFFER_BYTESIZE/4); Index++)
    	{
    		if ( DestPtr[Index] != SrcPtr[Index])
    		{
    			printf("Error in Comparison : Index : %x \n\r", Index);
    			return XST_FAILURE;
    		}
    	}

    	printf("DMA Transfer is Successful \n\r");
    	return XST_SUCCESS;


    return 0;
}

总结

一定要确认vivado的Address Editor中外设都分配了地址,之前误操作unassign导致项目编译的时候很多东西找不到。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一匹狼呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值