AXI DMA+AXI-S FIFO回环学习

1 DMA 简介

DMA 是现代计算机的特色之一,是硬件实现存储器与存储器、存储器与 I/O 设备之间直接进行高速数据传输的内存技术,它允许不同速率的设备进行沟通,而不需要依靠 CPU 的中断负载。
如果不使用 DMA,那么 CPU 需要从数据源把每一个片段的数据复制到寄存器中,这个过程会一直占用 CPU 的资源。当使用 DMA 时,CPU 向 DMA 发送一个存储传输请求,当 DMA 控制器收到请求时就会将数据从源地址搬运到目的地址,搬运过程中不消化 CPU 的资源,当传输完成后 DMA 控制器以中断的方式通知 CPU。
为了发起传输事务,DMA 控制器必须有:

  1. 源地址
  2. 目的地址
  3. 传输长度
    DMA 存储传输的过程如下:
  4. 处理器向 DMA 控制器发送一条 DMA 命令
  5. DMA 控制器把数据从外设传输到存储器或从存储器搬运到存储器,而让 CPU 腾出手来做其它操作
  6. 数据传输完成后,DMA 控制器向 CPU 发出一个中断,来通知处理器 DMA 传输完成

ZYNQ 提供两种 DMA,一种是集成在 PS 中的硬核 DMA,一种是 PL 中的软核 AXI DMA IP。
各种接口方式的比较如下:
|500
PL 的 DMA 和 AXI_HP 接口的传输适用于大量数据的高性能传输,带宽高,传输方式的拓扑图如下:
|500

1.1 AXI DMA IP

AXI Direct Memory Access(AXI DMA)IP 核在 AXI 4 内存映射和 AXI 4-Stream IP 接口之间提供高带宽直接储存访问。

|500
AXI DMA 用到了三种总线。AXI 4-Lite 用于对寄存器进行配置,AXI 4 Memory Map 总线用于读写 DDR 中的数据,AXI 4 Stream 总线用于 AXI DMA 对外设数据的读写,其中 AXI 4 Stream Master(MM 2 S,Memory Map to Stream)接口用于向 PL写入数据,AXI 4-Stream Slave (S 2 MM,Stream to Memory Map) 接口用于从 PL读取数据。
AXI DMA 提供 3 种模式,分别是 Direct Register 模式、Scatter/Gather 模式和 Cyclic DMA(循环 DMA)模式,常用的是 Direct Register 模式。
Direct Register DMA 模式即 Simple DMA 模式。Direct Register 模式提供了一种配置,用于在 MM 2 S 和 S 2 MM 通道上执行简单的 DMA 传输。Simple DMA(简单 DMA)允许应用程序在 DMA 和 Device 之间定义单个事务。它有两个通道:一个从 DMA 到 Device,另一个从 Device 到 DMA。这里有个地方需要大家注意下,在编写 Simple DMA(简单 DMA)代码时必须设置缓冲区地址和长度字段以启动相应通道中的传输。(其中 PL 对应 Device)

1.1.1 Vivado 中的 IP 配置

