以ZYNQ SOC快速打开算法验证通路(4)——AXI DMA使用解析及环路测试

一、AXI DMA介绍

  上篇该系列博文中描述W5500接到上位机传输的多寡,此后要将数据缓存起来。当数据量较充分或其他数带动富比高之景象下,片上缓存(OCM)已无力回天满足急需,这时急需将大量数保存在外挂的DDR
SDRAM中。

  本篇博文讲述AXI
DMA的组成部分应用总结,硬件IP子系统搭建和SDK
C代码封装参考米联客ZYNQ教程。若想被ZYNQ的PS与PL两有高速数据传输,需要运用PS的HP(高性能)接口通过AXI_DMA完成多少搬移,这正顺应PG021
AXI DMA v7.1 LogiCORE IP Product Guide中介绍的AXI DMA的行使场景:The AXI
DMA provides high-speed data movement between system memory and an
AXI4-Stream-based target IP such as AXI Ethernet.

  最简便易行的措施是应用Xilinx的读写地址库函数Xil_In32()和Xil_Out32(),当然不仅仅支持32bit各富有,还连8
16同64bit。但这种方式每次读写都使占用CPU,无法在读写的而接收连续数据还是对前的多寡更是处理,也就算无法形成类似FPGA逻辑设计受到的“流水线结构”,此时前段数缓存过程遭到,后段数据会让废弃。所以,需要运用PS端CPU子系统外之专用硬件DMA完成快速的批量多少搬移工作。

  如图,AXI DMA主要不外乎Memory Map和
Stream两部分接口,前者连接PS子系统,后者则总是带有流接口的PL
IP核。

图片 1

图片 2

  以Xilinx
SDK的system.mss页面下直导入ps_dma示例工程。

  其极简易的从一直寄存器模式(Simple
DMA),这里需要留意地址指向伙同的题目:当没使能地址重对合之气象下,如果AXI
Memory
Map数据位宽是32bit,则搬移数据所在地方必须于0x0,0x4,0x8相当于苗头地址上。接下来关注DMA
IP核配置界面主要参数:

图片 3图片 4

图片 5

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include "sleep.h"
  4 #include "xparameters.h"
  5 #include "xil_types.h"
  6 #include "xil_assert.h"
  7 #include "xil_io.h"
  8 #include "xil_exception.h"
  9 #include "xil_cache.h"
 10 #include "xil_printf.h"
 11 #include "xscugic.h"
 12 #include "xdmaps.h"
 13 
 14 /************************** Constant Definitions *****************************/
 15 /*
 16  * The following constants map to the XPAR parameters created in the
 17  * xparameters.h file. They are defined here such that a user can easily
 18  * change all the needed parameters in one place.
 19  */
 20 #define DMA_DEVICE_ID             XPAR_XDMAPS_1_DEVICE_ID
 21 #define INTC_DEVICE_ID            XPAR_SCUGIC_SINGLE_DEVICE_ID
 22 
 23 #define DMA_DONE_INTR_0            XPAR_XDMAPS_0_DONE_INTR_0
 24 #define DMA_DONE_INTR_1            XPAR_XDMAPS_0_DONE_INTR_1
 25 #define DMA_DONE_INTR_2            XPAR_XDMAPS_0_DONE_INTR_2
 26 #define DMA_DONE_INTR_3            XPAR_XDMAPS_0_DONE_INTR_3
 27 #define DMA_DONE_INTR_4            XPAR_XDMAPS_0_DONE_INTR_4
 28 #define DMA_DONE_INTR_5            XPAR_XDMAPS_0_DONE_INTR_5
 29 #define DMA_DONE_INTR_6            XPAR_XDMAPS_0_DONE_INTR_6
 30 #define DMA_DONE_INTR_7            XPAR_XDMAPS_0_DONE_INTR_7
 31 #define DMA_FAULT_INTR            XPAR_XDMAPS_0_FAULT_INTR
 32 
 33 
 34 
 35 #define TEST_ROUNDS    1    /* Number of loops that the Dma transfers run.*/
 36 #define DMA_LENGTH    1024    /* Length of the Dma Transfers */
 37 #define TIMEOUT_LIMIT     0x2000    /* Loop count for timeout */
 38 
 39 /**************************** Type Definitions *******************************/
 40 
 41 
 42 /***************** Macros (Inline Functions) Definitions *********************/
 43 
 44 
 45 /************************** Function Prototypes ******************************/
 46 
 47 int XDmaPs_Example_W_Intr(XScuGic *GicPtr, u16 DeviceId);
 48 int SetupInterruptSystem(XScuGic *GicPtr, XDmaPs *DmaPtr);
 49 void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd,
 50             void *CallbackRef);
 51 
 52 /************************** Macro Definitions *****************************/
 53 
 54 
 55 /************************** Variable Definitions *****************************/
 56 #ifdef __ICCARM__
 57 #pragma data_alignment=32
 58 static int Src[DMA_LENGTH];
 59 static int Dst[DMA_LENGTH];
 60 #pragma data_alignment=4
 61 #else
 62 static int Src[DMA_LENGTH] __attribute__ ((aligned (32)));
 63 static int Dst[DMA_LENGTH] __attribute__ ((aligned (32)));
 64 #endif
 65 
 66 XDmaPs DmaInstance;
 67 #ifndef TESTAPP_GEN
 68 XScuGic GicInstance;
 69 #endif
 70 
 71 /****************************************************************************/
 72 /**
 73 *
 74 * This is the main function for the DmaPs interrupt example.
 75 *
 76 * @param    None.
 77 *
 78 * @return    XST_SUCCESS to indicate success, otherwise XST_FAILURE.
 79 *
 80 * @note        None.
 81 *
 82 ****************************************************************************/
 83 #ifndef TESTAPP_GEN
 84 int main(void)
 85 {
 86     int Status;
 87 
 88     Status = XDmaPs_Example_W_Intr(&GicInstance,DMA_DEVICE_ID);
 89     if (Status != XST_SUCCESS) {
 90         xil_printf("Error: XDMaPs_Example_W_Intr failed\r\n");
 91         return XST_FAILURE;
 92     }
 93 
 94     xil_printf("XDMaPs_Example_W_Intr passed\r\n");
 95     return XST_SUCCESS;
 96 
 97 }
 98 #endif
 99 
