• 利用ZYNQ SOC快速打开算法验证通路(3)——PS端DMA缓存数据到PS端DDR


      上篇该系列博文中讲述W5500接收到上位机传输的数据,此后需要将数据缓存起来。当数据量较大或者其他数据带宽较高的情况下,片上缓存(OCM)已无法满足需求,这时需要将大量数据保存在外挂的DDR SDRAM中。

      最简单的方式是使用Xilinx的读写地址库函数Xil_In32()和Xil_Out32(),当然不仅支持32bit位宽,还包括8 16和64bit。但这种方式每次读写都要占用CPU,无法在读写的同时接收后续数据或者对之前的数据进一步处理,也就无法形成类似FPGA逻辑设计中的“流水线结构”,此时前段数据缓存过程中,后段数据会被丢弃。所以,需要利用PS端CPU子系统内的专用硬件DMA完成高速的批量数据搬移工作。

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

      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
    ");
     91         return XST_FAILURE;
     92     }
     93 
     94     xil_printf("XDMaPs_Example_W_Intr passed
    ");
     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
    ", 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 }
    ps_dma_demo

       其实demo中做的操作非常简单,仅仅是定义了两个数组Src和Dst,之后利用PS_DMA将Src中数据搬移到Dst中,搬移完成后进入中断函数比较两部分地址数据是否一致。Xilinx的SDK软件代码有固定的套路,“上有政策,下有对策”,我们可以将其封装成固定格式的一个个子函数,方便今后调用。这里把整个工程分为:系统中断,PS_DMA专有中断以及主函数三个部分。

     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 }
    sys_intr.c
    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_ */
    sys_intr.h
      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
    ");
    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 }
    psdma_intr.c
     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_ */
    psdma_intr.h
      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
    ");
     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
    ");
     53         return XST_FAILURE;
     54     }
     55     xil_printf("Checking data...
    ");
     56     Status = dataCheck(DDR_BASEADDR,DMA_LENGTH);
     57     if(Status != XST_SUCCESS)
     58     {
     59         xil_printf("Error:check failed
    ");
     60         return XST_FAILURE;
     61     }
     62 
     63     xil_printf("Writing data to DDR using DMA test passed!
    ");
     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
    ",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
    ", 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.
    ");
    119                 return XST_FAILURE;
    120             }
    121             xil_printf("Starting the DMA is successful.
    ");
    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
    ");
    130             if (TimeOutCnt >= TIMEOUT_LIMIT) {
    131                 xil_printf("Overtime!
    ");
    132                 TestStatus = XST_FAILURE;
    133             }
    134 
    135             if (Checked[Channel] < 0) {
    136                 /* DMA controller failed */
    137                 xil_printf("Checking failure!
    ");
    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.
    ");
    150 
    151     PS_DMA_InitPara(&DmaCmd);//主要设置DMA的源目的地址
    152     //xil_printf("Configuring DMA parameters is successful.
    ");
    153 
    154     int Status;
    155 
    156     Status = PS_DMA_IntrInit(&DmaInstance,DeviceId);
    157     if (Status != XST_SUCCESS) {
    158             xil_printf("DMA initialization is failed.
    ");
    159             return XST_FAILURE;
    160         }
    161     //xil_printf("DMA initialization is successful.
    ");
    162 
    163     Status = sys_IntrInit(GicPtr);
    164     if (Status != XST_SUCCESS) {
    165             xil_printf("Initialization of the interrupt system  is failed.
    ");
    166             return XST_FAILURE;
    167         }
    168     //xil_printf("Initialization of the interrupt system  is successful.
    ");
    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.
    ");
    175         return XST_FAILURE;
    176     }
    177     //xil_printf("Setting up DMA interrupt is successful.
    ");
    178 
    179     xil_printf("System initialization is finished.
    ");
    180     xil_printf("------------------------------------------
    ");
    181     return XST_SUCCESS;
    182 }
    main.c

      上述代码的封装方式参考了米联客教程中的思想。先说明系统中断部分:sys_IntrInit()函数中进行查找表配置和中断控制器初始化操作,setupIntrException()函数负责使能中断异常处理。再来说说PS_DMA中断部分:PS_DMA_IntrInit()函数与系统中断中sys_IntrInit()从操作到格式几乎完成相同,亦是查找表配置和DMA的初始化。PS_DMA_SetupIntr()函数完成了中断源和中断控制器的连接和设置中断处理器,以及中断使能,也就是所有PS_DMA的专用中断操作。

      PS_DMA_SetupIntr()内最重要的部分是XDmaPs_SetDoneHandler(),其相当于一个调用中断函数的通用处理框架,它的第三个参数DoneHandler才是真正的中断处理函数。这里涉及到C语言的高级话题:函数通过函数指针调用另一个函数,被函数指针调用的函数就是通常讲的“回调函数”了。指针调用函数的方式兼顾了程序的通用架构和灵活性,具体参考文章:不懂C语言回调函数,那就看这篇文章吧! - 简书 https://www.jianshu.com/p/2f695d6fd64f  在该程序中,中断回调函数为DmaDoneHandler()。

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

      简要来说,DMA以burst形式传输数据,意思是分批次搬移。手册说明原或目的burst_size位宽不能超过64bit,这也是其挂载AXI总线的数据位宽。PS_DMA_InitPara()里的SrcBurstSize为源突发传输位宽字节数,最大为8.SrcBurstLen是手册中所说的“burst length”,即突发传输数据个数。SrcInc表示burst types为地址自增(1)还是地址固定(0)模式。目的控制字同理。剩下的三个参数最重要:SrcAddr DstAddr Length分别代表源首地址 目的首地址和一共需要搬移的数据字节数。需要注意的是,一定要满足srcburstsize*srcburstlen == dstburstsize*dstburstlen,否则发生错误。这一点也比较好理解,相当于FPGA逻辑设计中的异步FIFO两侧数据带宽要匹配。

       那么要想完成OCM到DDR的数据搬移,改动下地址就可以嘛。由于读写DDR要访问绝对地址,所以要格外注意读写操作的地址不能和DDR内存储程序代码和中间数据的地址段重叠。避免程序崩溃很简单的做法就是在XPAR_PS7_DDR_0_S_AXI_BASEADDR 的基础上加一段偏移量,具体加多少的问题本人也不是很明确,希望看到的朋友能在评论中指点一二。

      明确了PS_DMA的参数和使用方式,还有一点非常重要:PS_DMA的工作时钟是多少?这就需要继续看ug585了。

      DMA控制器工作在CPU_2*时钟速率下,那这个CPU_2*的频率值具体是多少呢?

      从上表可以看出,CPU的时钟系统有两种时钟比例关系,分别是:6:2:1和4:2:1。对应的时钟名称依次是:CPU_6*4* CPU_3*2* CPU_2* CPU_1*。后边的N*就是该时钟频率与CPU_1*的频率的倍数。确定CPU_6*4*的数值和当前的时钟比例关系,也就确定了其他时钟的频率。PS_CLK频率与PLL Feedback Divider Value值相乘得到ARM PLL output frequency。之后经过二分频获得CPU_6*4*。在IP Integrator中打开ZYNQ的时钟配置界面:

      当前使用时钟比例关系是6:2:1,PLL时钟频率是1333.333MHz,也就是CPU_6*4*的频率是1333.33/2=667MHz。综上,DMA的工作时钟CPU_2*的频率值是667/3=222MHz。

      对于ZYNQ这一SOC架构来说,PS端连接如以太网,USB等高带宽外设计接口更加方便,所以PS_DMA的灵活运用还好是十分必要的,更灵活高效的利用这一硬件资源还要后期继续探索。PS端和PL端高速数据交互就需要用到另一个DMA成员AXI_DMA,可以说它利用片内总线打破了CPU+FPGA架构的性能瓶颈,该部分内容将在后续说明。

  • 相关阅读:
    Linux 安装 jdk 后 jps 出现问题/usr/jdk1.8.0_151/bin/jps: /lib/ld-linux.so.2: bad ELF interpreter: No such
    Jackson 注解
    Git 右键添加Git Bash
    No validator could be found for constraint
    rror querying database. Cause: java.sql.SQLException: null, message from server: "Host '192.168.30.1' is not allowed to connect to this MySQL server"
    Linux 安装 Mysql-5.7.23-linux-glibc2
    Promise
    PAT(B) 1094 谷歌的招聘(Java)
    PAT(B) 1074 宇宙无敌加法器(Java)
    PAT(B) 1078 字符串压缩与解压(Java)
  • 原文地址:https://www.cnblogs.com/moluoqishi/p/9372065.html
Copyright © 2020-2023  润新知