Enable Scatter Gather Engine
选中此选项可启用 Scatter Gather 模式操作,并在 AXI DMA 中包含 Scatter Gather Engine。取消选中此选项可启用 Direct Register 模式操作,但不包括 AXI DMA 中的 Scatter Gather Engine。禁用 Scatter Gather Engine 会使 Scatter/Gather Engine 的所有输出端口都绑定为零,并且所有输入端口都将保持打开状态。此处我们取消勾选 Enable Scatter Gather Engine
Enable Micro DMA
使能后会生成高度优化的 DMA,资源消耗较少,用于极少量数据的传输
Width of Buffer Length Register
该选项配置了 AXI DMA 单次最大能搬运多少个字节,字节数
Address Width (32 - 64)
指定地址空间的宽度,可以是 32 到 64 之间的任意值
Enable Read Channel
开启 AXI DMA 的读通道 MM 2 S,相关配置如下:

  • Number of Channels:指定通道数。保持默认值 1
  • Memory Map Data Width:AXI MM 2 S 存储映射读取数据总线的数据位宽。有效值为 32、64、128、256、512 和 1024。此处保持默认值 32
  • Stream Data Width:AXI MM 2 S AXI 4-Stream 数据总线的数据位宽。该值必须小于或等于 Memory Map Data Width。有效值为 8、16、32、64、128、512 和 1024。此处保持默认值 32
  • Max Burst Size:突发分区粒度设置。此设置指定 MM 2 S 的 AXI 4-Memory Map 侧的突发周期的最大值。有效值为 2、4、8、16、32、64、128 和 256
  • Allow Unaligned Transfers:启用或禁用 MM 2 S 数据重新排列引擎(Data Realignment Engine,DRE)。选中时,DRE 被使能并允许在 MM 2 S 存储映射数据路径上数据重新对齐到 8 位的字节水平。对于 MM 2 S通道,则从内存中读取数据。如果 DRE 被使能,则数据读取可以从任何缓冲区地址字节偏移开始,并且读取数据被对齐,使得第一个字节读取是 AXI 4-Stream 上的第一个有效字节输出
    Enable Write Channel
    开启 AXI DMA 的写通道 S 2 MM,相关配置同上

2 Vitis 工程解析

2.1 头文件引用和宏定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/***************************** Include Files *********************************/

#include "xaxidma.h"
#include "xparameters.h"
#include "xil_exception.h"
#include "xdebug.h"
#include "xil_util.h"

#ifdef XPAR_UARTNS550_0_BASEADDR
#include "xuartns550_l.h" /* to use uartns550 */
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
#include "xintc.h"
#else
#include "xscugic.h"
#endif

/************************** Constant Definitions *****************************/

/*
* Device hardware build related constants.
*/

#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID

#ifdef XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
#elif defined(XPAR_MIG7SERIES_0_BASEADDR)
#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR
#elif defined(XPAR_MIG_0_C0_DDR4_MEMORY_MAP_BASEADDR)
#define DDR_BASE_ADDR XPAR_MIG_0_C0_DDR4_MEMORY_MAP_BASEADDR
#elif defined(XPAR_PSU_DDR_0_S_AXI_BASEADDR)
#define DDR_BASE_ADDR XPAR_PSU_DDR_0_S_AXI_BASEADDR
#endif

#define DDR_BASE_ADDR XPAR_PS7_DDR_0_S_AXI_BASEADDR // 0x00100000

#ifndef DDR_BASE_ADDR
#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \
DEFAULT SET TO 0x01000000
#define MEM_BASE_ADDR 0x01000000
#else
#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x01000000) // 0x01100000
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
#define RX_INTR_ID XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define TX_INTR_ID XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID
#else
#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
#define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID
#endif

#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) // 0x01200000
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) // 0x01400000
#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) // 0x015FFFFF

#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID
#else
#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
#endif

#ifdef XPAR_INTC_0_DEVICE_ID
#define INTC XIntc
#define INTC_HANDLER XIntc_InterruptHandler
#else
#define INTC XScuGic
#define INTC_HANDLER XScuGic_InterruptHandler
#endif

/* Timeout loop counter for reset
*/
#define RESET_TIMEOUT_COUNTER 10000

#define TEST_START_VALUE 0x1
/*
* Buffer and Buffer Descriptor related constant definition
*/
#define MAX_PKT_LEN 0x200

#define NUMBER_OF_TRANSFERS 10
#define POLL_TIMEOUT_COUNTER 1000000U
#define NUMBER_OF_EVENTS 1

#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR 重新定义了 DDR 3 的基址.。数据读写的基址为 #define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x01000000) // 0x01100000 AXI DMA 读取数据的起始地址为 #define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) // 0x01200000,写入地址为 0x01400000