100 
101 /*****************************************************************************/
102 /**
103  *
104  * Interrupt Example to test the DMA.
105  *
106  * @param    DeviceId is the Device ID of the DMA controller.
107  *
108  * @return    XST_SUCCESS to indicate success, otherwise XST_FAILURE.
109  *
110  * @note    None.
111  *
112  ****************************************************************************/
113 int XDmaPs_Example_W_Intr(XScuGic *GicPtr, u16 DeviceId)
114 {
115     int Index;
116     unsigned int Channel = 0;
117     int Status;
118     int TestStatus;
119     int TestRound;
120     int TimeOutCnt;
121     volatile int Checked[XDMAPS_CHANNELS_PER_DEV];
122     XDmaPs_Config *DmaCfg;
123     XDmaPs *DmaInst = &DmaInstance;
124     XDmaPs_Cmd DmaCmd;
125 
126     memset(&DmaCmd, 0, sizeof(XDmaPs_Cmd));
127 
128     DmaCmd.ChanCtrl.SrcBurstSize = 4;
129     DmaCmd.ChanCtrl.SrcBurstLen = 4;
130     DmaCmd.ChanCtrl.SrcInc = 1;
131     DmaCmd.ChanCtrl.DstBurstSize = 4;
132     DmaCmd.ChanCtrl.DstBurstLen = 4;
133     DmaCmd.ChanCtrl.DstInc = 1;
134     DmaCmd.BD.SrcAddr = (u32) Src;
135     DmaCmd.BD.DstAddr = (u32) Dst;
136     DmaCmd.BD.Length = DMA_LENGTH * sizeof(int);
137 
138 
139     /*
140      * Initialize the DMA Driver
141      */
142     DmaCfg = XDmaPs_LookupConfig(DeviceId);
143     if (DmaCfg == NULL) {
144         return XST_FAILURE;
145     }
146 
147     Status = XDmaPs_CfgInitialize(DmaInst,
148                    DmaCfg,
149                    DmaCfg->BaseAddress);
150     if (Status != XST_SUCCESS) {
151         return XST_FAILURE;
152     }
153 
154 
155     /*
156      * Setup the interrupt system.
157      */
158     Status = SetupInterruptSystem(GicPtr, DmaInst);
159     if (Status != XST_SUCCESS) {
160         return XST_FAILURE;
161     }
162 
163 
164     TestStatus = XST_SUCCESS;
165 
166     for (TestRound = 0; TestRound < TEST_ROUNDS; TestRound++) {
167         xil_printf("Test round %d\r\n", TestRound);
168         for (Channel = 0;
169              Channel < XDMAPS_CHANNELS_PER_DEV;
170              Channel++) {
171 
172 
173             /* Initialize source */
174             for (Index = 0; Index < DMA_LENGTH; Index++)
175                 Src[Index] = DMA_LENGTH - Index;
176 
177             /* Clear destination */
178             for (Index = 0; Index < DMA_LENGTH; Index++)
179                 Dst[Index] = 0;
180 
181             Checked[Channel] = 0;
182 
183             /* Set the Done interrupt handler */
184             XDmaPs_SetDoneHandler(DmaInst,
185                            Channel,
186                            DmaDoneHandler,
187                            (void *)Checked);
188 
189 
190             Status = XDmaPs_Start(DmaInst, Channel, &DmaCmd, 0);
191             if (Status != XST_SUCCESS) {
192                 return XST_FAILURE;
193             }
194 
195             TimeOutCnt = 0;
196 
197             /* Now the DMA is done */
198             while (!Checked[Channel]
199                    && TimeOutCnt < TIMEOUT_LIMIT) {
200                 TimeOutCnt++;
201             }
202 
203             if (TimeOutCnt >= TIMEOUT_LIMIT) {
204                 TestStatus = XST_FAILURE;
205             }
206 
207             if (Checked[Channel] < 0) {
208                 /* DMA controller failed */
209                 TestStatus = XST_FAILURE;
210             }
211         }
212     }
213 
214     return TestStatus;
215 
216 }
217 
218 
219 /******************************************************************************/
220 /**
221  *
222  * This function connects the interrupt handler of the interrupt controller to
223  * the processor.  This function is seperate to allow it to be customized for
224  * each application. Each processor or RTOS may require unique processing to
225  * connect the interrupt handler.
226  *
227  * @param    GicPtr is the GIC instance pointer.
228  * @param    DmaPtr is the DMA instance pointer.
229  *
230  * @return    None.
231  *
232  * @note    None.
233  *
234  ****************************************************************************/
235 int SetupInterruptSystem(XScuGic *GicPtr, XDmaPs *DmaPtr)
236 {
237     int Status;
238 #ifndef TESTAPP_GEN    
239     XScuGic_Config *GicConfig;
240 
241 
242     Xil_ExceptionInit();
243 
244     /*
245      * Initialize the interrupt controller driver so that it is ready to
246      * use.
247      */
248     GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
249     if (NULL == GicConfig) {
250         return XST_FAILURE;
251     }
252 
253     Status = XScuGic_CfgInitialize(GicPtr, GicConfig,
254                        GicConfig->CpuBaseAddress);
255     if (Status != XST_SUCCESS) {
256         return XST_FAILURE;
257     }
258 
259     /*
260      * Connect the interrupt controller interrupt handler to the hardware
261      * interrupt handling logic in the processor.
262      */
263     Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
264                  (Xil_ExceptionHandler)XScuGic_InterruptHandler,
265                  GicPtr);
266 #endif
267     /*
268      * Connect the device driver handlers that will be called when an interrupt
269      * for the device occurs, the device driver handler performs the specific
270      * interrupt processing for the device
271      */
272 
273     /*
274      * Connect the Fault ISR
275      */
276     Status = XScuGic_Connect(GicPtr,
277                  DMA_FAULT_INTR,
278                  (Xil_InterruptHandler)XDmaPs_FaultISR,
279                  (void *)DmaPtr);
280     if (Status != XST_SUCCESS) {
281         return XST_FAILURE;
282     }
283 
284     /*
285      * Connect the Done ISR for all 8 channels of DMA 0
286      */
287     Status = XScuGic_Connect(GicPtr,
288                  DMA_DONE_INTR_0,
289                  (Xil_InterruptHandler)XDmaPs_DoneISR_0,
290                  (void *)DmaPtr);
291     Status |= XScuGic_Connect(GicPtr,
292                  DMA_DONE_INTR_1,
293                  (Xil_InterruptHandler)XDmaPs_DoneISR_1,
294                  (void *)DmaPtr);
295     Status |= XScuGic_Connect(GicPtr,
296                  DMA_DONE_INTR_2,
297                  (Xil_InterruptHandler)XDmaPs_DoneISR_2,
298                  (void *)DmaPtr);
299     Status |= XScuGic_Connect(GicPtr,
300                  DMA_DONE_INTR_3,
301                  (Xil_InterruptHandler)XDmaPs_DoneISR_3,
302                  (void *)DmaPtr);
303     Status |= XScuGic_Connect(GicPtr,
304                  DMA_DONE_INTR_4,
305                  (Xil_InterruptHandler)XDmaPs_DoneISR_4,
306                  (void *)DmaPtr);
307     Status |= XScuGic_Connect(GicPtr,
308                  DMA_DONE_INTR_5,
309                  (Xil_InterruptHandler)XDmaPs_DoneISR_5,
310                  (void *)DmaPtr);
311     Status |= XScuGic_Connect(GicPtr,
312                  DMA_DONE_INTR_6,
313                  (Xil_InterruptHandler)XDmaPs_DoneISR_6,
314                  (void *)DmaPtr);
315     Status |= XScuGic_Connect(GicPtr,
316                  DMA_DONE_INTR_7,
317                  (Xil_InterruptHandler)XDmaPs_DoneISR_7,
318                  (void *)DmaPtr);
319 
320     if (Status != XST_SUCCESS)
321         return XST_FAILURE;
322 
323     /*
324      * Enable the interrupts for the device
325      */
326     XScuGic_Enable(GicPtr, DMA_DONE_INTR_0);
327     XScuGic_Enable(GicPtr, DMA_DONE_INTR_1);
328     XScuGic_Enable(GicPtr, DMA_DONE_INTR_2);
329     XScuGic_Enable(GicPtr, DMA_DONE_INTR_3);
330     XScuGic_Enable(GicPtr, DMA_DONE_INTR_4);
331     XScuGic_Enable(GicPtr, DMA_DONE_INTR_5);
332     XScuGic_Enable(GicPtr, DMA_DONE_INTR_6);
333     XScuGic_Enable(GicPtr, DMA_DONE_INTR_7);
334     XScuGic_Enable(GicPtr, DMA_FAULT_INTR);
335 
336     Xil_ExceptionEnable();
337 
338     return XST_SUCCESS;
339 
340 }
341 
342 
343 /*****************************************************************************/
344 /**
345 *
346 * DmaDoneHandler.
347 *
348 * @param    Channel is the Channel number.
349 * @param    DmaCmd is the Dma Command.
350 * @param    CallbackRef is the callback reference data.
351 *
352 * @return    None.
353 *
354 * @note        None.
355 *
356 ******************************************************************************/
357 void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd, void *CallbackRef)
358 {
359 
360     /* done handler */
361     volatile int *Checked = (volatile int *)CallbackRef;
362     int Index;
363     int Status = 1;
364     int *Src;
365     int *Dst;
366 
367     Src = (int *)DmaCmd->BD.SrcAddr;
368     Dst = (int *)DmaCmd->BD.DstAddr;
369 
370     /* DMA successful */
371     /* compare the src and dst buffer */
372     for (Index = 0; Index < DMA_LENGTH; Index++) {
373         if ((Src[Index] != Dst[Index]) ||
374                 (Dst[Index] != DMA_LENGTH - Index)) {
375             Status = -XST_FAILURE;
376         }
377     }
378 
379 
380     Checked[Channel] = Status;
381 }

  AXI
DMA可以生些许独传输方向:读通道以及描绘通道,依次为MM2S和S2MM方向。也就是说“读”和“写”是DMA主动对CPU发起的操作。重点查以下几个参数:

ps_dma_demo

