软件环境: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);将字符数组用串口送出。