HEAD
配置思路:
初始数据定义
#include "xaxidma.h" //dma #include "xparameters.h"//设备 #include "xscugic.h" //中断 #include "xil_printf.h" //串口 #define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID //DMA设备ID #define INT_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID //中断设备ID #define INTR_S2MM_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID //DMA接收中断ID #define FIFO_DATABYTE 4 //FIFO内单个数据4字节 #define TEST_COUNT 80 //测试数据列长80个数据 #define MAX_PKT_LEN TEST_COUNT*FIFO_DATABYTE //分配地址长度 #define TEST_START_VALUE 0xc //初始测试数据 #define NUMBER_OF_TRANSFERS 2 //测试次数 int XAxiDma_Setup(u16 DeviceId); //DMA配置函数 static int CheckData(void); //中断处理函数 int SetInterruptInit(XScuGic *InstancePtr, u16 IntrID, XAxiDma *XAxiDmaPtr); //中断配置函数 XScuGic INST; //中断控制器实例 XAxiDma AxiDma; //XAxiDma 实例 u8 TxBufferPtr[MAX_PKT_LEN]; //发送数据列 u8 RxBufferPtr[MAX_PKT_LEN]; //接收数据列
主程序
int main() { int Status; xil_printf("\r\n--- Entering main() --- \r\n"); Status=XAxiDma_Setup(DMA_DEV_ID); if(Status!=XST_SUCCESS){ xil_printf("XAxiDma Test Failed\r\n"); return XST_FAILURE; } xil_printf("Successfully Ran XAxiDma Test\r\n"); xil_printf("---Exiting main()---\r\n"); return XST_SUCCESS; }
中断配置函数
int SetInterruptInit(XScuGic *InstancePtr, u16 IntrID, XAxiDma *XAxiDmaPtr) { XScuGic_Config * Config ; int Status ; //初始化中断控制器驱动 Config = XScuGic_LookupConfig(INT_DEVICE_ID) ; Status = XScuGic_CfgInitialize(&INST, Config, Config->CpuBaseAddress) ; if (Status != XST_SUCCESS) return XST_FAILURE ; //设置中断优先级和触发类型 //XScuGic_SetPriorityTriggerType(int_ins_ptr, tx_intr_id,0xa0,0x3); //XScuGic_SetPriorityTriggerType(int_ins_ptr,rx_intr_id,0xA0,0x3); //为中断设置中断处理函数 Status = XScuGic_Connect(InstancePtr, IntrID, (Xil_ExceptionHandler)CheckData, //此处写入中断处理函数 XAxiDmaPtr) ; if (Status != XST_SUCCESS) { return Status; } //使能中断 XScuGic_Enable(InstancePtr, IntrID) ; //启用来自硬件的中断 Xil_ExceptionInit(); Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,(Xil_ExceptionHandler) XScuGic_InterruptHandler,InstancePtr); Xil_ExceptionEnable(); return XST_SUCCESS ; }
DMA配置函数
int XAxiDma_Setup(u16 DeviceId) { XAxiDma_Config *CfgPtr; int Status; int Tries = NUMBER_OF_TRANSFERS; int Index; u8 Value; //查找DMA硬件配置信息 CfgPtr = XAxiDma_LookupConfig(DeviceId); if (!CfgPtr) { xil_printf("No config found for %d\r\n", DeviceId); return XST_FAILURE; } //初始化DMA引擎 Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr); if (Status != XST_SUCCESS) { xil_printf("Initialization failed %d\r\n", Status); return XST_FAILURE; } //判断有无使能sg模式,如果使能则返回错误 if(XAxiDma_HasSg(&AxiDma)){ xil_printf("Device configured as SG mode \r\n"); return XST_FAILURE; } //中断函数初始化 Status = SetInterruptInit(&INST,INTR_S2MM_ID, &AxiDma) ; if (Status != XST_SUCCESS) return XST_FAILURE ; /* Disable MM2S interrupt, Enable S2MM interrupt */ //使能中断 //当DMA向DDR写完数据后,发送中断 XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_IOC_MASK, XAXIDMA_DEVICE_TO_DMA); XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DMA_TO_DEVICE); //初始化发送数据数组 Value = TEST_START_VALUE; for(Index = 0; Index < MAX_PKT_LEN; Index ++) { TxBufferPtr[Index] = Value; Value = (Value + 1) & 0xFF; } /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache is enabled*/ //在发送数据前把cache里的数据写入到DDR中 /*由于DMA需要访问DDR3,而CPU与DDR3之间是通过Cache交互的,数据暂存在Cache里, 可能没有真正刷新到DDR3,如果外部设备也就是DMA想要读取 DDR3的值,必须将Cache里的数据刷新到DDR3中,这样DMA才能读到正确的值。调用 Xil_DCacheFlushRange函数,需要给出内存地址和长度。 */ Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN); Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN); for(Index = 0; Index < Tries; Index ++) { Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) TxBufferPtr,MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE); if (Status != XST_SUCCESS) { return XST_FAILURE; } //虽然看起来读和写都同时打开,但由于stream流的协议,会等待FIFO里有数据才开始传输 Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) RxBufferPtr,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA); if (Status != XST_SUCCESS) { return XST_FAILURE; } //确保cache写入到DDR当中 while ((XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA)) || (XAxiDma_Busy(&AxiDma,XAXIDMA_DMA_TO_DEVICE))) { /* Wait */ } } /* Test finishes successfully */ return XST_SUCCESS; }
中断处理函数
static int CheckData(void) { u8 *RxPacket; int Index = 0; u8 Value; RxPacket = RxBufferPtr; Value = TEST_START_VALUE; xil_printf("Enter Interrupt\r\n"); /*清除中断标志位*/ XAxiDma_IntrAckIrq(&AxiDma, XAXIDMA_IRQ_IOC_MASK,XAXIDMA_DEVICE_TO_DMA) ; /* Invalidate the DestBuffer before receiving the data, in case the Data Cache is enabled*/ /*在中断服务程序中,首先清除中断,由于 DDR3 中的数据已经更新,但 Cache 中的数据并 没有更新,CPU 如果想从 DDR3 中读取数据,需要调用 Xil_DCacheInvalidateRang 函数,将 Cache 数据作废,这样 CPU 就能从 DDR3 中读取正确的数据。同样也要给出内存地址和长 度。*/ Xil_DCacheInvalidateRange((UINTPTR)RxPacket, MAX_PKT_LEN); //数据比对 for(Index = 0; Index < MAX_PKT_LEN; Index++) { if (RxPacket[Index] != Value) { xil_printf("Data error %d: %x/%x\r\n", Index, (unsigned int)RxPacket[Index], (unsigned int)Value); return XST_FAILURE; } Value = (Value + 1) & 0xFF; } return XST_SUCCESS; }