欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-04-16 09:09:53
一、AXI DMA介绍 本篇博文讲述AXI DMA的一些使用总结,硬件IP子系统搭建与SDK C代码封装参考米联客ZYNQ教程。若想让ZYNQ的PS与PL两部分高速数据传输,需要利用PS的HP(高性能)接口通过AXI_DMA完成数据搬移,这正符合PG021 AXI DMA v7.1 LogiCORE ......

一、axi dma介绍

  本篇博文讲述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.

  如图,axi dma主要包括memory map和 stream两部分接口,前者连接ps子系统,后者则连接带有流接口的pl ip核。

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

  其最简单的事直接寄存器模式(simple dma),这里需要注意地址对齐的问题:当没有使能地址重对齐的情况下,如果axi memory map数据位宽是32bit,则搬移数据所在地址必须在0x0,0x4,0x8等起始地址上。接下来关注dma ip核配置界面主要参数:

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

  重点查看以下几个参数:

1 width of buffer length register:

  在直接寄存器模式下,它指定在mm2s_length和s2mm_length寄存器的有效比特数。mm2s_length寄存器指定了mm2s通道传输数据字节数,当cpu写入非零值时开始进行ps到pl的数据搬移,而s2mm_length对应另一个数据流方向。比特数直接与对应寄存器可写入的最大数直接相关,传输最大字节数= 2^(width of buffer length register)。此处保持默认14bit,也就是说启动dma传输的最大数据量是16384byte。

2 memory map data width:

  该参数指定了memory map侧数据接口宽度,选定32bit后搬移数据所在内存地址必须与4对齐。

3 max burst size:

  之前在讲解ps子系统内部的dma时介绍过dma的burst概念,即分批次传输数据块。此处没有完全看明白手册的介绍,猜想是每次传输的最大数据个数。

 二、axi dma loop ip子系统

  在利用zynq搭建系统时,经常需要利用各种ip核做所谓的“计算加速”,将重复性高 计算量大 占用较大cpu资源的底层处理交给各个ip核完成。这时ps ->dma ->pl -> dma -> ps的环路架构非常适用。这里使用axi stream data fifo代替自定义ip核作为演示,硬件ip子系统如下:

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

 三、sdk 官方demo解析

  首先分析下官方的demo。利用ZYNQ SOC快速打开算法验证通路(4)——AXI DMA使用解析及环路测试

利用ZYNQ SOC快速打开算法验证通路(4)——AXI DMA使用解析及环路测试
  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 }
xaxidma_example_simple_intr.c

 主函数中依次完成了:dma初始化,建立中断系统,使能dma中断,初始化标志位及发送数据,启动dma传输以及数据检测。中断部分的内容与ps dma非常相近,传输完成后进入的中断函数中仅置位了发送或接收完成标志位:

利用ZYNQ SOC快速打开算法验证通路(4)——AXI DMA使用解析及环路测试
  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 }
intrhandler

   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核,该侧“地址”由硬件连接决定。利用ZYNQ SOC快速打开算法验证通路(4)——AXI DMA使用解析及环路测试

  再来看看搬移数据内存首地址rxbufferptr和txbufferptr.从下边的定义可见mem_base_addr是ddr_base_addr加上一段偏移量的结果,ddr基地址数值从xparameters.h中查看。

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

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

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

四、函数重用封装

  官方的代码比较乱,都写在main函数里,米联客教程init_intr_sys()函数完成整个中断系统的建立,将官方demo中main函数dma测试之前关于中断部分的代码全部封装其中,包括dma中断初始化,中断控制器初始化,使能中断异常,连接dma发送与接收中断,dma中断使能五个过程。

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

五、axi总线信号ila波形分析 

 axi stream主要接口:

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

  一帧数据有64个,每个数据32bit(4byte),一共正好为c代码中max_pkt_len数值,即256byte。

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

  在pl->dma->ps方向上,检测tvalid上升沿拉高则触发ila抓取信号波形。观察到一个奇怪的现象,发现dma在接收几个数据后拉低ready信号停止接收数据,一段时间后再次拉高继续接收。暂时还不清楚原因,希望知道的朋友指点一二。

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

  

  后续本人会利用system generator设计算法ip,之后集成到ip integerator中作为cpu外设进行板级验证。继续学习!