2.2 定义函数和声明相关的 instance 和 flag 变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**************************** Type Definitions *******************************/

/***************** Macros (Inline Functions) Definitions *********************/

/************************** Function Prototypes ******************************/
#ifndef DEBUG
extern void xil_printf(const char *format, ...);
#endif

#ifdef XPAR_UARTNS550_0_BASEADDR
static void Uart550_Setup(void);
#endif

static int CheckData(int Length, u8 StartValue);
static void TxIntrHandler(void *Callback);
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);

/************************** Variable Definitions *****************************/
/*
* Device instance definitions
*/

static XAxiDma AxiDma; /* Instance of the XAxiDma */

static INTC Intc; /* Instance of the Interrupt Controller */

/*
* Flags interrupt handlers use to notify the application context the events.
*/
volatile u32 TxDone;
volatile u32 RxDone;
volatile u32 Error;

2.3 Main 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*****************************************************************************/
/**
*
* Main function
*
* This function is the main entry of the interrupt test. It does the following:
* Set up the output terminal if UART16550 is in the hardware build
* Initialize the DMA engine
* Set up Tx and Rx channels
* Set up the interrupt system for the Tx and Rx interrupts
* Submit a transfer
* Wait for the transfer to finish
* Check transfer status
* Disable Tx and Rx interrupts
* Print test status and exit
*
* @param None
*
* @return
* - XST_SUCCESS if example finishes successfully
* - XST_FAILURE if example fails.
*
* @note None.
*
******************************************************************************/
int main(void)
{
int Status;
XAxiDma_Config *Config;
int Tries = NUMBER_OF_TRANSFERS;
int Index;
u8 *TxBufferPtr;
u8 *RxBufferPtr;
u8 Value;

TxBufferPtr = (u8 *)TX_BUFFER_BASE;
RxBufferPtr = (u8 *)RX_BUFFER_BASE;
/* Initial setup for Uart16550 */
#ifdef XPAR_UARTNS550_0_BASEADDR

Uart550_Setup();

#endif

xil_printf("\r\n--- Entering main() --- \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;
}
else
{
xil_printf("Config found for %d\r\n", DMA_DEV_ID);
}

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

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

if (XAxiDma_HasSg(&AxiDma))
{
xil_printf("Device configured as SG mode \r\n");
return XST_FAILURE;
}
else
{
xil_printf("Device configured as simple mode \r\n");
}

/* Set up Interrupt system */
Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID);
if (Status != XST_SUCCESS)
{

xil_printf("Failed intr setup\r\n");
return XST_FAILURE;
}

/* Disable all interrupts before setup */

XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DMA_TO_DEVICE);

XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);

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

XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
XAXIDMA_DEVICE_TO_DMA);

/* Initialize flags before start transfer test */
TxDone = 0;
RxDone = 0;
Error = 0;

Value = TEST_START_VALUE;

for (Index = 0; Index < MAX_PKT_LEN; Index++)
{
TxBufferPtr[Index] = Value;

Value = (Value + 1) & 0xFF;
}