1 Width of Buffer Length Register:

   其实demo中召开的操作非常简单,仅仅是概念了零星个数组Src和Dst,之后采用PS_DMA将Src中数据搬移到Dst中,搬移完成后上暂停函数比较有限有的地方数据是否一律。Xilinx的SDK软件代码来定点的老路,“上有政策,下有对策”,我们可用那封装成固定格式的一个个子函数,方便今后调用。这里将整个工程分为:系统暂停,PS_DMA专有中断和主函数叔只有。

  在直接寄存器模式下,它指定在MM2S_LENGTH和S2MM_LENGTH寄存器的实用比特数。MM2S_LENGTH寄存器指定了MM2S坦途传输数据字节数,当CPU写副不零值时开始进行PS到PL的数量搬移,而S2MM_LENGTH对应另一个数据流方向。比特数直接与相应寄存器可写副的太酷勤直接相关,传输最特别字节数=
2^(Width of Buffer Length
Register)。此处保持默认14bit,也就是说启动DMA传输的卓绝可怜数据量是16384byte。

图片 6图片 7

2 Memory Map Data Width:

 1 #include "xscugic.h"
 2 #include "sys_intr.h"
 3 
 4 int sys_IntrInit(XScuGic *GicPtr)
 5 {
 6     XScuGic_Config *GicConfig;
 7     /*
 8     * Initialize the interrupt controller driver so that it is ready to
 9     * use.
10     */
11     int Status;
12     GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
13     if (NULL == GicConfig) {
14         return XST_FAILURE;
15     }
16 
17     Status = XScuGic_CfgInitialize(GicPtr, GicConfig,
18                        GicConfig->CpuBaseAddress);
19     if (Status != XST_SUCCESS) {
20         return XST_FAILURE;
21     }
22     return XST_SUCCESS;
23 }
24 
25 void setupIntrException(XScuGic *GicPtr)
26 {
27     Xil_ExceptionInit();
28     /*
29     * Connect the interrupt controller interrupt handler to the hardware
30     * interrupt handling logic in the processor.
31     */
32     Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
33                    (Xil_ExceptionHandler)XScuGic_InterruptHandler,
34                    GicPtr);
35     Xil_ExceptionEnable();
36 }

  该参数指定了Memory
Map侧数据接口宽度,选定32bit后迁移数据所在内存地址必须与4对一头。

sys_intr.c

3 Max Burst Size:

图片 8图片 9

  之前在教授PS子系统里面的DMA时介绍过DMA的Burst概念,即分批次传输数据块。官方IP核文档解释吗:

1 #ifndef SRC_SYS_INTR_H_
2 #define SRC_SYS_INTR_H_
3 
4 #define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID
5 
6 int sys_IntrInit(XScuGic *GicPtr);
7 void setupIntrException(XScuGic *GicPtr);
8 
9 #endif /* SRC_SYS_INTR_H_ */

图片 10

sys_intr.h

  理解起来burst
size确定了爆发周期的不过酷勤值,也就算是burst
size越充分,突发粒度越老(单次传输的多少个数越多)。这跟PS端DMA有所区别,显然跟
PS DMA的burst
length意义相近。笔者为进行过尝试,当启动传输数据量相同时,burst
size设置于充分状态下,每批次传输数据量再度多。

图片 11图片 12

 二、AXI DMA Loop IP子系统

  1 #include "xil_types.h"
  2 #include "xdmaps.h"
  3 #include "xscugic.h"
  4 #include "psdma_intr.h"
  5 
  6 int PS_DMA_IntrInit(XDmaPs *DmaInst,u16 DeviceId)
  7 {
  8     /*
  9     * Initialize the DMA Driver
 10     */
 11     int Status;
 12     XDmaPs_Config *DmaCfg = NULL;
 13     DmaCfg = XDmaPs_LookupConfig(DeviceId);
 14     if (DmaCfg == NULL) {
 15         return XST_FAILURE;
 16     }
 17 
 18     Status = XDmaPs_CfgInitialize(DmaInst,
 19                    DmaCfg,
 20                    DmaCfg->BaseAddress);
 21     if (Status != XST_SUCCESS) {
 22         return XST_FAILURE;
 23     }
 24     return XST_SUCCESS;
 25 }
 26 
 27 int PS_DMA_SetupIntr(XScuGic *GicPtr,XDmaPs *DmaPtr,unsigned Channel)
 28 {
 29     int Status;
 30     /*
 31     * Connect the device driver handlers that will be called when an interrupt
 32     * for the device occurs, the device driver handler performs the specific
 33     * interrupt processing for the device
 34     */
 35 
 36     /*
 37     * Connect the Fault ISR
 38     */
 39     Status = XScuGic_Connect(GicPtr,
 40                  DMA_FAULT_INTR,
 41                  (Xil_InterruptHandler)XDmaPs_FaultISR,
 42                  (void *)DmaPtr);
 43     if (Status != XST_SUCCESS) {
 44         return XST_FAILURE;
 45     }
 46 
 47     /*
 48      * Connect the Done ISR for all 8 channels of DMA 0
 49      */
 50     Status = XScuGic_Connect(GicPtr,
 51                  DMA_DONE_INTR_0,
 52                  (Xil_InterruptHandler)XDmaPs_DoneISR_0,
 53                  (void *)DmaPtr);
 54     /*Status |= XScuGic_Connect(GicPtr,
 55                  DMA_DONE_INTR_1,
 56                  (Xil_InterruptHandler)XDmaPs_DoneISR_1,
 57                  (void *)DmaPtr);
 58     Status |= XScuGic_Connect(GicPtr,
 59                  DMA_DONE_INTR_2,
 60                  (Xil_InterruptHandler)XDmaPs_DoneISR_2,
 61                  (void *)DmaPtr);
 62     Status |= XScuGic_Connect(GicPtr,
 63                  DMA_DONE_INTR_3,
 64                  (Xil_InterruptHandler)XDmaPs_DoneISR_3,
 65                  (void *)DmaPtr);
 66     Status |= XScuGic_Connect(GicPtr,
 67                  DMA_DONE_INTR_4,
 68                  (Xil_InterruptHandler)XDmaPs_DoneISR_4,
 69                  (void *)DmaPtr);
 70     Status |= XScuGic_Connect(GicPtr,
 71                  DMA_DONE_INTR_5,
 72                  (Xil_InterruptHandler)XDmaPs_DoneISR_5,
 73                  (void *)DmaPtr);
 74     Status |= XScuGic_Connect(GicPtr,
 75                  DMA_DONE_INTR_6,
 76                  (Xil_InterruptHandler)XDmaPs_DoneISR_6,
 77                  (void *)DmaPtr);
 78     Status |= XScuGic_Connect(GicPtr,
 79                  DMA_DONE_INTR_7,
 80                  (Xil_InterruptHandler)XDmaPs_DoneISR_7,
 81                  (void *)DmaPtr);*/
 82 
 83     if (Status != XST_SUCCESS)
 84         return XST_FAILURE;
 85 
 86     /* Set the Done interrupt handler */
 87     XDmaPs_SetDoneHandler(DmaPtr,
 88                 Channel,//Channel
 89                 DmaDoneHandler,//真正的中断函数
 90                 (void *)Checked);
 91 
 92     /*
 93      * Enable the interrupts for the device
 94      */
 95     XScuGic_Enable(GicPtr, DMA_DONE_INTR_0);
 96     /*
 97     XScuGic_Enable(GicPtr, DMA_DONE_INTR_1);
 98     XScuGic_Enable(GicPtr, DMA_DONE_INTR_2);
 99     XScuGic_Enable(GicPtr, DMA_DONE_INTR_3);
100     XScuGic_Enable(GicPtr, DMA_DONE_INTR_4);
101     XScuGic_Enable(GicPtr, DMA_DONE_INTR_5);
102     XScuGic_Enable(GicPtr, DMA_DONE_INTR_6);
103     XScuGic_Enable(GicPtr, DMA_DONE_INTR_7);*/
104     XScuGic_Enable(GicPtr, DMA_FAULT_INTR);
105 
106     return XST_SUCCESS;
107 }
108 
109 void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd, void *CallbackRef)
110 {
111 
112     /* done handler */
113     volatile int *Checked = (volatile int *)CallbackRef;
114     //int Index;
115     int Status = 1;
116 
117     xil_printf("Enter into the interrupt\n");
118     Checked[Channel] = Status;
119 }
120 
121 void PS_DMA_InitPara(XDmaPs_Cmd* DmaCmd)
122 {
123 
124     memset(DmaCmd, 0, sizeof(XDmaPs_Cmd));
125 
126     DmaCmd->ChanCtrl.SrcBurstSize = 4;
127     DmaCmd->ChanCtrl.SrcBurstLen = 4;
128     DmaCmd->ChanCtrl.SrcInc = 1;
129     DmaCmd->ChanCtrl.DstBurstSize = 4;
130     DmaCmd->ChanCtrl.DstBurstLen = 4;
131     DmaCmd->ChanCtrl.DstInc = 1;
132     DmaCmd->BD.SrcAddr = (u32) Src;
133     DmaCmd->BD.DstAddr = (u32) DDR_BASEADDR;//Dst
134     DmaCmd->BD.Length = DMA_LENGTH * sizeof(int);
135 }

  于运ZYNQ搭建系统时,经常用利用各种IP核做所谓的“计算加速”,将重复性高
