c/c++语言开发共享利用ZYNQ SOC快速打开算法验证通路(4)——AXI DMA使用解析及环路测试

一、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("rn--- entering main() --- rn"); 260  261     config = xaxidma_lookupconfig(dma_dev_id); 262     if (!config) { 263         xil_printf("no config found for %drn", 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 %drn", status); 273         return xst_failure; 274     } 275  276     if(xaxidma_hassg(&axidma)){ 277         xil_printf("device configured as sg mode rn"); 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 setuprn"); 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 donern", 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 failedrn"); 366             goto done; 367         } 368     } 369  370  371     xil_printf("axi dma interrupt example test passedrn"); 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() --- rn"); 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/%xrn", 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 intcrn"); 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 intcrn"); 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 intcrn"); 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 intcrn"); 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外设进行板级验证。继续学习!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/608272.html

(0)
上一篇 2021年5月15日
下一篇 2021年5月15日

精彩推荐