赞
踩
AXI DMA操作需要先提供一个在内存中驻留的不变空间,用于存储需要进行的DMA操作。形容这“每一次操作”的东西叫做Buffer Descriptor,缩写叫BD,这些BD是连接成链表的形式的,因为BD会动态增加,而预先分配存储BD的空间是恒定的,因此BD被连成一个环(BD Ring),其实就是一个循环链表。
Scatter/Gather 允许一个数据包(Packet)由多个描述符(BD)来描述。官方文档指出的一个典型应用是在传输网络包时,Header和数据往往是分开存储的,利用SG模式可以较好的处理向多个目标读写的操作,提高应用吞吐量。 DB Ring中DB成链存放,为了解决环形结构带来的不知道Packet的起点和终点带来的问题,DMA使用了帧开始位 (TXSOF,TX Start of Frame bit) 和帧结束位 (TXEOF,TX End of Frame Bit)来分辨一段Packet。 当 DMA 获取设置了 TXSOF 位的描述符时,将触发Packet的开始。 Packet继续获取后续描述符,直到它获取一个设置了 TXEOF 位的描述符。
在接收 (S2MM) 通道上,当开始接收数据包时,AXI DMA会自动使用 RXSOF 标记描述符,告诉软件部分这个描述符对应的buffer是一个数据包的开头。 如果正在接收的数据包的总字节数比描述符中指定的长,则用下一个描述符接着传。 这种获取和存储过程一直持续到整个接收数据包被传输完毕。 接收到数据包结尾时正在处理的描述符由AXI DMA自动标记为RXEOF=1。表明与该描述符关联的缓冲区包含数据包的结尾。
每个描述符内部指明了该特定描述符实际传输的字节数。 软件可以通过从 RXSOF 描述符通过描述符链到 RXEOF 描述符来确定为接收数据包传输的总字节数。
Scatter Gather 操作从设置控制寄存器和描述符指针开始。
设置和启动 MM2S 通道的 DMA 具体操作如下:
S2MM通道的配置类似:
上源码 (封装IP核的技能自己学一下)
module pl_write( input m_axis_aclk, input m_axis_aresetn, input [63:0] pl_data , input data_en , input m_axis_tready, output reg [31:0] m_axis_tdata, output [3:0] m_axis_tkeep, output m_axis_tlast,v output reg m_axis_tvalid ); parameter DATA_0 = 4'b0000, DATA_1 = 4'b0001, DATA_2 = 4'b0011, DATA_3 = 4'b0010, DATA_4 = 4'b0110, DATA_5 = 4'b0111, DATA_6 = 4'b0101, DATA_7 = 4'b0100, DATA_8 = 4'b1100, DATA_9 = 4'b1101; reg data_en_1; reg [63:0]pl_data_1; reg [3:0] next_flag; assign m_axis_tkeep = 4'b1111; assign m_axis_tlast = (next_flag==DATA_9)&&m_axis_tready&&m_axis_tvalid; always @(posedge m_axis_aclk) begin if(m_axis_aresetn == 1'b0)begin data_en_1<=1'b0; pl_data_1<=64'd0; end else if(m_axis_tready) begin data_en_1<=data_en; pl_data_1<=pl_data; end end always@(posedge m_axis_aclk)begin if(m_axis_aresetn == 1'b0)begin next_flag<=DATA_0; m_axis_tdata <= 32'd0; m_axis_tvalid<=1'b0; end else if(data_en_1) begin m_axis_tvalid<=1'b1; case (next_flag) DATA_0 : begin if(m_axis_tready)begin next_flag<=DATA_1; m_axis_tdata<={32'h22111111}; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_0; end end DATA_1 :begin if(m_axis_tready)begin m_axis_tdata<={32'h22111111}; next_flag<=DATA_2; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_1; end end DATA_2 :begin if(m_axis_tready)begin m_axis_tdata<={32'h22111111}; next_flag<=DATA_3; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_2; end end DATA_3 :begin if(m_axis_tready)begin m_axis_tdata<={32'h22111111}; next_flag<=DATA_4; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_3; end end DATA_4 : begin if(m_axis_tready)begin m_axis_tdata<={8'd01,8'd12,pl_data_1[15:0]}; next_flag<=DATA_5; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_4; end end DATA_5 :begin if(m_axis_tready)begin m_axis_tdata<={8'd02,8'd12,pl_data_1[31:16]}; next_flag<=DATA_6; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_5; end end DATA_6 :begin if(m_axis_tready)begin m_axis_tdata<={8'd03,8'd12,pl_data_1[47:32]}; next_flag<=DATA_7; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_6; end end DATA_7 :begin if(m_axis_tready)begin m_axis_tdata<={8'd04,8'd12,8'd0,pl_data_1[55:48]}; next_flag<=DATA_8; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_7; end end DATA_8 :begin if(m_axis_tready)begin m_axis_tdata<={8'd05,8'd12,8'd0,pl_data_1[63:56]}; next_flag<=DATA_9; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_8; end end DATA_9 :begin if(m_axis_tready)begin m_axis_tdata<={32'hffffffff}; next_flag<=DATA_0; end else begin m_axis_tdata <= m_axis_tdata; next_flag<=DATA_9; end end default:begin next_flag<=DATA_0; m_axis_tdata <= m_axis_tdata; end endcase end else begin m_axis_tvalid<=1'b0; end end endmodule
数据发送IP核根据自己需求创建了
// 要传输的每个packet大小
#define MAX_PKT_LEN 0x4 //缓冲个数 字节
#define MARK_UNCACHEABLE 0x701
// 每个packet对应的BD数量
#define NUMBER_OF_BDS_PER_PKT 11//一个bd 4字节
// 一共要传输的packet个数
#define NUMBER_OF_PKTS_TO_TRANSFER 1
- #include "xaxidma.h"
- #include "xparameters.h"
- #include "xil_exception.h"
- #include "xdebug.h"
- #include "xscugic.h"
- #include "xaxidma_hw.h"
-
- #define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
-
- #define MEM_BASE_ADDR 0x01100000 //ddr地址
- #define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
- #define RX_BD_SPACE_BASE (MEM_BASE_ADDR)
- #define RX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0000FFFF)
- #define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000)
- #define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x00300FFF)
- #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
-
- //超时计数
- #define RESET_TIMEOUT_COUNTER 10000
- // 要传输的每个packet大小
- #define MAX_PKT_LEN 0x4 //缓冲个数 字节
- #define MARK_UNCACHEABLE 0x701
- // 每个packet对应的BD数量
- #define NUMBER_OF_BDS_PER_PKT 11//一个bd 4字节
- // 一共要传输的packet个数
- #define NUMBER_OF_PKTS_TO_TRANSFER 1
- // 总共需要的BD总数
- #define NUMBER_OF_BDS_TO_TRANSFER (NUMBER_OF_PKTS_TO_TRANSFER * \
- NUMBER_OF_BDS_PER_PKT)
-
- //中断合并阈值和延迟定时器阈值我们将合并阈值设置为包的总数。在这个例子中,接收端只会得到一个完成中断。
- #define COALESCING_COUNT NUMBER_OF_PKTS_TO_TRANSFER
- #define DELAY_TIMER_COUNT 100
-
- #define INTC XScuGic
- #define INTC_HANDLER XScuGic_InterruptHandler
- //函数申明
-
- int CheckData(int Length);
- void RxCallBack(XAxiDma_BdRing * RxRingPtr);
- void RxIntrHandler(void *Callback);
- int SetupIntrSystem(INTC * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 RxIntrId);
- void DisableIntrSystem(INTC * IntcInstancePtr, u16 RxIntrId);
- int RxSetup(XAxiDma * AxiDmaInstPtr);
- //设备实例
- XAxiDma AxiDma;
- //中断控制器实例
- static INTC Intc;
- //中断标志
- volatile int RxDone=0;
- volatile int Error=0;
-
- int main(void)
- {
- int Status;
- XAxiDma_Config *Config;
- xil_printf("\r\n--- Entering strart --- \r\n");
- //查找设备配置信息
- Config = XAxiDma_LookupConfig(DMA_DEV_ID);
- if (!Config) {
- xil_printf("No config found for %d\r\n", DMA_DEV_ID);
- return XST_FAILURE;
- }
- //初始化DMA引擎
- XAxiDma_CfgInitialize(&AxiDma, Config);
- if(!XAxiDma_HasSg(&AxiDma)) {
- xil_printf("Device configured as Simple mode \r\n");
- return XST_FAILURE;
- }
- //设置接收通道,以使数据准备好接收
- Status = RxSetup(&AxiDma);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed RX setup\r\n");
- return XST_FAILURE;
- }
- //设置中断
- Status = SetupIntrSystem(&Intc, &AxiDma, RX_INTR_ID);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed intr setup\r\n");
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }
-
- //数据比对
- int CheckData(int Length)
- {
- u8 *RxPacket;
- int Index = 0;
- Xil_DCacheFlushRange((UINTPTR)RX_BUFFER_BASE, MAX_PKT_LEN *NUMBER_OF_BDS_TO_TRANSFER);
- RxPacket = (u8 *) RX_BUFFER_BASE;
- //使指定地址缓存区失效
- Xil_DCacheInvalidateRange((UINTPTR)RxPacket, Length);
- for(Index = 0; Index < Length; Index+=4) {
- xil_printf("Data %d: %x %x %x %x\r\n", Index / 4, RxPacket[Index + 3], RxPacket[Index + 2], RxPacket[Index + 1], RxPacket[Index + 0]);
- }
- RxDone=0;
- RxSetup(&AxiDma);
- XAxiDma_IntrAckIrq(&AxiDma,XAXIDMA_IRQ_IOC_MASK,XAXIDMA_DEVICE_TO_DMA);
- return XST_SUCCESS;
- }
-
- void RxCallBack(XAxiDma_BdRing * RxRingPtr)
- {
- int BdCount;
- XAxiDma_Bd *BdPtr;
- XAxiDma_Bd *BdCurPtr;
- u32 BdSts;
- int Index;
- xil_printf("enter RxCallBack\r\n");
- //获取所有已处理bd
- BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);
- //处理bd
- BdCurPtr = BdPtr;
- for (Index = 0; Index < BdCount; Index++) {
- //检查bd状态并判断是否有错误
- BdSts = XAxiDma_BdGetSts(BdCurPtr);
- if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
- (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {
- Error = 1;
- break;
- }
- //查找下一个处理的bd
- BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
- RxDone += 1;
- }
- CheckData(RxDone);
- }
-
- void RxIntrHandler(void *Callback)
- {
- XAxiDma_BdRing *RxRingPtr = (XAxiDma_BdRing *) Callback;
- u32 IrqStatus;
- int TimeOut;
- /* Read pending interrupts */
- IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);
- /* Acknowledge pending interrupts */
- XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus);
- if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {return;}
- if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
- XAxiDma_BdRingDumpRegs(RxRingPtr);
- Error = 1;
- XAxiDma_Reset(&AxiDma);
- TimeOut = RESET_TIMEOUT_COUNTER;
- while (TimeOut) {
- if(XAxiDma_ResetIsDone(&AxiDma)) {break;}
- TimeOut -= 1;
- }
- return;
- }
- //调用回调
- if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
- xil_printf("Generate rx interrupt\r\n");
- RxCallBack(RxRingPtr);
- }
- }
- //初始化中断
- int SetupIntrSystem(INTC * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 RxIntrId)
- {
- //获取发送/接收 环
- XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(AxiDmaPtr);
- int Status;
- XScuGic_Config *IntcConfig;
- //查找中断控制器信息
- 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, RxIntrId, 0xA0, 0x3);
- //绑定中断处理函数
- Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
- (Xil_InterruptHandler)RxIntrHandler,
- RxRingPtr);
- if (Status != XST_SUCCESS) {
- return Status;
- }
- //启动中断源
- XScuGic_Enable(IntcInstancePtr, RxIntrId);
- //启动硬件中断
- Xil_ExceptionInit();
- //绑定中断异常处理函数
- Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
- (Xil_ExceptionHandler)INTC_HANDLER,
- (void *)IntcInstancePtr);
- //启用IRQ异常
- Xil_ExceptionEnable();
- return XST_SUCCESS;
- }
- //禁用dma中断
- void DisableIntrSystem(INTC * IntcInstancePtr, u16 RxIntrId)
- {
- XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
- }
- //设置读取通道
- int RxSetup(XAxiDma * AxiDmaInstPtr)
- {
- XAxiDma_BdRing *RxRingPtr;
- int Status;
- XAxiDma_Bd BdTemplate;
- XAxiDma_Bd *BdPtr;
- XAxiDma_Bd *BdCurPtr;
- int BdCount;
- int FreeBdCount;
- UINTPTR RxBufferPtr;
- int Index;
- //获取接收环
- RxRingPtr = XAxiDma_GetRxRing(&AxiDma);
- //设置空间之前禁用所有读取中断
- XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
- //设置bd空间
- BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
- RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1);
- //创建bd环
- Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE,RX_BD_SPACE_BASE,
- XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx bd create failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //为Rx通道设置BD模板。然后复制到每个RX BD。
- //bd归零
- XAxiDma_BdClear(&BdTemplate);
- //复制模板到创建的bd 模板为16个4字节数据uint32_t类型
- Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx bd clone failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //在读取bd环上加上缓冲区以便读取数据
- FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
- Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx bd alloc failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- BdCurPtr = BdPtr;
- RxBufferPtr = RX_BUFFER_BASE;
- for (Index = 0; Index < FreeBdCount; Index++) {
- //设置bd缓冲地址
- Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n",
- (unsigned int)RxBufferPtr,
- (UINTPTR)BdCurPtr, Status);
- return XST_FAILURE;
- }
- //为给定的bd设置子段长度
- Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN,
- RxRingPtr->MaxTransferLen);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx set length %d on BD %x failed %d\r\n",
- MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);
- return XST_FAILURE;
- }
- //接收BDs不需要设置任何控件硬件会设置每个流的SOF/EOF位
- //设置bd控制位
- XAxiDma_BdSetCtrl(BdCurPtr, 0);
- //设置bd的id
- XAxiDma_BdSetId(BdCurPtr, RxBufferPtr);
- RxBufferPtr += MAX_PKT_LEN;
- BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
- }
- //设置合并阈值,因此只有一个接收中断在本例中出现如果你想有多个中断发生,改变 COALESCING_COUNT是一个较小的值
- //为给定的描述符环形通道设置中断合并参数。
- Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, COALESCING_COUNT,DELAY_TIMER_COUNT);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx set coalesce failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //将一组bd加入到分配的硬件中
- Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx ToHw failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //使能所有读取中断
- XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
- //启动读取dma通道
- Status = XAxiDma_BdRingStart(RxRingPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx start BD ring failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }

- #include "xaxidma.h"
- #include "xparameters.h"
- #include "xil_exception.h"
- #include "xdebug.h"
- #include "xscugic.h"
-
- #define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
-
- #define MEM_BASE_ADDR 0x01100000 //ddr地址
- #define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
- #define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID
- #define RX_BD_SPACE_BASE (MEM_BASE_ADDR)
- #define RX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0000FFFF)
- #define TX_BD_SPACE_BASE (MEM_BASE_ADDR + 0x00010000)
- #define TX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0001FFFF)
- #define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000)
- #define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000)
- #define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF)
- #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
-
- //超时计数
- #define RESET_TIMEOUT_COUNTER 10000
- // 要传输的每个packet大小
- #define MAX_PKT_LEN 0x100 //缓冲个数
- #define MARK_UNCACHEABLE 0x701
- // 每个packet对应的BD数量
- #define NUMBER_OF_BDS_PER_PKT 12
- // 一共要传输的packet个数
- #define NUMBER_OF_PKTS_TO_TRANSFER 11
- // 总共需要的BD总数
- #define NUMBER_OF_BDS_TO_TRANSFER (NUMBER_OF_PKTS_TO_TRANSFER * \
- NUMBER_OF_BDS_PER_PKT)
-
- /*中断合并阈值和延迟定时器阈值
- *有效范围为1到255
- *我们将合并阈值设置为包的总数。在这个例子中,接收端只会得到一个完成中断。
- */
- #define COALESCING_COUNT NUMBER_OF_PKTS_TO_TRANSFER
- #define DELAY_TIMER_COUNT 100
-
- #define INTC XScuGic
- #define INTC_HANDLER XScuGic_InterruptHandler
- //函数申明
- static int CheckData(int Length, u8 StartValue);
- static void TxCallBack(XAxiDma_BdRing * TxRingPtr);
- static void TxIntrHandler(void *Callback);
- static void RxCallBack(XAxiDma_BdRing * RxRingPtr);
- static void RxIntrHandler(void *Callback);
- static int SetupIntrSystem(INTC * IntcInstancePtr,
- XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
- static void DisableIntrSystem(INTC * IntcInstancePtr,
- u16 TxIntrId, u16 RxIntrId);
- static int RxSetup(XAxiDma * AxiDmaInstPtr);
- static int TxSetup(XAxiDma * AxiDmaInstPtr);
- static int SendPacket(XAxiDma * AxiDmaInstPtr);
-
- //设备实例
- XAxiDma AxiDma;
- //中断控制器实例
- static INTC Intc;
- //中断标志
- volatile int TxDone;
- volatile int RxDone;
- volatile int Error;
-
- //发送数据包缓冲区,必须32位对齐使用
- u32 *Packet = (u32 *) TX_BUFFER_BASE;
-
- int main(void)
- {
- int Status;
- XAxiDma_Config *Config;
- xil_printf("\r\n--- Entering strart --- \r\n");
- //查找设备配置信息
- Config = XAxiDma_LookupConfig(DMA_DEV_ID);
- if (!Config) {
- xil_printf("No config found for %d\r\n", DMA_DEV_ID);
- return XST_FAILURE;
- }
- //初始化DMA引擎
- XAxiDma_CfgInitialize(&AxiDma, Config);
- if(!XAxiDma_HasSg(&AxiDma)) {
- xil_printf("Device configured as Simple mode \r\n");
- return XST_FAILURE;
- }
- //设置发送通道,以使数据准备好发送
- Status = TxSetup(&AxiDma);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed TX setup\r\n");
- return XST_FAILURE;
- }
- //设置接收通道,以使数据准备好接收
- Status = RxSetup(&AxiDma);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed RX setup\r\n");
- return XST_FAILURE;
- }
- //设置中断
- Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed intr setup\r\n");
- return XST_FAILURE;
- }
- //初始化标志信号
- TxDone = 0;
- RxDone = 0;
- Error = 0;
- //发送数据
- Status = SendPacket(&AxiDma);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed send packet\r\n");
- return XST_FAILURE;
- }
- //检查发送接收是否完成
- while (((TxDone < NUMBER_OF_BDS_TO_TRANSFER) ||
- (RxDone < NUMBER_OF_BDS_TO_TRANSFER)) && !Error) {}
- if (Error) {
- xil_printf("Failed test transmit%s done, "
- "receive%s done\r\n", TxDone? "":" not",
- RxDone? "":" not");
- goto Done;
- }else {
- //数据比对
- Status = CheckData(MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER,0xC);
- if (Status != XST_SUCCESS) {
- xil_printf("Data check failed\r\n");
- goto Done;
- }
- xil_printf("Successfully ran AXI DMA SG interrupt Example\r\n");
- }
- //关闭发送、接收中断
- DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);
- Done:
- xil_printf("--- Exiting end --- \r\n");
- if (Status != XST_SUCCESS) {
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }
- //数据比对
- static int CheckData(int Length, u8 StartValue)
- {
- u8 *RxPacket;
- int Index = 0;
- u8 Value;
-
- RxPacket = (u8 *) RX_BUFFER_BASE;
- Value = StartValue;
- //使指定地址缓存区失效
- Xil_DCacheInvalidateRange((UINTPTR)RxPacket, Length);
-
- for(Index = 0; Index < Length; Index++) {
- if (RxPacket[Index] != Value) {
- xil_printf("Data error %d: %x/%x\r\n",
- Index, RxPacket[Index], Value);
- return XST_FAILURE;
- }
- Value = (Value + 1) & 0xFF;
- }
- return XST_SUCCESS;
- }
- //发送回调函数
- static void TxCallBack(XAxiDma_BdRing * TxRingPtr)
- {
- int BdCount;
- u32 BdSts;
- XAxiDma_Bd *BdPtr;
- XAxiDma_Bd *BdCurPtr;
- int Status;
- int Index;
- xil_printf("enter TxCallBack\r\n");
- //获取所有已处理bd
- BdCount = XAxiDma_BdRingFromHw(TxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);
- //处理bd
- BdCurPtr = BdPtr;
- for (Index = 0; Index < BdCount; Index++) {
- //检查bd状态并判断是否有错误
- BdSts = XAxiDma_BdGetSts(BdCurPtr);
- if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
- (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {
- Error = 1;
- break;
- }
- //这里我们什么都不需要做。但是如果RTOS是使用时,我们可能需要释放附加的数据包缓冲区处理过的BD
- /* NOP */
- //查找下一个处理的bd
- BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(TxRingPtr, BdCurPtr);
- }
- //释放所有bd内存以便下一次使用
- Status = XAxiDma_BdRingFree(TxRingPtr, BdCount, BdPtr);
- if (Status != XST_SUCCESS) {
- Error = 1;
- }
- if(!Error) {
- //没有错误返回已处理bd个数
- TxDone += BdCount;
- }
- }
- //发送中断函数
- static void TxIntrHandler(void *Callback)
- {
- XAxiDma_BdRing *TxRingPtr = (XAxiDma_BdRing *) Callback;
- u32 IrqStatus;
- int TimeOut;
- //读取挂起中断
- IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr);
- //确认挂起中断
- XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus);
- if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
- return;
- }
- if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
- XAxiDma_BdRingDumpRegs(TxRingPtr);
- Error = 1;
- //复位
- XAxiDma_Reset(&AxiDma);
- TimeOut = RESET_TIMEOUT_COUNTER;
- while (TimeOut) {
- if (XAxiDma_ResetIsDone(&AxiDma)) {break;}
- TimeOut -= 1;
- }
- return;
- }
- //无错误调用发送回调函数
- if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
- xil_printf("Generate tx interrupt\r\n");
- TxCallBack(TxRingPtr);
- }
- }
-
- static void RxCallBack(XAxiDma_BdRing * RxRingPtr)
- {
- int BdCount;
- XAxiDma_Bd *BdPtr;
- XAxiDma_Bd *BdCurPtr;
- u32 BdSts;
- int Index;
- xil_printf("enter RxCallBack\r\n");
- //获取所有已处理bd
- BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr);
- //处理bd
- BdCurPtr = BdPtr;
- for (Index = 0; Index < BdCount; Index++) {
- //检查bd状态并判断是否有错误
- BdSts = XAxiDma_BdGetSts(BdCurPtr);
- if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) ||
- (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) {
- Error = 1;
- break;
- }
- //查找下一个处理的bd
- BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
- RxDone += 1;
- }
- }
-
- static void RxIntrHandler(void *Callback)
- {
- XAxiDma_BdRing *RxRingPtr = (XAxiDma_BdRing *) Callback;
- u32 IrqStatus;
- int TimeOut;
- /* Read pending interrupts */
- IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr);
- /* Acknowledge pending interrupts */
- XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus);
- if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {return;}
- if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
- XAxiDma_BdRingDumpRegs(RxRingPtr);
- Error = 1;
- XAxiDma_Reset(&AxiDma);
- TimeOut = RESET_TIMEOUT_COUNTER;
- while (TimeOut) {
- if(XAxiDma_ResetIsDone(&AxiDma)) {break;}
- TimeOut -= 1;
- }
- return;
- }
- //调用回调
- if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) {
- xil_printf("Generate rx interrupt\r\n");
- RxCallBack(RxRingPtr);
- }
- }
- //初始化中断
- static int SetupIntrSystem(INTC * IntcInstancePtr,
- XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
- {
- //获取发送/接收 环
- XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaPtr);
- XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(AxiDmaPtr);
- int Status;
- XScuGic_Config *IntcConfig;
- //查找中断控制器信息
- 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, TxIntrId, 0xA0, 0x3);
- XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3);
- //绑定中断处理函数
- Status = XScuGic_Connect(IntcInstancePtr, TxIntrId,
- (Xil_InterruptHandler)TxIntrHandler,
- TxRingPtr);
- if (Status != XST_SUCCESS) {
- return Status;
- }
- Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
- (Xil_InterruptHandler)RxIntrHandler,
- RxRingPtr);
- if (Status != XST_SUCCESS) {
- return Status;
- }
- //启动中断源
- XScuGic_Enable(IntcInstancePtr, TxIntrId);
- XScuGic_Enable(IntcInstancePtr, RxIntrId);
- //启动硬件中断
- Xil_ExceptionInit();
- //绑定中断异常处理函数
- Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
- (Xil_ExceptionHandler)INTC_HANDLER,
- (void *)IntcInstancePtr);
- //启用IRQ异常
- Xil_ExceptionEnable();
- return XST_SUCCESS;
- }
- //禁用dma中断
- static void DisableIntrSystem(INTC * IntcInstancePtr,
- u16 TxIntrId, u16 RxIntrId)
- {
- XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
- XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
- }
- //设置读取通道
- static int RxSetup(XAxiDma * AxiDmaInstPtr)
- {
- XAxiDma_BdRing *RxRingPtr;
- int Status;
- XAxiDma_Bd BdTemplate;
- XAxiDma_Bd *BdPtr;
- XAxiDma_Bd *BdCurPtr;
- int BdCount;
- int FreeBdCount;
- UINTPTR RxBufferPtr;
- int Index;
- //获取接收环
- RxRingPtr = XAxiDma_GetRxRing(&AxiDma);
-
- //设置空间之前禁用所有读取中断
- XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
- //设置bd空间
- BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
- RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1);
- //创建bd环
- Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE,RX_BD_SPACE_BASE,
- XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx bd create failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //为Rx通道设置BD模板。然后复制到每个RX BD。
- //bd归零
- XAxiDma_BdClear(&BdTemplate);
- //复制模板到创建的bd 模板为16个4字节数据uint32_t类型
- Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx bd clone failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //在读取bd环上加上缓冲区以便读取数据
- FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr);
- Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx bd alloc failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- BdCurPtr = BdPtr;
- RxBufferPtr = RX_BUFFER_BASE;
- for (Index = 0; Index < FreeBdCount; Index++) {
- //设置bd缓冲地址
- Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n",
- (unsigned int)RxBufferPtr,
- (UINTPTR)BdCurPtr, Status);
- return XST_FAILURE;
- }
- //为给定的bd设置子段长度
- Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN,
- RxRingPtr->MaxTransferLen);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx set length %d on BD %x failed %d\r\n",
- MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);
- return XST_FAILURE;
- }
- //接收BDs不需要设置任何控件硬件会设置每个流的SOF/EOF位
- //设置bd控制位
- XAxiDma_BdSetCtrl(BdCurPtr, 0);
- //设置bd的id
- XAxiDma_BdSetId(BdCurPtr, RxBufferPtr);
- RxBufferPtr += MAX_PKT_LEN;
- BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(RxRingPtr, BdCurPtr);
- }
-
- //设置合并阈值,因此只有一个接收中断在本例中出现如果你想有多个中断发生,改变 COALESCING_COUNT是一个较小的值
- //为给定的描述符环形通道设置中断合并参数。
- Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, COALESCING_COUNT,DELAY_TIMER_COUNT);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx set coalesce failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //将一组bd加入到分配的硬件中
- Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx ToHw failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- //使能所有读取中断
- XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK);
- //启动读取dma通道
- Status = XAxiDma_BdRingStart(RxRingPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Rx start BD ring failed with %d\r\n", Status);
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }
- //设置发送
- static int TxSetup(XAxiDma * AxiDmaInstPtr)
- {
- XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(&AxiDma);
- XAxiDma_Bd BdTemplate;
- int Status;
- u32 BdCount;
-
- XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);
-
- BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT,
- (UINTPTR)TX_BD_SPACE_HIGH - (UINTPTR)TX_BD_SPACE_BASE + 1);
-
- Status = XAxiDma_BdRingCreate(TxRingPtr, TX_BD_SPACE_BASE,
- TX_BD_SPACE_BASE,
- XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount);
- if (Status != XST_SUCCESS) {
-
- xil_printf("Failed create BD ring\r\n");
- return XST_FAILURE;
- }
-
- XAxiDma_BdClear(&BdTemplate);
- Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate);
- if (Status != XST_SUCCESS) {
-
- xil_printf("Failed clone BDs\r\n");
- return XST_FAILURE;
- }
-
- Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, COALESCING_COUNT,
- DELAY_TIMER_COUNT);
- if (Status != XST_SUCCESS) {
-
- xil_printf("Failed set coalescing"
- " %d/%d\r\n",COALESCING_COUNT, DELAY_TIMER_COUNT);
- return XST_FAILURE;
- }
- XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK);
- Status = XAxiDma_BdRingStart(TxRingPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed bd start\r\n");
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }
-
- static int SendPacket(XAxiDma * AxiDmaInstPtr)
- {
- XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr);
- u8 *TxPacket;
- u8 Value;
- XAxiDma_Bd *BdPtr, *BdCurPtr;
- int Status;
- int Index, Pkts;
- UINTPTR BufferAddr;
- //限制报文长度
- if (MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT >
- TxRingPtr->MaxTransferLen) {
- xil_printf("Invalid total per packet transfer length for the "
- "packet %d/%d\r\n",
- MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT,
- TxRingPtr->MaxTransferLen);
- return XST_INVALID_PARAM;
- }
- TxPacket = (u8 *) Packet;
- //发送数据
- Value = 0xC;
- for(Index = 0; Index < MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER;
- Index ++) {
- TxPacket[Index] = Value;
- Value = (Value + 1) & 0xFF;
- }
- //发送之前刷新缓冲区
- Xil_DCacheFlushRange((UINTPTR)TxPacket, MAX_PKT_LEN *
- NUMBER_OF_BDS_TO_TRANSFER);
- Xil_DCacheFlushRange((UINTPTR)RX_BUFFER_BASE, MAX_PKT_LEN *
- NUMBER_OF_BDS_TO_TRANSFER);
- Status = XAxiDma_BdRingAlloc(TxRingPtr, NUMBER_OF_BDS_TO_TRANSFER,
- &BdPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed bd alloc\r\n");
- return XST_FAILURE;
- }
- BufferAddr = (UINTPTR)Packet;
- BdCurPtr = BdPtr;
- /*
- * Set up the BD using the information of the packet to transmit
- * Each transfer has NUMBER_OF_BDS_PER_PKT BDs
- */
- for(Index = 0; Index < NUMBER_OF_PKTS_TO_TRANSFER; Index++) {
- for(Pkts = 0; Pkts < NUMBER_OF_BDS_PER_PKT; Pkts++) {
- u32 CrBits = 0;
- //设置缓冲区地址
- Status = XAxiDma_BdSetBufAddr(BdCurPtr, BufferAddr);
- if (Status != XST_SUCCESS) {
- xil_printf("Tx set buffer addr %x on BD %x failed %d\r\n",
- (unsigned int)BufferAddr,
- (UINTPTR)BdCurPtr, Status);
- return XST_FAILURE;
- }
- //设置长度字段
- Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN,
- TxRingPtr->MaxTransferLen);
- if (Status != XST_SUCCESS) {
- xil_printf("Tx set length %d on BD %x failed %d\r\n",
- MAX_PKT_LEN, (UINTPTR)BdCurPtr, Status);
- return XST_FAILURE;
- }
- //起始bd设置sof
- if (Pkts == 0) {
- CrBits |= XAXIDMA_BD_CTRL_TXSOF_MASK;
- }
- //最后一个bd设置eof和ioc
- if(Pkts == (NUMBER_OF_BDS_PER_PKT - 1)) {
- CrBits |= XAXIDMA_BD_CTRL_TXEOF_MASK;
- }
-
- XAxiDma_BdSetCtrl(BdCurPtr, CrBits);
- XAxiDma_BdSetId(BdCurPtr, BufferAddr);
- BufferAddr += MAX_PKT_LEN;
- BdCurPtr = (XAxiDma_Bd *)XAxiDma_BdRingNext(TxRingPtr, BdCurPtr);
- }
- }
-
- //将bd交给硬件
- Status = XAxiDma_BdRingToHw(TxRingPtr, NUMBER_OF_BDS_TO_TRANSFER,
- BdPtr);
- if (Status != XST_SUCCESS) {
- xil_printf("Failed to hw, length %d\r\n",
- (int)XAxiDma_BdGetLength(BdPtr,
- TxRingPtr->MaxTransferLen));
- return XST_FAILURE;
- }
- return XST_SUCCESS;
- }