/* Flush the buffers before the DMA transfer, in case the Data Cache
* is enabled
*/
Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN);
/* Send a packet */
for (int i = 0; i < Tries; i++)
{

Status = XAxiDma_SimpleTransfer(&AxiDma, (UINTPTR)RxBufferPtr,
MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);

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

Status = XAxiDma_SimpleTransfer(&AxiDma, (UINTPTR)TxBufferPtr,
MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);

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

Status = Xil_WaitForEventSet(POLL_TIMEOUT_COUNTER, NUMBER_OF_EVENTS, &Error);
if (Status == XST_SUCCESS)
{
if (!TxDone)
{
xil_printf("Transmit error %d\r\n", Status);
goto Done;
}
else if (Status == XST_SUCCESS && !RxDone)
{
xil_printf("Receive error %d\r\n", Status);
goto Done;
}
}

/*
* Wait for TX done or timeout
*/
Status = Xil_WaitForEventSet(POLL_TIMEOUT_COUNTER, NUMBER_OF_EVENTS, &TxDone);
if (Status != XST_SUCCESS)
{
xil_printf("Transmit failed %d\r\n", Status);
goto Done;
}

/*
* Wait for RX done or timeout
*/
Status = Xil_WaitForEventSet(POLL_TIMEOUT_COUNTER, NUMBER_OF_EVENTS, &RxDone);
if (Status != XST_SUCCESS)
{
xil_printf("Receive failed %d\r\n", Status);
goto Done;
}

/*
* Test finished, check data
*/
Status = CheckData(MAX_PKT_LEN, 0x1);
if (Status != XST_SUCCESS)
{
xil_printf("Data check failed\r\n");
goto Done;
}
xil_printf("Transfer %d done\r\n", i + 1);
}
xil_printf("Successfully ran AXI DMA interrupt Example\r\n");

/* Disable TX and RX Ring interrupts and return success */

DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);

Done:
xil_printf("--- Exiting main() --- \r\n");

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

return XST_SUCCESS;
}

Tries 为测试回环的次数

2.4 函数的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
*****************************************************************************/
/*
*
* 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.
*
******************************************************************************/
static int CheckData(int Length, u8 StartValue)
{
u8 *RxPacket;
int Index = 0;
u8 Value;

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

/* Invalidate the DestBuffer before receiving the data, in case the
* Data Cache is enabled
*/
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;
}

/*****************************************************************************/
/*
*
* 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.
*
* @return None.
*
* @note None.
*
******************************************************************************/
static void 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 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 successful
*
* @note None.
*
******************************************************************************/
static int SetupIntrSystem(INTC *IntcInstancePtr,
XAxiDma *AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
{
int Status;

#ifdef XPAR_INTC_0_DEVICE_ID

/* Initialize the interrupt controller and connect the ISRs */
Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
if (Status != XST_SUCCESS)
{

xil_printf("Failed init intc\r\n");
return XST_FAILURE;
}

Status = XIntc_Connect(IntcInstancePtr, TxIntrId,
(XInterruptHandler)TxIntrHandler, AxiDmaPtr);
if (Status != XST_SUCCESS)
{

xil_printf("Failed tx connect intc\r\n");
return XST_FAILURE;
}

Status = XIntc_Connect(IntcInstancePtr, RxIntrId,
(XInterruptHandler)RxIntrHandler, AxiDmaPtr);
if (Status != XST_SUCCESS)
{

xil_printf("Failed rx connect intc\r\n");
return XST_FAILURE;
}

/* Start the interrupt controller */
Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
if (Status != XST_SUCCESS)
{

xil_printf("Failed to start intc\r\n");
return XST_FAILURE;
}

XIntc_Enable(IntcInstancePtr, TxIntrId);
XIntc_Enable(IntcInstancePtr, RxIntrId);

#else

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;
}
//设置中断优先级和触发类型
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)TxIntrHandler,
AxiDmaPtr);
if (Status != XST_SUCCESS)
{
return Status;
}

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

XScuGic_Enable(IntcInstancePtr, TxIntrId);
XScuGic_Enable(IntcInstancePtr, RxIntrId);

#endif

/* Enable interrupts from the hardware */

Xil_ExceptionInit();
Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
(Xil_ExceptionHandler)INTC_HANDLER,
(void *)IntcInstancePtr);

Xil_ExceptionEnable();

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.
*
******************************************************************************/
static void DisableIntrSystem(INTC *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
}


AXI DMA+AXI-S FIFO回环学习
https://www.moerjielovecookie.icu/2025/01/25/ZYNQ-AXI DMA+AXI-S FIFO回环学习/
作者
Sawen Moerjie
发布于
2025年1月25日
许可协议