计算量大 占用比较生CPU资源的底层处理交给各个IP核完成。这时PS ->DMA
->PL -> DMA -> PS的环路架构非常适用。这里以AXI Stream Data
FIFO代替自定义IP核作为示范,硬件IP子系统如下:

psdma_intr.c

图片 13

图片 14图片 15

 三、SDK 官方demo解析

 1 #ifndef SRC_PSDMA_INTR_H_
 2 #define SRC_PSDMA_INTR_H_
 3 
 4 #define DMA_DONE_INTR_0            XPAR_XDMAPS_0_DONE_INTR_0
 5 #define DMA_DONE_INTR_1            XPAR_XDMAPS_0_DONE_INTR_1
 6 #define DMA_DONE_INTR_2            XPAR_XDMAPS_0_DONE_INTR_2
 7 #define DMA_DONE_INTR_3            XPAR_XDMAPS_0_DONE_INTR_3
 8 #define DMA_DONE_INTR_4            XPAR_XDMAPS_0_DONE_INTR_4
 9 #define DMA_DONE_INTR_5            XPAR_XDMAPS_0_DONE_INTR_5
10 #define DMA_DONE_INTR_6            XPAR_XDMAPS_0_DONE_INTR_6
11 #define DMA_DONE_INTR_7            XPAR_XDMAPS_0_DONE_INTR_7
12 #define DMA_FAULT_INTR            XPAR_XDMAPS_0_FAULT_INTR
13 
14 #define DDR_BASEADDR 0x00600000//XPAR_PS7_DDR_0_S_AXI_BASEADDR 0x00100000
15 #define DMA_LENGTH    1024    /* Length of the Dma Transfers */
16 
17 int Src[DMA_LENGTH] __attribute__ ((aligned (32)));
18 volatile int Checked[XDMAPS_CHANNELS_PER_DEV];
19 
20 int PS_DMA_IntrInit(XDmaPs *DmaInst,u16 DeviceId);
21 int PS_DMA_SetupIntr(XScuGic *GicPtr,XDmaPs *DmaPtr,unsigned Channel);
22 void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd, void *CallbackRef);
23 void PS_DMA_InitPara(XDmaPs_Cmd* DmaCmd);
24 
25 #endif /* SRC_PSDMA_INTR_H_ */

  率先分析下官方的demo。图片 16

psdma_intr.h

图片 17图片 18

