【JokerのZYNQ7020】AXI_DMA_PL_PS。

软件环境:vivado 2017.4        硬件平台:XC7Z020 


这篇跟上一篇AXI_DMA_LOOP大体框架差不多,差别主要是体现在这次PS接收端的数据不是自己预先发送的,而是在PL端产生,然后通过AXI4_Stream送过来的。所以主要还是想说一下PL端AXI4_Stream数据产生及握手的整个过程。

AXI4_Stream与AXI4_FULL、AXI4_LITE最大的不同是接口不包含地址线,这样的话不用牵扯读写地址的操作,直接发送接收数据,大大的加快了传输的速度。那数据是发送到哪,又从哪接收的呢?当然是看DMA了,DMA在初始化的时候,就会配置好源地址寄存器和目的地址寄存器。

主要接口信号种类及作用大致描述如下。

信号 

描述

ACLK

时钟源

全局时钟信号。所有信号在ACLK信号上升沿采样。

ARESETn

复位源

全局复位信号。ARESETn低电平有效。

TVALID

TVALID表示主设备正在驱动一个有效的传输。当TVALID和TREADY都置位时,发生一个传输。

TREADY

TREADY表示从设备在当前周期能够接收一次传输。

TDATA[(8n-1):0]

TDATA是基本的有效载荷,用来提供跨越接口的数据。数据为整数个字节。

TSTRB[(n-1):0]

TSTRB位字节修饰符。用来描述TDATA相关字节内容作为一个数字字节或者一个位置字节被处理。

TKEEP[(n-1):0]

TKEEP是字节修饰符。用来表明TDATA相关字节的内容是否作为数据流的一部分被处理。TKEEP字节修饰符未被确认的那些相关字节是空字节,可以从数据流中去除。

TLAST

TLAST表明了包的边界。

TID[(i-1):0]

TID是数据流的标识符,用来表明不同的数据流。

TDEST[(d-1):0]

TDEST为据流提供路由信息。

TUSER[(n-1):0]

TUSER是用户定义的边带信息,这它能伴随数据流进行发送。

 时序关系除了没有地址操作以外,同AXI4_FULL差不多,都是在VALID和READY同时为高时,DATA数据有效。

这里在哔哔一下这个KEEP信号,KEEP信号位宽数需要等于DATA字节数,也就是说,当传送32bits数据时候,若全32bits数据均有效,则需将KEEP信号置4‘b1111。


Vivado 2017.4 建立如下连接关系。

 注意,时钟开两个100MHz的,然后DMA设置如下。

 左边AXI4_Stream DATA FIFO 0往PS端不停送入0~1023数据,配置如下。

 这里还要注意一下,最左边S_AXIS接口,也需要改动一下,就是下图中用红框框出的地方,双击打开,然后更改,加入KEEP。

 右边AXI4_Stream DATA FIFO 1是PS送到PL的数据,配置如下。

 都搞定以后,Generate Output Products,然后生成顶层文件,再对顶层文件做如下改动,自动通过AXI4_Stream发数。