- //
- /* FreeRTOS includes. */
- #include "FreeRTOS.h"
- #include "task.h"
- #include "queue.h"
- #include "timers.h"
-
- /* Xilinx includes. */
- #include "xil_printf.h"
- #include "xparameters.h"
- #include "sleep.h"
- #include "oled_driver.h"
- /* user includes. */
- #include "sg_dma.h"
-
- /*-----------------------------------------------------------*/
- static void dma_rx_Task( void *pvParameters );
- static void oled_Task( void *pvParameters );
- static void led_Task(void *pvParameters);
-
- static TaskHandle_t dma_RxTask;
- static TaskHandle_t oled;
- static TaskHandle_t led;
- static QueueHandle_t xQueue = NULL;
- static QueueHandle_t led_flag = NULL;
- extern int rx_data_buf[4];
-
- int main( void )
- {
- xil_printf( "Hello from Intelligent home system\r\n" );
- sg_dma_init();
- xTaskCreate( dma_rx_Task,
- ( const char * ) "DMA_RX",
- configMINIMAL_STACK_SIZE,
- NULL,
- tskIDLE_PRIORITY,
- &dma_RxTask );
-
- xTaskCreate( oled_Task,
- ( const char * ) "oled",
- configMINIMAL_STACK_SIZE,
- NULL,
- tskIDLE_PRIORITY+1 ,
- &oled );
-
- xTaskCreate( led_Task,
- ( const char * ) "led",
- configMINIMAL_STACK_SIZE,
- NULL,
- tskIDLE_PRIORITY+2,
- &led );
- //创建队列
- xQueue = xQueueCreate( 1,sizeof( rx_data_buf ) );
- led_flag = xQueueCreate( 1,3);
- //检查队列是否创建
- configASSERT( xQueue );
-
- vTaskStartScheduler();
-
- for( ;; );
- }
-
- static void dma_rx_Task( void *pvParameters )
- {
- for( ;; )
- {
- rx_data();
- xil_printf("task1\r\n");
- xQueueSend( xQueue,
- rx_data_buf,
- 0UL );
- }
- }
-
- static void oled_Task( void *pvParameters )
- {
- int Recdstring[4] = {0};
- u8 key_val;
- u8 led_data[3]={0};
- for( ;; )
- {
- xil_printf("task2\r\n");
- xQueueReceive( xQueue,
- Recdstring,
- portMAX_DELAY );
- OLED_ShowNum(34,0,Recdstring[0],2,16);
- OLED_ShowNum(34,2,Recdstring[1],2,16);
- OLED_ShowNum(98,2,Recdstring[2],1,16);
- OLED_ShowNum(98,0,Recdstring[3],3,16);
-
- if (READ == 0){
- usleep(20000);
- if (READ == 0)
- key_val = ~key_val;}while(READ == 0){}
- if(key_val){
- if(Recdstring[3]<200)
- {
- led_data[0]=1;
-
- }else{
-
- led_data[0]=0;
- }
- if(Recdstring[0]>28)
- {
- led_data[1]=1;
- }else{
- led_data[1]=0;
- }
- if(Recdstring[2]>50)
- {
- led_data[2]=1;
-
- }else{
- led_data[2]=0;
- }
- xQueueSend( led_flag,
- led_data,
- 0UL );
- }
- }
- }
-
- static void led_Task(void *pvParameters)
- {
- u8 led[3];
- for( ;; )
- {
- xil_printf("task3\r\n");
- xQueueReceive( led_flag,
- led,
- portMAX_DELAY );
- if(led[0]){
- LIGHT_HGIH;
- }else{
- LIGHET_LOW;
- }
- if(led[1]){
- AIR_HIGH;
- }else{
- AIR_LOW;
- }
- if(led[2]){
- flag_HIGH;
- }else{
- flag_LOW;
- }
- }
- }
-

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。