图片 19图片 20

  1 /******************************************************************************
  2 *
  3 * Copyright (C) 2010 - 2016 Xilinx, Inc.  All rights reserved.
  4 *
  5 * Permission is hereby granted, free of charge, to any person obtaining a copy
  6 * of this software and associated documentation files (the "Software"), to deal
  7 * in the Software without restriction, including without limitation the rights
  8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9 * copies of the Software, and to permit persons to whom the Software is
 10 * furnished to do so, subject to the following conditions:
 11 *
 12 * The above copyright notice and this permission notice shall be included in
 13 * all copies or substantial portions of the Software.
 14 *
 15 * Use of the Software is limited solely to applications:
 16 * (a) running on a Xilinx device, or
 17 * (b) that interact with a Xilinx device through a bus or interconnect.
 18 *
 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 22 * XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 24 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 25 * SOFTWARE.
 26 *
 27 * Except as contained in this notice, the name of the Xilinx shall not be used
 28 * in advertising or otherwise to promote the sale, use or other dealings in
 29 * this Software without prior written authorization from Xilinx.
 30 *
 31 ******************************************************************************/
 32 /*****************************************************************************/
 33 /**
 34  *
 35  * @file xaxidma_example_simple_intr.c
 36  *
 37  * This file demonstrates how to use the xaxidma driver on the Xilinx AXI
 38  * DMA core (AXIDMA) to transfer packets.in interrupt mode when the AXIDMA core
 39  * is configured in simple mode
 40  *
 41  * This code assumes a loopback hardware widget is connected to the AXI DMA
 42  * core for data packet loopback.
 43  *
 44  * To see the debug print, you need a Uart16550 or uartlite in your system,
 45  * and please set "-DDEBUG" in your compiler options. You need to rebuild your
 46  * software executable.
 47  *
 48  * Make sure that MEMORY_BASE is defined properly as per the HW system. The
 49  * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In
 50  * throughput mode, it is 512MB.  These limits are need to ensured for
 51  * proper operation of this code.
 52  *
 53  *
 54  * <pre>
 55  * MODIFICATION HISTORY:
 56  *
 57  * Ver   Who  Date     Changes
 58  * ----- ---- -------- -------------------------------------------------------
 59  * 4.00a rkv  02/22/11 New example created for simple DMA, this example is for
 60  *                  simple DMA,Added interrupt support for Zynq.
 61  * 4.00a srt  08/04/11 Changed a typo in the RxIntrHandler, changed
 62  *               XAXIDMA_DMA_TO_DEVICE to XAXIDMA_DEVICE_TO_DMA
 63  * 5.00a srt  03/06/12 Added Flushing and Invalidation of Caches to fix CRs
 64  *               648103, 648701.
 65  *               Added V7 DDR Base Address to fix CR 649405.
 66  * 6.00a srt  03/27/12 Changed API calls to support MCDMA driver.
 67  * 7.00a srt  06/18/12 API calls are reverted back for backward compatibility.
 68  * 7.01a srt  11/02/12 Buffer sizes (Tx and Rx) are modified to meet maximum
 69  *               DDR memory limit of the h/w system built with Area mode
 70  * 7.02a srt  03/01/13 Updated DDR base address for IPI designs (CR 703656).
 71  * 9.1   adk  01/07/16 Updated DDR base address for Ultrascale (CR 799532) and
 72  *               removed the defines for S6/V6.
 73  * 9.2   vak  15/04/16 Fixed compilation warnings in the example
 74  * </pre>
 75  *
 76  * ***************************************************************************
 77  */
 78 
 79 /***************************** Include Files *********************************/
 80 
 81 #include "xaxidma.h"
 82 #include "xparameters.h"
 83 #include "xil_exception.h"
 84 #include "xdebug.h"
 85 
 86 #ifdef XPAR_UARTNS550_0_BASEADDR
 87 #include "xuartns550_l.h"       /* to use uartns550 */
 88 #endif
 89 
 90 
 91 #ifdef XPAR_INTC_0_DEVICE_ID
 92  #include "xintc.h"
 93 #else
 94  #include "xscugic.h"
 95 #endif
 96 
 97 /************************** Constant Definitions *****************************/
 98 
 99 /*
100  * Device hardware build related constants.
101  */
102 
103 #define DMA_DEV_ID        XPAR_AXIDMA_0_DEVICE_ID
104 
105 #ifdef XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
106 #define DDR_BASE_ADDR        XPAR_AXI_7SDDR_0_S_AXI_BASEADDR
107 #elif XPAR_MIG7SERIES_0_BASEADDR
108 #define DDR_BASE_ADDR    XPAR_MIG7SERIES_0_BASEADDR
109 #elif XPAR_MIG_0_BASEADDR
110 #define DDR_BASE_ADDR    XPAR_MIG_0_BASEADDR
111 #elif XPAR_PSU_DDR_0_S_AXI_BASEADDR
112 #define DDR_BASE_ADDR    XPAR_PSU_DDR_0_S_AXI_BASEADDR
113 #endif
114 
115 #ifndef DDR_BASE_ADDR
116 #warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \
117         DEFAULT SET TO 0x01000000
118 #define MEM_BASE_ADDR        0x01000000
119 #else
120 #define MEM_BASE_ADDR        (DDR_BASE_ADDR + 0x1000000)
121 #endif
122 
123 #ifdef XPAR_INTC_0_DEVICE_ID
124 #define RX_INTR_ID        XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID
125 #define TX_INTR_ID        XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID
126 #else
127 #define RX_INTR_ID        XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID
128 #define TX_INTR_ID        XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID
129 #endif
130 
131 #define TX_BUFFER_BASE        (MEM_BASE_ADDR + 0x00100000)
132 #define RX_BUFFER_BASE        (MEM_BASE_ADDR + 0x00300000)
133 #define RX_BUFFER_HIGH        (MEM_BASE_ADDR + 0x004FFFFF)
134 
135 #ifdef XPAR_INTC_0_DEVICE_ID
136 #define INTC_DEVICE_ID          XPAR_INTC_0_DEVICE_ID
137 #else
138 #define INTC_DEVICE_ID          XPAR_SCUGIC_SINGLE_DEVICE_ID
139 #endif
140 
141 #ifdef XPAR_INTC_0_DEVICE_ID
142  #define INTC        XIntc
143  #define INTC_HANDLER    XIntc_InterruptHandler
144 #else
145  #define INTC        XScuGic
146  #define INTC_HANDLER    XScuGic_InterruptHandler
147 #endif
148 
149 
150 /* Timeout loop counter for reset
151  */
152 #define RESET_TIMEOUT_COUNTER    10000
153 
154 #define TEST_START_VALUE    0xC
155 /*
156  * Buffer and Buffer Descriptor related constant definition
157  */
158 #define MAX_PKT_LEN        0x100
159 
160 #define NUMBER_OF_TRANSFERS    10
161 
162 /* The interrupt coalescing threshold and delay timer threshold
163  * Valid range is 1 to 255
164  *
165  * We set the coalescing threshold to be the total number of packets.
166  * The receive side will only get one completion interrupt for this example.
167  */
168 
169 /**************************** Type Definitions *******************************/
170 
171 
172 /***************** Macros (Inline Functions) Definitions *********************/
173 
174 
175 /************************** Function Prototypes ******************************/
176 #ifndef DEBUG
177 extern void xil_printf(const char *format, ...);
178 #endif
179 
180 #ifdef XPAR_UARTNS550_0_BASEADDR
181 static void Uart550_Setup(void);
182 #endif
183 
184 static int CheckData(int Length, u8 StartValue);
185 static void TxIntrHandler(void *Callback);
186 static void RxIntrHandler(void *Callback);
187 
188 
189 
190 
191 static int SetupIntrSystem(INTC * IntcInstancePtr,
192                XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId);
193 static void DisableIntrSystem(INTC * IntcInstancePtr,
194                     u16 TxIntrId, u16 RxIntrId);
195 
196 
197 
198 /************************** Variable Definitions *****************************/
199 /*
200  * Device instance definitions
201  */
202 
203 
204 static XAxiDma AxiDma;        /* Instance of the XAxiDma */
205 
206 static INTC Intc;    /* Instance of the Interrupt Controller */
207 
208 /*
209  * Flags interrupt handlers use to notify the application context the events.
210  */
211 volatile int TxDone;
212 volatile int RxDone;
213 volatile int Error;
214 
215 /*****************************************************************************/
216 /**
217 *
218 * Main function
219 *
220 * This function is the main entry of the interrupt test. It does the following:
221 *    Set up the output terminal if UART16550 is in the hardware build
222 *    Initialize the DMA engine
223 *    Set up Tx and Rx channels
224 *    Set up the interrupt system for the Tx and Rx interrupts
225 *    Submit a transfer
226 *    Wait for the transfer to finish
227 *    Check transfer status
228 *    Disable Tx and Rx interrupts
229 *    Print test status and exit
230 *
231 * @param    None
232 *
233 * @return
234 *        - XST_SUCCESS if example finishes successfully
235 *        - XST_FAILURE if example fails.
236 *
237 * @note        None.
238 *
239 ******************************************************************************/
240 int main(void)
241 {
242     int Status;
243     XAxiDma_Config *Config;
244     int Tries = NUMBER_OF_TRANSFERS;
245     int Index;
246     u8 *TxBufferPtr;
247     u8 *RxBufferPtr;
248     u8 Value;
249 
250     TxBufferPtr = (u8 *)TX_BUFFER_BASE ;
251     RxBufferPtr = (u8 *)RX_BUFFER_BASE;
252     /* Initial setup for Uart16550 */
253 #ifdef XPAR_UARTNS550_0_BASEADDR
254 
255     Uart550_Setup();
256 
257 #endif
258 
259     xil_printf("\r\n--- Entering main() --- \r\n");
260 
261     Config = XAxiDma_LookupConfig(DMA_DEV_ID);
262     if (!Config) {
263         xil_printf("No config found for %d\r\n", DMA_DEV_ID);
264 
265         return XST_FAILURE;
266     }
267 
268     /* Initialize DMA engine */
269     Status = XAxiDma_CfgInitialize(&AxiDma, Config);
270 
271     if (Status != XST_SUCCESS) {
272         xil_printf("Initialization failed %d\r\n", Status);
273         return XST_FAILURE;
274     }
275 
276     if(XAxiDma_HasSg(&AxiDma)){
277         xil_printf("Device configured as SG mode \r\n");
278         return XST_FAILURE;
279     }
280 
281     /* Set up Interrupt system  */
282     Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID);
283     if (Status != XST_SUCCESS) {
284 
285         xil_printf("Failed intr setup\r\n");
286         return XST_FAILURE;
287     }
288 
289     /* Disable all interrupts before setup */
290 
291     XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
292                         XAXIDMA_DMA_TO_DEVICE);
293 
294     XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
295                 XAXIDMA_DEVICE_TO_DMA);
296 
297     /* Enable all interrupts */
298     XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
299                             XAXIDMA_DMA_TO_DEVICE);
300 
301 
302     XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,
303                             XAXIDMA_DEVICE_TO_DMA);
304 
305     /* Initialize flags before start transfer test  */
306     TxDone = 0;
307     RxDone = 0;
308     Error = 0;
309 
310     Value = TEST_START_VALUE;
311 
312     for(Index = 0; Index < MAX_PKT_LEN; Index ++) {
313             TxBufferPtr[Index] = Value;
314 
315             Value = (Value + 1) & 0xFF;
316     }
317 
318     /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache
319      * is enabled
320      */
321     Xil_DCacheFlushRange((UINTPTR)TxBufferPtr, MAX_PKT_LEN);
322 #ifdef __aarch64__
323     Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN);
324 #endif
325 
326     /* Send a packet */
327     for(Index = 0; Index < Tries; Index ++) {
328 
329         Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) RxBufferPtr,
330                     MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
331 
332         if (Status != XST_SUCCESS) {
333             return XST_FAILURE;
334         }
335 
336         Status = XAxiDma_SimpleTransfer(&AxiDma,(UINTPTR) TxBufferPtr,
337                     MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE);
338 
339         if (Status != XST_SUCCESS) {
340             return XST_FAILURE;
341         }
342 
343 
344         /*
345          * Wait TX done and RX done
346          */
347         while (!TxDone && !RxDone && !Error) {
348                 /* NOP */
349         }
350 
351         if (Error) {
352             xil_printf("Failed test transmit%s done, "
353             "receive%s done\r\n", TxDone? "":" not",
354                             RxDone? "":" not");
355 
356             goto Done;
357 
358         }
359 
360         /*
361          * Test finished, check data
362          */
363         Status = CheckData(MAX_PKT_LEN, 0xC);
364         if (Status != XST_SUCCESS) {
365             xil_printf("Data check failed\r\n");
366             goto Done;
367         }
368     }
369 
370 
371     xil_printf("AXI DMA interrupt example test passed\r\n");
372 
373 
374     /* Disable TX and RX Ring interrupts and return success */
375 
376     DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID);
377 
378 Done:
379     xil_printf("--- Exiting main() --- \r\n");
380 
381     return XST_SUCCESS;
382 }
383 
384 #ifdef XPAR_UARTNS550_0_BASEADDR
385 /*****************************************************************************/
386 /*
387 *
388 * Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8
389 *
390 * @param    None
391 *
392 * @return    None
393 *
394 * @note        None.
395 *
396 ******************************************************************************/
397 static void Uart550_Setup(void)
398 {
399 
400     XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR,
401             XPAR_XUARTNS550_CLOCK_HZ, 9600);
402 
403     XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR,
404             XUN_LCR_8_DATA_BITS);
405 }
406 #endif
407 
408 /*****************************************************************************/
409 /*
410 *
411 * This function checks data buffer after the DMA transfer is finished.
412 *
413 * We use the static tx/rx buffers.
414 *
415 * @param    Length is the length to check
416 * @param    StartValue is the starting value of the first byte
417 *
418 * @return
419 *        - XST_SUCCESS if validation is successful
420 *        - XST_FAILURE if validation is failure.
421 *
422 * @note        None.
423 *
424 ******************************************************************************/
425 static int CheckData(int Length, u8 StartValue)
426 {
427     u8 *RxPacket;
428     int Index = 0;
429     u8 Value;
430 
431     RxPacket = (u8 *) RX_BUFFER_BASE;
432     Value = StartValue;
433 
434     /* Invalidate the DestBuffer before receiving the data, in case the
435      * Data Cache is enabled
436      */
437 #ifndef __aarch64__
438     Xil_DCacheInvalidateRange((u32)RxPacket, Length);
439 #endif
440 
441     for(Index = 0; Index < Length; Index++) {
442         if (RxPacket[Index] != Value) {
443             xil_printf("Data error %d: %x/%x\r\n",
444                 Index, RxPacket[Index], Value);
445 
446             return XST_FAILURE;
447         }
448         Value = (Value + 1) & 0xFF;
449     }
450 
451     return XST_SUCCESS;
452 }
453 
454 /*****************************************************************************/
455 /*
456 *
457 * This is the DMA TX Interrupt handler function.
458 *
459 * It gets the interrupt status from the hardware, acknowledges it, and if any
460 * error happens, it resets the hardware. Otherwise, if a completion interrupt
461 * is present, then sets the TxDone.flag
462 *
463 * @param    Callback is a pointer to TX channel of the DMA engine.
464 *
465 * @return    None.
466 *
467 * @note        None.
468 *
469 ******************************************************************************/
470 static void TxIntrHandler(void *Callback)
471 {
472 
473     u32 IrqStatus;
474     int TimeOut;
475     XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
476 
477     /* Read pending interrupts */
478     IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);
479 
480     /* Acknowledge pending interrupts */
481 
482 
483     XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
484 
485     /*
486      * If no interrupt is asserted, we do not do anything
487      */
488     if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
489 
490         return;
491     }
492 
493     /*
494      * If error interrupt is asserted, raise error flag, reset the
495      * hardware to recover from the error, and return with no further
496      * processing.
497      */
498     if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
499 
500         Error = 1;
501 
502         /*
503          * Reset should never fail for transmit channel
504          */
505         XAxiDma_Reset(AxiDmaInst);
506 
507         TimeOut = RESET_TIMEOUT_COUNTER;
508 
509         while (TimeOut) {
510             if (XAxiDma_ResetIsDone(AxiDmaInst)) {
511                 break;
512             }
513 
514             TimeOut -= 1;
515         }
516 
517         return;
518     }
519 
520     /*
521      * If Completion interrupt is asserted, then set the TxDone flag
522      */
523     if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
524 
525         TxDone = 1;
526     }
527 }
528 
529 /*****************************************************************************/
530 /*
531 *
532 * This is the DMA RX interrupt handler function
533 *
534 * It gets the interrupt status from the hardware, acknowledges it, and if any
535 * error happens, it resets the hardware. Otherwise, if a completion interrupt
536 * is present, then it sets the RxDone flag.
537 *
538 * @param    Callback is a pointer to RX channel of the DMA engine.
539 *
540 * @return    None.
541 *
542 * @note        None.
543 *
544 ******************************************************************************/
545 static void RxIntrHandler(void *Callback)
546 {
547     u32 IrqStatus;
548     int TimeOut;
549     XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
550 
551     /* Read pending interrupts */
552     IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);
553 
554     /* Acknowledge pending interrupts */
555     XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
556 
557     /*
558      * If no interrupt is asserted, we do not do anything
559      */
560     if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
561         return;
562     }
563 
564     /*
565      * If error interrupt is asserted, raise error flag, reset the
566      * hardware to recover from the error, and return with no further
567      * processing.
568      */
569     if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
570 
571         Error = 1;
572 
573         /* Reset could fail and hang
574          * NEED a way to handle this or do not call it??
575          */
576         XAxiDma_Reset(AxiDmaInst);
577 
578         TimeOut = RESET_TIMEOUT_COUNTER;
579 
580         while (TimeOut) {
581             if(XAxiDma_ResetIsDone(AxiDmaInst)) {
582                 break;
583             }
584 
585             TimeOut -= 1;
586         }
587 
588         return;
589     }
590 
591     /*
592      * If completion interrupt is asserted, then set RxDone flag
593      */
594     if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
595 
596         RxDone = 1;
597     }
598 }
599 
600 /*****************************************************************************/
601 /*
602 *
603 * This function setups the interrupt system so interrupts can occur for the
604 * DMA, it assumes INTC component exists in the hardware system.
605 *
606 * @param    IntcInstancePtr is a pointer to the instance of the INTC.
607 * @param    AxiDmaPtr is a pointer to the instance of the DMA engine
608 * @param    TxIntrId is the TX channel Interrupt ID.
609 * @param    RxIntrId is the RX channel Interrupt ID.
610 *
611 * @return
612 *        - XST_SUCCESS if successful,
613 *        - XST_FAILURE.if not succesful
614 *
615 * @note        None.
616 *
617 ******************************************************************************/
618 static int SetupIntrSystem(INTC * IntcInstancePtr,
619                XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId)
620 {
621     int Status;
622 
623 #ifdef XPAR_INTC_0_DEVICE_ID
624 
625     /* Initialize the interrupt controller and connect the ISRs */
626     Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID);
627     if (Status != XST_SUCCESS) {
628 
629         xil_printf("Failed init intc\r\n");
630         return XST_FAILURE;
631     }
632 
633     Status = XIntc_Connect(IntcInstancePtr, TxIntrId,
634                    (XInterruptHandler) TxIntrHandler, AxiDmaPtr);
635     if (Status != XST_SUCCESS) {
636 
637         xil_printf("Failed tx connect intc\r\n");
638         return XST_FAILURE;
639     }
640 
641     Status = XIntc_Connect(IntcInstancePtr, RxIntrId,
642                    (XInterruptHandler) RxIntrHandler, AxiDmaPtr);
643     if (Status != XST_SUCCESS) {
644 
645         xil_printf("Failed rx connect intc\r\n");
646         return XST_FAILURE;
647     }
648 
649     /* Start the interrupt controller */
650     Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE);
651     if (Status != XST_SUCCESS) {
652 
653         xil_printf("Failed to start intc\r\n");
654         return XST_FAILURE;
655     }
656 
657     XIntc_Enable(IntcInstancePtr, TxIntrId);
658     XIntc_Enable(IntcInstancePtr, RxIntrId);
659 
660 #else
661 
662     XScuGic_Config *IntcConfig;
663 
664 
665     /*
666      * Initialize the interrupt controller driver so that it is ready to
667      * use.
668      */
669     IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
670     if (NULL == IntcConfig) {
671         return XST_FAILURE;
672     }
673 
674     Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig,
675                     IntcConfig->CpuBaseAddress);
676     if (Status != XST_SUCCESS) {
677         return XST_FAILURE;
678     }
679 
680 
681     XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3);
682 
683     XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3);
684     /*
685      * Connect the device driver handler that will be called when an
686      * interrupt for the device occurs, the handler defined above performs
687      * the specific interrupt processing for the device.
688      */
689     Status = XScuGic_Connect(IntcInstancePtr, TxIntrId,
690                 (Xil_InterruptHandler)TxIntrHandler,
691                 AxiDmaPtr);
692     if (Status != XST_SUCCESS) {
693         return Status;
694     }
695 
696     Status = XScuGic_Connect(IntcInstancePtr, RxIntrId,
697                 (Xil_InterruptHandler)RxIntrHandler,
698                 AxiDmaPtr);
699     if (Status != XST_SUCCESS) {
700         return Status;
701     }
702 
703     XScuGic_Enable(IntcInstancePtr, TxIntrId);
704     XScuGic_Enable(IntcInstancePtr, RxIntrId);
705 
706 
707 #endif
708 
709     /* Enable interrupts from the hardware */
710 
711     Xil_ExceptionInit();
712     Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT,
713             (Xil_ExceptionHandler)INTC_HANDLER,
714             (void *)IntcInstancePtr);
715 
716     Xil_ExceptionEnable();
717 
718     return XST_SUCCESS;
719 }
720 
721 /*****************************************************************************/
722 /**
723 *
724 * This function disables the interrupts for DMA engine.
725 *
726 * @param    IntcInstancePtr is the pointer to the INTC component instance
727 * @param    TxIntrId is interrupt ID associated w/ DMA TX channel
728 * @param    RxIntrId is interrupt ID associated w/ DMA RX channel
729 *
730 * @return    None.
731 *
732 * @note        None.
733 *
734 ******************************************************************************/
735 static void DisableIntrSystem(INTC * IntcInstancePtr,
736                     u16 TxIntrId, u16 RxIntrId)
737 {
738 #ifdef XPAR_INTC_0_DEVICE_ID
739     /* Disconnect the interrupts for the DMA TX and RX channels */
740     XIntc_Disconnect(IntcInstancePtr, TxIntrId);
741     XIntc_Disconnect(IntcInstancePtr, RxIntrId);
742 #else
743     XScuGic_Disconnect(IntcInstancePtr, TxIntrId);
744     XScuGic_Disconnect(IntcInstancePtr, RxIntrId);
745 #endif
746 }
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include "sleep.h"
  4 #include "xparameters.h"
  5 #include "xil_types.h"
  6 #include "xil_assert.h"
  7 #include "xil_io.h"
  8 #include "xil_exception.h"
  9 #include "xil_cache.h"
 10 #include "xil_printf.h"
 11 #include "xscugic.h"
 12 #include "xdmaps.h"
 13 
 14 #include "sys_intr.h"
 15 #include "psdma_intr.h"
 16 
 17 
 18 #define DMA_DEVICE_ID             XPAR_XDMAPS_1_DEVICE_ID
 19 #define INTC_DEVICE_ID            XPAR_SCUGIC_SINGLE_DEVICE_ID
 20 
 21 
 22 #define TEST_ROUNDS    1    /* Number of loops that the Dma transfers run.*/
 23 #define TIMEOUT_LIMIT     0x2000    /* Loop count for timeout */
 24 
 25 
 26 static XScuGic GicInstance;
 27 static XDmaPs DmaInstance;
 28 static XDmaPs_Cmd DmaCmd;
 29 unsigned int Channel = 0;
 30 
 31 /************************** Function Prototypes ******************************/
 32 
 33 int PS_DMA_WriteTest();
 34 int SetupInterruptSystem(XScuGic *GicPtr, XDmaPs *DmaPtr);
 35 void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd,
 36             void *CallbackRef);
 37 int dataCheck(u32 baseAddr,u32 len);
 38 int systemInit(XScuGic *GicPtr,u16 DeviceId);
 39 
 40 
 41 int main(void)
 42 {
 43     int Status;
 44     Status = systemInit(&GicInstance,DMA_DEVICE_ID);
 45     if (Status != XST_SUCCESS) {
 46             xil_printf("System initialization is failed\r\n");
 47             return XST_FAILURE;
 48         }
 49 
 50     Status = PS_DMA_WriteTest();
 51     if (Status != XST_SUCCESS) {
 52         xil_printf("Error: XDMaPs_Example_W_Intr failed\r\n");
 53         return XST_FAILURE;
 54     }
 55     xil_printf("Checking data...\n");
 56     Status = dataCheck(DDR_BASEADDR,DMA_LENGTH);
 57     if(Status != XST_SUCCESS)
 58     {
 59         xil_printf("Error:check failed\n");
 60         return XST_FAILURE;
 61     }
 62 
 63     xil_printf("Writing data to DDR using DMA test passed!\r\n");
 64     return XST_SUCCESS;
 65 
 66 }
 67 
 68 int dataCheck(u32 baseAddr,u32 len)
 69 {
 70     u32 DDR_ReadData[1024];
 71     int i;
 72     for(i=0;i<len;i++)
 73     {
 74         DDR_ReadData[i] = Xil_In32(baseAddr+i*4);
 75         if(DDR_ReadData[i]!=Src[i])
 76             return XST_FAILURE;
 77         //else  //将写入DDR数据读回 并打印
 78         //    xil_printf("data at %x is %d\n",baseAddr+i*4,DDR_ReadData[i]);
 79     }
 80     return XST_SUCCESS;
 81 }
 82 
 83 
 84 /*****************************************************************************/
 85 /**
 86  *
 87  * Interrupt Example to test the DMA.
 88  *
 89  * @param    DeviceId is the Device ID of the DMA controller.
 90  *
 91  * @return    XST_SUCCESS to indicate success, otherwise XST_FAILURE.
 92  *
 93  * @note    None.
 94  *
 95  ****************************************************************************/
 96 int PS_DMA_WriteTest()
 97 {
 98     int Index;
 99     int Status;
100     int TestStatus;
101     int TestRound;
102     int TimeOutCnt;
103 
104     TestStatus = XST_SUCCESS;
105 
106     for (TestRound = 0; TestRound < TEST_ROUNDS; TestRound++) {
107         xil_printf("Test round %d\r\n", TestRound);
108         for (Channel = 0;Channel < 1;Channel++)
109         {
110             /* Initialize source */
111             for (Index = 0; Index < DMA_LENGTH; Index++)
112                 Src[Index] = DMA_LENGTH - Index;
113 
114             Checked[Channel] = 0;
115 
116             Status = XDmaPs_Start(&DmaInstance, Channel, &DmaCmd, 0);
117             if (Status != XST_SUCCESS) {
118                 xil_printf("Starting the DMA is failed.\n");
119                 return XST_FAILURE;
120             }
121             xil_printf("Starting the DMA is successful.\n");
122             TimeOutCnt = 0;
123 
124             while (!Checked[Channel]
125                    && TimeOutCnt < TIMEOUT_LIMIT) {
126                 TimeOutCnt++;
127             }
128             /* Now the DMA is done */
129             xil_printf("Jump out of the interrupt\n");
130             if (TimeOutCnt >= TIMEOUT_LIMIT) {
131                 xil_printf("Overtime!\n");
132                 TestStatus = XST_FAILURE;
133             }
134 
135             if (Checked[Channel] < 0) {
136                 /* DMA controller failed */
137                 xil_printf("Checking failure!\n");
138                 TestStatus = XST_FAILURE;
139             }
140         }
141     }
142 
143     return TestStatus;
144 
145 }
146 
147 int systemInit(XScuGic *GicPtr,u16 DeviceId)
148 {
149     xil_printf("Start to initialize interrupt system.\n");
150 
151     PS_DMA_InitPara(&DmaCmd);//主要设置DMA的源目的地址
152     //xil_printf("Configuring DMA parameters is successful.\n");
153 
154     int Status;
155 
156     Status = PS_DMA_IntrInit(&DmaInstance,DeviceId);
157     if (Status != XST_SUCCESS) {
158             xil_printf("DMA initialization is failed.\n");
159             return XST_FAILURE;
160         }
161     //xil_printf("DMA initialization is successful.\n");
162 
163     Status = sys_IntrInit(GicPtr);
164     if (Status != XST_SUCCESS) {
165             xil_printf("Initialization of the interrupt system  is failed.\n");
166             return XST_FAILURE;
167         }
168     //xil_printf("Initialization of the interrupt system  is successful.\n");
169 
170     setupIntrException(GicPtr);
171 
172     Status = PS_DMA_SetupIntr(GicPtr,&DmaInstance,Channel);//////////////////////////DMA中断入口///////////////////////
173     if (Status != XST_SUCCESS) {
174         xil_printf("Setting up DMA interrupt is failed.\n");
175         return XST_FAILURE;
176     }
177     //xil_printf("Setting up DMA interrupt is successful.\n");
178 
179     xil_printf("System initialization is finished.\n");
180     xil_printf("------------------------------------------\n");
181     return XST_SUCCESS;
182 }