`timescale 1 ps / 1 ps

module dma_system_wrapper
   (
    DDR_addr,
    DDR_ba,
    DDR_cas_n,
    DDR_ck_n,
    DDR_ck_p,
    DDR_cke,
    DDR_cs_n,
    DDR_dm,
    DDR_dq,
    DDR_dqs_n,
    DDR_dqs_p,
    DDR_odt,
    DDR_ras_n,
    DDR_reset_n,
    DDR_we_n,
    FIXED_IO_ddr_vrn,
    FIXED_IO_ddr_vrp,
    FIXED_IO_mio,
    FIXED_IO_ps_clk,
    FIXED_IO_ps_porb,
    FIXED_IO_ps_srstb
);
  inout [14:0]DDR_addr;
  inout [2:0]DDR_ba;
  inout DDR_cas_n;
  inout DDR_ck_n;
  inout DDR_ck_p;
  inout DDR_cke;
  inout DDR_cs_n;
  inout [3:0]DDR_dm;
  inout [31:0]DDR_dq;
  inout [3:0]DDR_dqs_n;
  inout [3:0]DDR_dqs_p;
  inout DDR_odt;
  inout DDR_ras_n;
  inout DDR_reset_n;
  inout DDR_we_n;
  inout FIXED_IO_ddr_vrn;
  inout FIXED_IO_ddr_vrp;
  inout [53:0]FIXED_IO_mio;
  inout FIXED_IO_ps_clk;
  inout FIXED_IO_ps_porb;
  inout FIXED_IO_ps_srstb;

  wire DC;
  wire [14:0]DDR_addr;
  wire [2:0]DDR_ba;
  wire DDR_cas_n;
  wire DDR_ck_n;
  wire DDR_ck_p;
  wire DDR_cke;
  wire DDR_cs_n;
  wire [3:0]DDR_dm;
  wire [31:0]DDR_dq;
  wire [3:0]DDR_dqs_n;
  wire [3:0]DDR_dqs_p;
  wire DDR_odt;
  wire DDR_ras_n;
  wire DDR_reset_n;
  wire DDR_we_n;
  wire FCLK_CLK1;
  wire FIXED_IO_ddr_vrn;
  wire FIXED_IO_ddr_vrp;
  wire [53:0]FIXED_IO_mio;
  wire FIXED_IO_ps_clk;
  wire FIXED_IO_ps_porb;
  wire FIXED_IO_ps_srstb;
  
  wire [0:0]peripheral_aresetn;
  
  wire  m_axis_aclk;
  wire  s_axis_aclk;
  
  wire  [31:0]M_AXIS_tdata;
  wire  [3:0]M_AXIS_tkeep;
  wire  M_AXIS_tlast;
  wire  M_AXIS_tready;
  wire  M_AXIS_tvalid;

  assign M_AXIS_tready = 1'b1;
  
  reg   [31:0]S_AXIS_tdata;
  wire  [3:0]S_AXIS_tkeep;
  reg   S_AXIS_tlast;
  wire  S_AXIS_tready;
  reg   S_AXIS_tvalid;
  reg   [1:0]state;

assign s_axis_aclk = FCLK_CLK1;
assign m_axis_aclk = FCLK_CLK1;
wire m_axis_aresetn;
wire s_axis_aresetn;
assign m_axis_aresetn = peripheral_aresetn;
assign s_axis_aresetn = peripheral_aresetn;
assign S_AXIS_tkeep = 4'b1111;

always@(posedge FCLK_CLK1)
 begin
     if(!peripheral_aresetn) begin
         S_AXIS_tvalid <= 1'b0;
         S_AXIS_tdata <= 32'd0;
         S_AXIS_tlast <= 1'b0;
         state <=0;
     end
     else begin
        case(state)
          0: begin
              if(S_AXIS_tready) begin
                 S_AXIS_tvalid <= 1'b1;
                 state <= 1;
              end
              else begin
                 S_AXIS_tvalid <= 1'b0;
                 state <= 0;
              end
            end
          1:begin
               if(S_AXIS_tready) begin
                   S_AXIS_tdata <= S_AXIS_tdata + 1'b1;
                   if(S_AXIS_tdata == 32'd1022) begin
                      S_AXIS_tlast <= 1'b1;
                      state <= 2;
                   end
                   else begin
                      S_AXIS_tlast <= 1'b0;
                      state <= 1;
                   end
               end
               else begin
                  S_AXIS_tdata <= S_AXIS_tdata;                   
                  state <= 1;
               end
            end       
          2:begin
               if(!S_AXIS_tready) begin
                  S_AXIS_tvalid <= 1'b1;
                  S_AXIS_tlast <= 1'b1;
                  S_AXIS_tdata <= S_AXIS_tdata;
                  state <= 2;
               end
               else begin
                  S_AXIS_tvalid <= 1'b0;
                  S_AXIS_tlast <= 1'b0;
                  S_AXIS_tdata <= 32'd0;
                  state <= 0;
               end
            end
         default: state <=0;
         endcase
     end              
 end
 
       
  AXI_DMA_PL_PS AXI_DMA_PL_PS_TEST
       (
        .DDR_addr(DDR_addr),
        .DDR_ba(DDR_ba),
        .DDR_cas_n(DDR_cas_n),
        .DDR_ck_n(DDR_ck_n),
        .DDR_ck_p(DDR_ck_p),
        .DDR_cke(DDR_cke),
        .DDR_cs_n(DDR_cs_n),
        .DDR_dm(DDR_dm),
        .DDR_dq(DDR_dq),
        .DDR_dqs_n(DDR_dqs_n),
        .DDR_dqs_p(DDR_dqs_p),
        .DDR_odt(DDR_odt),
        .DDR_ras_n(DDR_ras_n),
        .DDR_reset_n(DDR_reset_n),
        .DDR_we_n(DDR_we_n),
        .FCLK_CLK1(FCLK_CLK1),
        .FIXED_IO_ddr_vrn(FIXED_IO_ddr_vrn),
        .FIXED_IO_ddr_vrp(FIXED_IO_ddr_vrp),
        .FIXED_IO_mio(FIXED_IO_mio),
        .FIXED_IO_ps_clk(FIXED_IO_ps_clk),
        .FIXED_IO_ps_porb(FIXED_IO_ps_porb),
        .FIXED_IO_ps_srstb(FIXED_IO_ps_srstb),
        .M_AXIS_tdata(M_AXIS_tdata),
        .M_AXIS_tkeep(M_AXIS_tkeep),
        .M_AXIS_tlast(M_AXIS_tlast),
        .M_AXIS_tready(M_AXIS_tready),
        .M_AXIS_tvalid(M_AXIS_tvalid),
        .m_axis_aresetn(m_axis_aresetn),
        .m_axis_aclk(m_axis_aclk),
        
        .S_AXIS_tdata(S_AXIS_tdata),
        .S_AXIS_tkeep(S_AXIS_tkeep),
        .S_AXIS_tlast(S_AXIS_tlast),
        .S_AXIS_tready(S_AXIS_tready),
        .S_AXIS_tvalid(S_AXIS_tvalid),
        .s_axis_aresetn(s_axis_aresetn),
        .s_axis_aclk(s_axis_aclk),
        
        .peripheral_aresetn(peripheral_aresetn)
        );
endmodule

Generate Bitstream,Export Hardware(注意勾选include biestream),最后launch SDK进行测试。


SDK这边,程序跟上一篇AXI_DMA_LOOP程序差不多,无非就是加了定时器,用于发送和接收测速,而定时器的例程之前也写过,也就不在这多哔哔了。

main.c

#include "dma_intr.h"
#include "timer_intr.h"
#include "sys_intr.h"

static XScuGic Intc; //GIC
static  XAxiDma AxiDma;
static  XScuTimer Timer;//timer

volatile u32 RX_success;
volatile u32 TX_success;

volatile u32 RX_ready=1;
volatile u32 TX_ready=1;

#define TIMER_LOAD_VALUE    166666665 //0.5S

char string_display[17]="";

int Tries = NUMBER_OF_TRANSFERS;
int i;
int Index;
u32 *TxBufferPtr= (u32 *)TX_BUFFER_BASE;
u32 *RxBufferPtr=(u32 *)RX_BUFFER_BASE;
u8 Value=0;
float speed_tx;
float speed_rx;

int axi_dma_test()
{
	int Status;
	TxDone = 0;
	RxDone = 0;
	Error = 0;

	xil_printf("PKT_LEN=%d\r\n",MAX_PKT_LEN);

	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
	 */
	Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN*sizeof(u32));
	Timer_start(&Timer);
	while(1)
	//for(i = 0; i < Tries; i ++)
	{
		//RX DMA Transfer

		if(RX_ready)
		{
		   RX_ready=0;
		   Status = XAxiDma_SimpleTransfer(&AxiDma,(u32)RxBufferPtr,
					(u32)(MAX_PKT_LEN*sizeof(u32)), XAXIDMA_DEVICE_TO_DMA);

		   if (Status != XST_SUCCESS) {return XST_FAILURE;}
		}

		//TX DMA Transfer
		if(TX_ready)
		{
			TX_ready=0;
			Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBufferPtr,
					(u32)(MAX_PKT_LEN*sizeof(u32)), XAXIDMA_DMA_TO_DEVICE);

			if (Status != XST_SUCCESS) {return XST_FAILURE;}
		}

		if(RxDone)
		{
			RxDone=0;
			RX_ready=1;
			RX_success++;
		}

		if(TxDone)
		{
			TxDone=0;
			TX_ready=1;
			TX_success++;
		}
		if(usec==2)
		{
			usec=0;
			sprintf(string_display,"RX=%d",RX_success);
			xil_printf("%s\r\n",string_display);
			speed_rx = MAX_PKT_LEN*sizeof(u32)*RX_success/1024/1024;
			sprintf(string_display,"RX_sp=%.2fMB/S",speed_rx);
			xil_printf("%s\r\n",string_display);

			sprintf(string_display,"TX=%d",TX_success);
			xil_printf("%s\r\n",string_display);
			speed_tx = (MAX_PKT_LEN)*sizeof(u32)*TX_success/1024/1024;
			sprintf(string_display,"TX_sp=%.2fMB/S",speed_tx);
			xil_printf("%s\r\n",string_display);
			RX_success=0;
			TX_success=0;

		}

		if (Error) {
			xil_printf("Failed test transmit%s done, "
			"receive%s done\r\n", TxDone? "":" not",
							RxDone? "":" not");
			goto Done;
		}

	}

	/* Disable TX and RX Ring interrupts and return success */
	DMA_DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);
Done:
	xil_printf("--- Exiting Test --- \r\n");

	return XST_SUCCESS;

}

int init_intr_sys(void)
{
	DMA_Intr_Init(&AxiDma,0);//initial interrupt system
	Timer_init(&Timer,TIMER_LOAD_VALUE,0);
	Init_Intr_System(&Intc); // initial DMA interrupt system
	Setup_Intr_Exception(&Intc);
	DMA_Setup_Intr_System(&Intc,&AxiDma,TX_INTR_ID,RX_INTR_ID);//setup dma interrpt system
	Timer_Setup_Intr_System(&Intc,&Timer,TIMER_IRPT_INTR);
	DMA_Intr_Enable(&Intc,&AxiDma);

}

int main(void)
{
	init_intr_sys();
	axi_dma_test();
}

timer_intr.c

#include "timer_intr.h"

volatile int usec;


static void TimerIntrHandler(void *CallBackRef)
{

    XScuTimer *TimerInstancePtr = (XScuTimer *) CallBackRef;
    XScuTimer_ClearInterruptStatus(TimerInstancePtr);
    usec++;
}
void Timer_start(XScuTimer *TimerPtr)
{
	    XScuTimer_Start(TimerPtr);
}

void Timer_Setup_Intr_System(XScuGic *GicInstancePtr,XScuTimer *TimerInstancePtr, u16 TimerIntrId)
{
        XScuGic_Connect(GicInstancePtr, TimerIntrId,
                        (Xil_ExceptionHandler)TimerIntrHandler,//set up the timer interrupt
                        (void *)TimerInstancePtr);

        XScuGic_Enable(GicInstancePtr, TimerIntrId);//enable the interrupt for the Timer at GIC
        XScuTimer_EnableInterrupt(TimerInstancePtr);//enable interrupt on the timer
 }

int Timer_init(XScuTimer *TimerPtr,u32 Load_Value,u32 DeviceId)
{
     XScuTimer_Config *TMRConfigPtr;     //timer config
     //私有定时器初始化
     TMRConfigPtr = XScuTimer_LookupConfig(DeviceId);
     XScuTimer_CfgInitialize(TimerPtr, TMRConfigPtr,TMRConfigPtr->BaseAddr);
     //XScuTimer_SelfTest(&Timer);
     //加载计数周期,私有定时器的时钟为CPU的一半,为333MHZ,如果计数1S,加载值为1sx(333x1000x1000)(1/s)-1=0x13D92D3F
     XScuTimer_LoadTimer(TimerPtr, Load_Value);//F8F00600+0=reg=F8F00600
     //自动装载
     XScuTimer_EnableAutoReload(TimerPtr);//F8F00600+8=reg=F8F00608

     return 1;
}

timer_intr.h

#ifndef TIMER_INTR_H_
#define TIMER_INTR_H_

#include <stdio.h>
#include "xadcps.h"
#include "xil_types.h"
#include "xscugic.h"
#include "xil_exception.h"
#include "xscutimer.h"


extern volatile int usec;

//timer info
#define TIMER_DEVICE_ID     XPAR_XSCUTIMER_0_DEVICE_ID
#define TIMER_IRPT_INTR     XPAR_SCUTIMER_INTR

void Timer_start(XScuTimer *TimerPtr);
void Timer_Setup_Intr_System(XScuGic *GicInstancePtr,XScuTimer *TimerInstancePtr, u16 TimerIntrId);
int Timer_init(XScuTimer *TimerPtr,u32 Load_Value,u32 DeviceId);
#endif /* TIMER_INTR_H_ */

sys_intr.c 

#include "sys_intr.h"
void Setup_Intr_Exception(XScuGic * IntcInstancePtr)
{
	/* Enable interrupts from the hardware */
	Xil_ExceptionInit();
	Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
			(Xil_ExceptionHandler)XScuGic_InterruptHandler,
			(void *)IntcInstancePtr);

	Xil_ExceptionEnable();
}

int Init_Intr_System(XScuGic * IntcInstancePtr)
{
	int Status;

	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;
	}
	return XST_SUCCESS;
}

sys_intr.h

#ifndef SYS_INTR_H_
#define SYS_INTR_H_

#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"


#define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID

int Init_Intr_System(XScuGic * IntcInstancePtr);
void setup_Intr_Exception(XScuGic * IntcInstancePtr);

#endif /* SYS_INTR_H_ */

dma_intr.c

#include "dma_intr.h"

volatile int TxDone;
volatile int RxDone;
volatile int Error;
/*****************************************************************************/
/*
*
* This function checks data buffer after the DMA transfer is finished.
*
* We use the static tx/rx buffers.
*
* @param	Length is the length to check
* @param	StartValue is the starting value of the first byte
*
* @return
*		- XST_SUCCESS if validation is successful
*		- XST_FAILURE if validation is failure.
*
* @note		None.
*
******************************************************************************/
 int DMA_CheckData(int Length, u8 StartValue)
{
	u32 *RxPacket;
	int Index = 0;
	u8 Value;

	RxPacket = (u32 *) RX_BUFFER_BASE;
	Value = StartValue;

	/* Invalidate the DestBuffer before receiving the data, in case the
	 * Data Cache is enabled
	 * 如果启用了数据高速缓存,则在接收数据之前使DestBuffer无效
	 */
#ifndef __aarch64__
	Xil_DCacheInvalidateRange((u32)RxPacket, Length);
#endif

	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;
}
/*****************************************************************************/
/**
*
* This function disables the interrupts for DMA engine.
*
* @param	IntcInstancePtr is the pointer to the INTC component instance
* @param	TxIntrId is interrupt ID associated w/ DMA TX channel
* @param	RxIntrId is interrupt ID associated w/ DMA RX channel
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
 void DMA_DisableIntrSystem(XScuGic * IntcInstancePtr,
					u16 TxIntrId, u16 RxIntrId)
{
#ifdef XPAR_INTC_0_DEVICE_ID
	/* Disconnect the interrupts for the DMA TX and RX channels */
	XIntc_Disconnect(IntcInstancePtr, TxIntrId);
	XIntc_Disconnect(IntcInstancePtr, RxIntrId);
#else
	XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
	XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
#endif
}
/*****************************************************************************/
/*
*
* This is the DMA TX Interrupt handler function.
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then sets the TxDone.flag
*
* @param	Callback is a pointer to TX channel of the DMA engine.回调是指向DMA引擎的TX通道的指针。
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void DMA_TxIntrHandler(void *Callback)
{

	u32 IrqStatus;
	int TimeOut;
	XAxiDma *AxiDmaInst = (XAxiDma *)Callback;

	/* Read pending interrupts */
	IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);

	/* Acknowledge pending interrupts */

	XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);

	/*
	 * If no interrupt is asserted, we do not do anything
	 */
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {

		return;
	}

	/*
	 * If error interrupt is asserted, raise error flag, reset the
	 * hardware to recover from the error, and return with no further
	 * processing.
	 */
	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {

		Error = 1;

		/*
		 * Reset should never fail for transmit channel
		 */
		XAxiDma_Reset(AxiDmaInst);

		TimeOut = RESET_TIMEOUT_COUNTER;

		while (TimeOut) {
			if (XAxiDma_ResetIsDone(AxiDmaInst)) {
				break;
			}

			TimeOut -= 1;
		}

		return;
	}

	/*
	 * If Completion interrupt is asserted, then set the TxDone flag
	 */
	if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {

		TxDone = 1;
	}
}

/*****************************************************************************/
/*
*
* This is the DMA RX interrupt handler function
*
* It gets the interrupt status from the hardware, acknowledges it, and if any
* error happens, it resets the hardware. Otherwise, if a completion interrupt
* is present, then it sets the RxDone flag.
*
* @param	Callback is a pointer to RX channel of the DMA engine.
*
* @return	None.
*
* @note		None.
*
******************************************************************************/
static void DMA_RxIntrHandler(void *Callback)
{
	u32 IrqStatus;
	int TimeOut;
	XAxiDma *AxiDmaInst = (XAxiDma *)Callback;

	/* Read pending interrupts */
	IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);

	/* Acknowledge pending interrupts */
	XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);

	/*
	 * If no interrupt is asserted, we do not do anything
	 */
	if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
		return;
	}

	/*
	 * If error interrupt is asserted, raise error flag, reset the
	 * hardware to recover from the error, and return with no further
	 * processing.
	 */
	if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {

		Error = 1;

		/* Reset could fail and hang
		 * NEED a way to handle this or do not call it??
		 */
		XAxiDma_Reset(AxiDmaInst);

		TimeOut = RESET_TIMEOUT_COUNTER;

		while (TimeOut) {
			if(XAxiDma_ResetIsDone(AxiDmaInst)) {
				break;
			}

			TimeOut -= 1;
		}

		return;
	}

	/*
	 * If completion interrupt is asserted, then set RxDone flag
	 */
	if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {

		RxDone = 1;
	}
}

/*****************************************************************************/
/*
*
* This function setups the interrupt system so interrupts can occur for the
* DMA, it assumes INTC component exists in the hardware system.
*
* @param	IntcInstancePtr is a pointer to the instance of the INTC.
* @param	AxiDmaPtr is a pointer to the instance of the DMA engine
* @param	TxIntrId is the TX channel Interrupt ID.
* @param	RxIntrId is the RX channel Interrupt ID.
*
* @return
*		- XST_SUCCESS if successful,
*		- XST_FAILURE.if not succesful
*
* @note		None.
*
******************************************************************************/
int DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{
	int Status;
	XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3);

	XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 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, TxIntrId,
				(Xil_InterruptHandler)DMA_TxIntrHandler,
				AxiDmaPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
				(Xil_InterruptHandler)DMA_RxIntrHandler,
				AxiDmaPtr);
	if (Status != XST_SUCCESS) {
		return Status;
	}

	XScuGic_Enable(IntcInstancePtr, TxIntrId);
	XScuGic_Enable(IntcInstancePtr, RxIntrId);
	return XST_SUCCESS;
}



int DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr)
{

	/* Disable all interrupts before setup */

	XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
						XAXIDMA_DMA_TO_DEVICE);

	XAxiDma_IntrDisable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
				XAXIDMA_DEVICE_TO_DMA);

	/* Enable all interrupts */
	XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
							XAXIDMA_DMA_TO_DEVICE);

	XAxiDma_IntrEnable(DMAPtr, XAXIDMA_IRQ_ALL_MASK,
							XAXIDMA_DEVICE_TO_DMA);
	return XST_SUCCESS;

}


int DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId)
{
	int Status;
	XAxiDma_Config *Config=NULL;

	Config = XAxiDma_LookupConfig(DeviceId);
	if (!Config) {
		xil_printf("No config found for %d\r\n", DeviceId);
		return XST_FAILURE;
	}

	/* Initialize DMA engine */
	Status = XAxiDma_CfgInitialize(DMAPtr, Config);

	if (Status != XST_SUCCESS) {
		xil_printf("Initialization failed %d\r\n", Status);
		return XST_FAILURE;
	}

	if(XAxiDma_HasSg(DMAPtr)){
		xil_printf("Device configured as SG mode \r\n");
		return XST_FAILURE;
	}
	return XST_SUCCESS;

}

dma_intr.h

#ifndef DMA_INTR_H
#define DMA_INTR_H
#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xscugic.h"

/************************** Constant Definitions *****************************/
/*
 * Device hardware build related constants.
 */
#define DMA_DEV_ID		XPAR_AXIDMA_0_DEVICE_ID

#define MEM_BASE_ADDR		0x10000000


#define RX_INTR_ID		XPAR_FABRIC_AXI_DMA_0_S2MM_INTROUT_INTR
#define TX_INTR_ID		XPAR_FABRIC_AXI_DMA_0_MM2S_INTROUT_INTR


#define TX_BUFFER_BASE		(MEM_BASE_ADDR + 0x00100000)
#define RX_BUFFER_BASE		(MEM_BASE_ADDR + 0x00300000)
#define RX_BUFFER_HIGH		(MEM_BASE_ADDR + 0x004FFFFF)


/* Timeout loop counter for reset
 */
#define RESET_TIMEOUT_COUNTER	10000
/* test start value
 */
#define TEST_START_VALUE	0xC
/*
 * Buffer and Buffer Descriptor related constant definition
 */
#define MAX_PKT_LEN		1024//4MB
/*
 * transfer times
 */
#define NUMBER_OF_TRANSFERS	100000

extern volatile int TxDone;
extern volatile int RxDone;
extern volatile int Error;

int  DMA_CheckData(int Length, u8 StartValue);
int  DMA_Setup_Intr_System(XScuGic * IntcInstancePtr,XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
int  DMA_Intr_Enable(XScuGic * IntcInstancePtr,XAxiDma *DMAPtr);
int  DMA_Intr_Init(XAxiDma *DMAPtr,u32 DeviceId);
#endif

AXI4_Stream DATA FIFO 0,从PL-PS数据发送抓取波形如下。

AXI4_Stream DATA FIFO 1,从PS-PL数据接收抓取波形如下。

最后测试结果。


SDK方面,由于代码段给上篇AXI_DMA_LOOP差不多,所以要注意的点还是那些:

1.所有涉及MAX_PKT_LEN的地方,都要*sizeof(u32) ;

2.所有涉及TxBufferPtr、RxBufferPtr、TX_BUFFER_BASE、RX_BUFFER_BASE指针前面也要变成u32;

3.传输前一定要记得Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN*sizeof(u32));

4.接收后一定要记得Xil_DCacheFlushRange((u32)RxBufferPtr, MAX_PKT_LEN*sizeof(u32));

5.XAxiDma_SimpleTransfer(&AxiDma,(u32)RxBufferPtr,(u32)(MAX_PKT_LEN*sizeof(u32)), XAXIDMA_DEVICE_TO_DMA);用于接收。

6.XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBufferPtr,(u32)(MAX_PKT_LEN*sizeof(u32)), XAXIDMA_DMA_TO_DEVICE);用于发送。

7.可通过sprintf(string_display,"RX=%d",TX_success);.将int或者float数,转成字符数组;

8.可通过xil_printf("%s\r\n",string_display);将字符数组用串口送出。

  • 1
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值