ZYNQ使用AXI DMA(Scatter/Gather)模式进行PL与PS数据交互附源码(ps端移植freertos或者裸机)

简介

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 具体操作如下:

  • 将起始描述符的位置写入Current Descriptor寄存器中
  • 设置运行/停止位为1(MM2S_DMACR.RS=1)启动MM2S运行
  • (可选)启用中断(MM2S_DMACR.IOC_IrqEn 和 MM2S_DMACR.Err_IrqEn)
  • 将末尾描述符位置写入Tail Descriptor寄存器中,写入后会立刻触发DMA获取描述符,如果是多通道,这一步骤会在数据包到达S2MM时开始
  • 处理当前描述符,从内存中读取数据并转化成Stream输出

S2MM通道的配置类似:

  • 将起始描述符的位置写入Current Descriptor寄存器中
  • 通过将运行/停止位设置为 1 (S2MM_DMACR.RS =1) 来启动 S2MM 通道运行,并且暂停位 (DMASR.Halted) 置低,指示 S2MM 通道正在运行
  • (可选)启用中断(MM2S_DMACR.IOC_IrqEn 和 MM2S_DMACR.Err_IrqEn)
  • 将有效地址写入尾部描述符寄存器,自动触发 DMA 从内存获取描述符
  • 处理获取的描述符,并将从 S2MM 流式通道接收到的任何数据写入内存

不说了理论知识去看其他up分享我们直接上配置教程

AXI DMA 配置

 AXI FIFO配置

 

 ZYNQ配置

 

 

 配置完成我们进行AXI Stream流接口ip核的设计

上源码    (封装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核根据自己需求创建了

上ps端代码

注意:每一个bd可存储4字节的数据 bd串联为一个环形成一个数据包packet

// 要传输的每个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;
}

此代码为回环 DMA需要勾选发送和接收端口并直接将zynq接收和发送端连接起来形成回环就可以了

#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;
}

笔者使用它进行传感器数据搬运到ddr  ps端移植freertos进行oled显示与控制

附上freertos的代码吧官方只是移植了一个框架使用重点在任务间的数据传递以及调度器的使用

//
/* 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;
		}
	}
}

  • 4
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Zynq RTOS scatter/gather DMA是指在Zynq嵌入式系统中使用的一种特殊的DMA技术。DMA(Direct Memory Access,直接存储器访问)是一种数据传输方式,它允许外部设备直接访问系统内存,而不需要CPU的干预。 Zynq是一种集成了ARM处理器和可编程逻辑的芯片,它在嵌入式系统中常用于高性能计算和数据处理任务。而RTOS(Real-Time Operating System,实时操作系统)是一种专为嵌入式系统设计的操作系统,具有实时性和可预测性。 scatter/gather DMA是一种高效的DMA传输方式,它允许数据按照预定义的映射关系从不同的源地址传输到不同的目标地址,而无需 CPU 的介入。这种方式可以大大减轻 CPU 的负担,提高数据传输的效率和速度。 在Zynq RTOS中,scatter/gather DMA通常用于处理需要大量数据传输的应用,如音频、视频、网络数据包等。通过配置DMA控制器和内存映射表,可以实现从多个源地址到多个目标地址的数据传输,从而实现高效的数据处理。 在使用scatter/gather DMA时,首先需要配置DMA控制器,设置数据传输的源地址、目标地址、传输长度等参数。然后,根据具体的需求,配置内存映射表,定义每个源地址和目标地址之间的映射关系。最后,启动DMA传输,它会按照预定义的映射关系自动完成数据传输,无需 CPU 的干预。 通过使用Zynq RTOS scatter/gather DMA,可以实现高效的数据传输和处理,节约 CPU 的资源,提高系统性能和响应速度。这种技术在许多嵌入式系统中被广泛应用,为复杂的数据处理任务提供了一种有效的解决方案。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值