xaxidma_example_simple_intr.c

main.c

 主函数惨遭逐一完成了:DMA初始化,建立中断系统,使能DMA中断,初始化标志位与发送数据,启动DMA传输和数据检测。中断部分的情节及PS
DMA非常接近,传输就后进入的中断函数中唯有置位了发送或收取好标志位:

  上述代码的卷入方式参考了米联客教程被的思。先说明系统中断部分:sys_IntrInit()函数中进行查找表配置与刹车控制器初始化操作,setupIntrException()函数负责使能暂停异常处理。再来说说PS_DMA中断部分:PS_DMA_IntrInit()函数和网暂停中sys_IntrInit()从操作及格式几乎就同样,亦凡查找表配置以及DMA的初始化。PS_DMA_SetupIntr()函数完成了中断源和刹车控制器的连年和装中断处理器,以及暂停而能,也不怕是有着PS_DMA的专用中断操作。

图片 21图片 22

  PS_DMA_SetupIntr()内最好关键的一对是XDmaPs_SetDoneHandler(),其相当给一个调用中断函数的通用处理框架,它的老三单参数DoneHandler才是真的的中断处理函数。这里涉及到C语言的高级话题:函数通过函数指针调用另一个函数,被函数指针调用的函数就是司空见惯说的“回调函数”了。指针调用函数的计兼顾了序的通用架构和灵活性,具体参考文章:**不懂C语言回调函数,那就看这首文章吧!

  1 static void TxIntrHandler(void *Callback)
  2 {
  3 
  4     u32 IrqStatus;
  5     int TimeOut;
  6     XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
  7 
  8     /* Read pending interrupts */
  9     IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE);
 10 
 11     /* Acknowledge pending interrupts */
 12 
 13 
 14     XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE);
 15 
 16     /*
 17      * If no interrupt is asserted, we do not do anything
 18      */
 19     if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
 20 
 21         return;
 22     }
 23 
 24     /*
 25      * If error interrupt is asserted, raise error flag, reset the
 26      * hardware to recover from the error, and return with no further
 27      * processing.
 28      */
 29     if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
 30 
 31         Error = 1;
 32 
 33         /*
 34          * Reset should never fail for transmit channel
 35          */
 36         XAxiDma_Reset(AxiDmaInst);
 37 
 38         TimeOut = RESET_TIMEOUT_COUNTER;
 39 
 40         while (TimeOut) {
 41             if (XAxiDma_ResetIsDone(AxiDmaInst)) {
 42                 break;
 43             }
 44 
 45             TimeOut -= 1;
 46         }
 47 
 48         return;
 49     }
 50 
 51     /*
 52      * If Completion interrupt is asserted, then set the TxDone flag
 53      */
 54     if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
 55 
 56         TxDone = 1;
 57     }
 58 }
 59 
 60 /*****************************************************************************/
 61 /*
 62 *
 63 * This is the DMA RX interrupt handler function
 64 *
 65 * It gets the interrupt status from the hardware, acknowledges it, and if any
 66 * error happens, it resets the hardware. Otherwise, if a completion interrupt
 67 * is present, then it sets the RxDone flag.
 68 *
 69 * @param    Callback is a pointer to RX channel of the DMA engine.
 70 *
 71 * @return    None.
 72 *
 73 * @note        None.
 74 *
 75 ******************************************************************************/
 76 static void RxIntrHandler(void *Callback)
 77 {
 78     u32 IrqStatus;
 79     int TimeOut;
 80     XAxiDma *AxiDmaInst = (XAxiDma *)Callback;
 81 
 82     /* Read pending interrupts */
 83     IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA);
 84 
 85     /* Acknowledge pending interrupts */
 86     XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA);
 87 
 88     /*
 89      * If no interrupt is asserted, we do not do anything
 90      */
 91     if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) {
 92         return;
 93     }
 94 
 95     /*
 96      * If error interrupt is asserted, raise error flag, reset the
 97      * hardware to recover from the error, and return with no further
 98      * processing.
 99      */
