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

2024-02-05 05:20

本文主要是介绍利用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\r\n");
 91         return XST_FAILURE;
 92     }
 93 
 94     xil_printf("XDMaPs_Example_W_Intr passed\r\n");
 95     return XST_SUCCESS;
 96 
 97 }
 98 #endif
 99 
100 
101 /*****************************************************************************/
102 /**
103  *
104  * Interrupt Example to test the DMA.
105  *
106  * @param    DeviceId is the Device ID of the DMA controller.
107  *
108  * @return    XST_SUCCESS to indicate success, otherwise XST_FAILURE.
109  *
110  * @note    None.
111  *
112  ****************************************************************************/
113 int XDmaPs_Example_W_Intr(XScuGic *GicPtr, u16 DeviceId)
114 {
115     int Index;
116     unsigned int Channel = 0;
117     int Status;
118     int TestStatus;
119     int TestRound;
120     int TimeOutCnt;
121     volatile int Checked[XDMAPS_CHANNELS_PER_DEV];
122     XDmaPs_Config *DmaCfg;
123     XDmaPs *DmaInst = &DmaInstance;
124     XDmaPs_Cmd DmaCmd;
125 
126     memset(&DmaCmd, 0, sizeof(XDmaPs_Cmd));
127 
128     DmaCmd.ChanCtrl.SrcBurstSize = 4;
129     DmaCmd.ChanCtrl.SrcBurstLen = 4;
130     DmaCmd.ChanCtrl.SrcInc = 1;
131     DmaCmd.ChanCtrl.DstBurstSize = 4;
132     DmaCmd.ChanCtrl.DstBurstLen = 4;
133     DmaCmd.ChanCtrl.DstInc = 1;
134     DmaCmd.BD.SrcAddr = (u32) Src;
135     DmaCmd.BD.DstAddr = (u32) Dst;
136     DmaCmd.BD.Length = DMA_LENGTH * sizeof(int);
137 
138 
139     /*
140      * Initialize the DMA Driver
141      */
142     DmaCfg = XDmaPs_LookupConfig(DeviceId);
143     if (DmaCfg == NULL) {
144         return XST_FAILURE;
145     }
146 
147     Status = XDmaPs_CfgInitialize(DmaInst,
148                    DmaCfg,
149                    DmaCfg->BaseAddress);
150     if (Status != XST_SUCCESS) {
151         return XST_FAILURE;
152     }
153 
154 
155     /*
156      * Setup the interrupt system.
157      */
158     Status = SetupInterruptSystem(GicPtr, DmaInst);
159     if (Status != XST_SUCCESS) {
160         return XST_FAILURE;
161     }
162 
163 
164     TestStatus = XST_SUCCESS;
165 
166     for (TestRound = 0; TestRound < TEST_ROUNDS; TestRound++) {
167         xil_printf("Test round %d\r\n", TestRound);
168         for (Channel = 0;
169              Channel < XDMAPS_CHANNELS_PER_DEV;
170              Channel++) {
171 
172 
173             /* Initialize source */
174             for (Index = 0; Index < DMA_LENGTH; Index++)
175                 Src[Index] = DMA_LENGTH - Index;
176 
177             /* Clear destination */
178             for (Index = 0; Index < DMA_LENGTH; Index++)
179                 Dst[Index] = 0;
180 
181             Checked[Channel] = 0;
182 
183             /* Set the Done interrupt handler */
184             XDmaPs_SetDoneHandler(DmaInst,
185                            Channel,
186                            DmaDoneHandler,
187                            (void *)Checked);
188 
189 
190             Status = XDmaPs_Start(DmaInst, Channel, &DmaCmd, 0);
191             if (Status != XST_SUCCESS) {
192                 return XST_FAILURE;
193             }
194 
195             TimeOutCnt = 0;
196 
197             /* Now the DMA is done */
198             while (!Checked[Channel]
199                    && TimeOutCnt < TIMEOUT_LIMIT) {
200                 TimeOutCnt++;
201             }
202 
203             if (TimeOutCnt >= TIMEOUT_LIMIT) {
204                 TestStatus = XST_FAILURE;
205             }
206 
207             if (Checked[Channel] < 0) {
208                 /* DMA controller failed */
209                 TestStatus = XST_FAILURE;
210             }
211         }
212     }
213 
214     return TestStatus;
215 
216 }
217 
218 
219 /******************************************************************************/
220 /**
221  *
222  * This function connects the interrupt handler of the interrupt controller to
223  * the processor.  This function is seperate to allow it to be customized for
224  * each application. Each processor or RTOS may require unique processing to
225  * connect the interrupt handler.
226  *
227  * @param    GicPtr is the GIC instance pointer.
228  * @param    DmaPtr is the DMA instance pointer.
229  *
230  * @return    None.
231  *
232  * @note    None.
233  *
234  ****************************************************************************/
235 int SetupInterruptSystem(XScuGic *GicPtr, XDmaPs *DmaPtr)
236 {
237     int Status;
238 #ifndef TESTAPP_GEN    
239     XScuGic_Config *GicConfig;
240 
241 
242     Xil_ExceptionInit();
243 
244     /*
245      * Initialize the interrupt controller driver so that it is ready to
246      * use.
247      */
248     GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID);
249     if (NULL == GicConfig) {
250         return XST_FAILURE;
251     }
252 
253     Status = XScuGic_CfgInitialize(GicPtr, GicConfig,
254                        GicConfig->CpuBaseAddress);
255     if (Status != XST_SUCCESS) {
256         return XST_FAILURE;
257     }
258 
259     /*
260      * Connect the interrupt controller interrupt handler to the hardware
261      * interrupt handling logic in the processor.
262      */
263     Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT,
264                  (Xil_ExceptionHandler)XScuGic_InterruptHandler,
265                  GicPtr);
266 #endif
267     /*
268      * Connect the device driver handlers that will be called when an interrupt
269      * for the device occurs, the device driver handler performs the specific
270      * interrupt processing for the device
271      */
272 
273     /*
274      * Connect the Fault ISR
275      */
276     Status = XScuGic_Connect(GicPtr,
277                  DMA_FAULT_INTR,
278                  (Xil_InterruptHandler)XDmaPs_FaultISR,
279                  (void *)DmaPtr);
280     if (Status != XST_SUCCESS) {
281         return XST_FAILURE;
282     }
283 
284     /*
285      * Connect the Done ISR for all 8 channels of DMA 0
286      */
287     Status = XScuGic_Connect(GicPtr,
288                  DMA_DONE_INTR_0,
289                  (Xil_InterruptHandler)XDmaPs_DoneISR_0,
290                  (void *)DmaPtr);
291     Status |= XScuGic_Connect(GicPtr,
292                  DMA_DONE_INTR_1,
293                  (Xil_InterruptHandler)XDmaPs_DoneISR_1,
294                  (void *)DmaPtr);
295     Status |= XScuGic_Connect(GicPtr,
296                  DMA_DONE_INTR_2,
297                  (Xil_InterruptHandler)XDmaPs_DoneISR_2,
298                  (void *)DmaPtr);
299     Status |= XScuGic_Connect(GicPtr,
300                  DMA_DONE_INTR_3,
301                  (Xil_InterruptHandler)XDmaPs_DoneISR_3,
302                  (void *)DmaPtr);
303     Status |= XScuGic_Connect(GicPtr,
304                  DMA_DONE_INTR_4,
305                  (Xil_InterruptHandler)XDmaPs_DoneISR_4,
306                  (void *)DmaPtr);
307     Status |= XScuGic_Connect(GicPtr,
308                  DMA_DONE_INTR_5,
309                  (Xil_InterruptHandler)XDmaPs_DoneISR_5,
310                  (void *)DmaPtr);
311     Status |= XScuGic_Connect(GicPtr,
312                  DMA_DONE_INTR_6,
313                  (Xil_InterruptHandler)XDmaPs_DoneISR_6,
314                  (void *)DmaPtr);
315     Status |= XScuGic_Connect(GicPtr,
316                  DMA_DONE_INTR_7,
317                  (Xil_InterruptHandler)XDmaPs_DoneISR_7,
318                  (void *)DmaPtr);
319 
320     if (Status != XST_SUCCESS)
321         return XST_FAILURE;
322 
323     /*
324      * Enable the interrupts for the device
325      */
326     XScuGic_Enable(GicPtr, DMA_DONE_INTR_0);
327     XScuGic_Enable(GicPtr, DMA_DONE_INTR_1);
328     XScuGic_Enable(GicPtr, DMA_DONE_INTR_2);
329     XScuGic_Enable(GicPtr, DMA_DONE_INTR_3);
330     XScuGic_Enable(GicPtr, DMA_DONE_INTR_4);
331     XScuGic_Enable(GicPtr, DMA_DONE_INTR_5);
332     XScuGic_Enable(GicPtr, DMA_DONE_INTR_6);
333     XScuGic_Enable(GicPtr, DMA_DONE_INTR_7);
334     XScuGic_Enable(GicPtr, DMA_FAULT_INTR);
335 
336     Xil_ExceptionEnable();
337 
338     return XST_SUCCESS;
339 
340 }
341 
342 
343 /*****************************************************************************/
344 /**
345 *
346 * DmaDoneHandler.
347 *
348 * @param    Channel is the Channel number.
349 * @param    DmaCmd is the Dma Command.
350 * @param    CallbackRef is the callback reference data.
351 *
352 * @return    None.
353 *
354 * @note        None.
355 *
356 ******************************************************************************/
357 void DmaDoneHandler(unsigned int Channel, XDmaPs_Cmd *DmaCmd, void *CallbackRef)
358 {
359 
360     /* done handler */
361     volatile int *Checked = (volatile int *)CallbackRef;
362     int Index;
363     int Status = 1;
364     int *Src;
365     int *Dst;
366 
367     Src = (int *)DmaCmd->BD.SrcAddr;
368     Dst = (int *)DmaCmd->BD.DstAddr;
369 
370     /* DMA successful */
371     /* compare the src and dst buffer */
372     for (Index = 0; Index < DMA_LENGTH; Index++) {
373         if ((Src[Index] != Dst[Index]) ||
374                 (Dst[Index] != DMA_LENGTH - Index)) {
375             Status = -XST_FAILURE;
376         }
377     }
378 
379 
380     Checked[Channel] = Status;
381 }
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\n");
118     Checked[Channel] = Status;
119 }
120 
121 void PS_DMA_InitPara(XDmaPs_Cmd* DmaCmd)
122 {
123 
124     memset(DmaCmd, 0, sizeof(XDmaPs_Cmd));
125 
126     DmaCmd->ChanCtrl.SrcBurstSize = 4;
127     DmaCmd->ChanCtrl.SrcBurstLen = 4;
128     DmaCmd->ChanCtrl.SrcInc = 1;
129     DmaCmd->ChanCtrl.DstBurstSize = 4;
130     DmaCmd->ChanCtrl.DstBurstLen = 4;
131     DmaCmd->ChanCtrl.DstInc = 1;
132     DmaCmd->BD.SrcAddr = (u32) Src;
133     DmaCmd->BD.DstAddr = (u32) DDR_BASEADDR;//Dst
134     DmaCmd->BD.Length = DMA_LENGTH * sizeof(int);
135 }
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\r\n");
 47             return XST_FAILURE;
 48         }
 49 
 50     Status = PS_DMA_WriteTest();
 51     if (Status != XST_SUCCESS) {
 52         xil_printf("Error: XDMaPs_Example_W_Intr failed\r\n");
 53         return XST_FAILURE;
 54     }
 55     xil_printf("Checking data...\n");
 56     Status = dataCheck(DDR_BASEADDR,DMA_LENGTH);
 57     if(Status != XST_SUCCESS)
 58     {
 59         xil_printf("Error:check failed\n");
 60         return XST_FAILURE;
 61     }
 62 
 63     xil_printf("Writing data to DDR using DMA test passed!\r\n");
 64     return XST_SUCCESS;
 65 
 66 }
 67 
 68 int dataCheck(u32 baseAddr,u32 len)
 69 {
 70     u32 DDR_ReadData[1024];
 71     int i;
 72     for(i=0;i<len;i++)
 73     {
 74         DDR_ReadData[i] = Xil_In32(baseAddr+i*4);
 75         if(DDR_ReadData[i]!=Src[i])
 76             return XST_FAILURE;
 77         //else  //将写入DDR数据读回 并打印
 78         //    xil_printf("data at %x is %d\n",baseAddr+i*4,DDR_ReadData[i]);
 79     }
 80     return XST_SUCCESS;
 81 }
 82 
 83 
 84 /*****************************************************************************/
 85 /**
 86  *
 87  * Interrupt Example to test the DMA.
 88  *
 89  * @param    DeviceId is the Device ID of the DMA controller.
 90  *
 91  * @return    XST_SUCCESS to indicate success, otherwise XST_FAILURE.
 92  *
 93  * @note    None.
 94  *
 95  ****************************************************************************/
 96 int PS_DMA_WriteTest()
 97 {
 98     int Index;
 99     int Status;
100     int TestStatus;
101     int TestRound;
102     int TimeOutCnt;
103 
104     TestStatus = XST_SUCCESS;
105 
106     for (TestRound = 0; TestRound < TEST_ROUNDS; TestRound++) {
107         xil_printf("Test round %d\r\n", TestRound);
108         for (Channel = 0;Channel < 1;Channel++)
109         {
110             /* Initialize source */
111             for (Index = 0; Index < DMA_LENGTH; Index++)
112                 Src[Index] = DMA_LENGTH - Index;
113 
114             Checked[Channel] = 0;
115 
116             Status = XDmaPs_Start(&DmaInstance, Channel, &DmaCmd, 0);
117             if (Status != XST_SUCCESS) {
118                 xil_printf("Starting the DMA is failed.\n");
119                 return XST_FAILURE;
120             }
121             xil_printf("Starting the DMA is successful.\n");
122             TimeOutCnt = 0;
123 
124             while (!Checked[Channel]
125                    && TimeOutCnt < TIMEOUT_LIMIT) {
126                 TimeOutCnt++;
127             }
128             /* Now the DMA is done */
129             xil_printf("Jump out of the interrupt\n");
130             if (TimeOutCnt >= TIMEOUT_LIMIT) {
131                 xil_printf("Overtime!\n");
132                 TestStatus = XST_FAILURE;
133             }
134 
135             if (Checked[Channel] < 0) {
136                 /* DMA controller failed */
137                 xil_printf("Checking failure!\n");
138                 TestStatus = XST_FAILURE;
139             }
140         }
141     }
142 
143     return TestStatus;
144 
145 }
146 
147 int systemInit(XScuGic *GicPtr,u16 DeviceId)
148 {
149     xil_printf("Start to initialize interrupt system.\n");
150 
151     PS_DMA_InitPara(&DmaCmd);//主要设置DMA的源目的地址
152     //xil_printf("Configuring DMA parameters is successful.\n");
153 
154     int Status;
155 
156     Status = PS_DMA_IntrInit(&DmaInstance,DeviceId);
157     if (Status != XST_SUCCESS) {
158             xil_printf("DMA initialization is failed.\n");
159             return XST_FAILURE;
160         }
161     //xil_printf("DMA initialization is successful.\n");
162 
163     Status = sys_IntrInit(GicPtr);
164     if (Status != XST_SUCCESS) {
165             xil_printf("Initialization of the interrupt system  is failed.\n");
166             return XST_FAILURE;
167         }
168     //xil_printf("Initialization of the interrupt system  is successful.\n");
169 
170     setupIntrException(GicPtr);
171 
172     Status = PS_DMA_SetupIntr(GicPtr,&DmaInstance,Channel);//DMA中断入口///
173     if (Status != XST_SUCCESS) {
174         xil_printf("Setting up DMA interrupt is failed.\n");
175         return XST_FAILURE;
176     }
177     //xil_printf("Setting up DMA interrupt is successful.\n");
178 
179     xil_printf("System initialization is finished.\n");
180     xil_printf("------------------------------------------\n");
181     return XST_SUCCESS;
182 }
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架构的性能瓶颈,该部分内容将在后续说明。

转载于:https://www.cnblogs.com/moluoqishi/p/9372065.html

这篇关于利用ZYNQ SOC快速打开算法验证通路(3)——PS端DMA缓存数据到PS端DDR的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/679845

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int