100     if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) {
101 
102         Error = 1;
103 
104         /* Reset could fail and hang
105          * NEED a way to handle this or do not call it??
106          */
107         XAxiDma_Reset(AxiDmaInst);
108 
109         TimeOut = RESET_TIMEOUT_COUNTER;
110 
111         while (TimeOut) {
112             if(XAxiDma_ResetIsDone(AxiDmaInst)) {
113                 break;
114             }
115 
116             TimeOut -= 1;
117         }
118 
119         return;
120     }
121 
122     /*
123      * If completion interrupt is asserted, then set RxDone flag
124      */
125     if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) {
126 
127         RxDone = 1;
128     }
129 }
  • 简书 https://www.jianshu.com/p/2f695d6fd64f ** 在拖欠次中,中断回调函数为DmaDoneHandler()。

intrHandler

  PS_DMA_InitPara()是自行添加的PS_DMA参数初始化函数,内部的参数更是根本了,我们来查Xilinx官方文档ug585的DMA
Controller章节。

   DMA启动传输部分如下,调用库函数XAxiDma_SimpleTransfer。以第一个吗条例,是将RxBufferPtr为数量首地址,MAX_PKT_LEN为字节数,XAXIDMA_DEVICE_TO_DMA为传输方向启动DMA传输数据。MAX_PKT_LEN不克跳之前IP核配置参数指定的16384byte,XAXIDMA_DEVICE_TO_DMA和XAXIDMA_DMA_TO_DEVICE依次指PL->
DMA ->PS以及PS->DMA ->
PL方向,也就算是PL就是中间的DEVICE。DMA启动函数只生一个地点,这是与PS端DMA最可怜之分别,因为数量搬移的任何一侧凡是富含无地址之流接口的IP核,该侧“地址”由硬件连接决定。图片 23

图片 24

  再来探望搬移数据外存首地址RxBufferPtr和TxBufferPtr.从脚的定义可见MEM_BASE_ADDR是DDR_BASE_ADDR加上同样段落偏移量的结果,DDR基地址数值从xparameters.h中翻。

  简要来说,DMA以burst形式传输数据,意思是分批次搬移。手册说明原或目的burst_size位富有不克超过64bit,这也是其挂载AXI总线的数目位富有。PS_DMA_InitPara()里之SrcBurstSize为自突发传输位宽字节数,最老也8.SrcBurstLen是手册中所说的“burst
length”,即突发传输数据个数。SrcInc代表burst
types为地方自增(1)还是地方固定(0)模式。目的控制字同理。剩下的老三个参数最重点:SrcAddr DstAddr Length分别表示源首地址

图片 25

目的首地址和凡需要迁移移的数量字节数。需要留意的是,一定要是满足srcburstsize*srcburstlen

dstburstsize*dstburstlen,否则发生错误。这一点乎较好明,相当给FPGA逻辑设计中的异步FIFO两侧数据带动富要配合。

   那么要惦记成就OCM到DDR的数码搬移,改动下地址便可以嘛。由于读写DDR要拜访纯属地址,所以要挺小心读写操作的地址不克跟DDR内存储程序代码和高中级数据的地点段重叠。避免程序崩溃大简短的做法即是当XPAR_PS7_DDR_0_S_AXI_BASEADDR
的基本功及加以相同截偏移量,具体加多少之问题自己为无是死明显,希望看到底情侣能以评头论足着指点一二。

  对于ZYNQ这无异SOC架构来说,PS端连接而盖极其网,USB等高带宽外设计接口更加便民,所以PS_DMA的灵活运用还好是十分必要的,更活便捷的使就无异硬件资源还要深持续探讨。PS端与PL端高速数据交互就用因此到另外一个DMA成员AXI_DMA,可以说它以片内总线打破了CPU+FPGA架构的性能瓶颈,该有情节将以继承证。

图片 26

图片 27

季、函数重用封装

  官方的代码比较乱,都写以main函数里,米联客教程init_intr_sys()函数完成总体中断系统的起,将法定demo中main函数DMA测试之前关于中断部分的代码全部卷入其中,包括DMA中断初始化,中断控制器初始化,使能暂停异常,连接DMA发送和吸纳中断,DMA中断而能五个经过。

图片 28

五、AXI总线信号ILA波形分析 

 AXI Stream主要接口:

  tdata:数据    tkeep:字节有效指示    tlast:帧尾指示    tready:准备就绪    tvalid:数据中指示

  MM2S方向要tvalid拉高则触发ILA抓到手信号波形。一帧数目来64单,每个数据32bit(4byte),一共正好呢C代码中MAX_PKT_LEN数值,即256byte。

图片 29

  中间他keep信号比较重大。如当stream位宽为16bit,传输数据量为255byte时常,tkeep信号在终极一个stream数据对应位置是2’b01指示第128个16bit数备受最后一个频繁之高字节为upsize过程遭到没用填充数据。

图片 30

  后续本人会采取System
Generator设计算法IP,之后并到IP
Integerator中作CPU外如果进行板级验证。继续读!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图