ZYNQ從放棄到入門(九)-PS和PL交互-DMA
我們上一節談到使用 DMA(直接內存訪問)的好處已經變得顯而易見。到了這一步,我們留下了人類長期以來一直在思考的問題:DMA到底是什么?
DMA介紹
在最基本的層面上,一旦處理器設置了傳輸,DMA 將數據傳入或傳出內存而無需CPU干預。DMA 可以顯著提高系統性能,具體取決于所采用的方法。在我們更詳細地了解 Zynq DMA 之前,我想先解釋一些 DMA 控制器的通用原理。通常 DMA 控制器以以下三種模式之一運行:
- Burst Mode突發模式 - 在一次連續操作中傳輸整個數據塊。在許多應用中,突發模式傳輸時拒絕總線訪問處理器。這種模式好與壞還是取決于系統。
- Cycle Stealing – 為了克服上訴的不足,DMA支持Cycle Stealing將單個 DMA 字節或字傳輸與處理器訪問系統總線交錯運行。
- 透明模式——最有效的模式。僅當處理器執行不需要訪問系統總線的任務時才傳輸數據。
DMA 控制器的一項非常有用的功能是支持分散/收集(scatter/gather)操作的能力。此功能允許將多個數據源傳輸到單個目標地址或允許單個源地址提供多個輸出目標(也稱為“緩沖區”)。Zynq SoC 的基于 ARM 的處理系統 (PS) 有一個 DMA 控制器 (DMAC),它連接到 Zynq 的 AXI4 互連并使用 AXI 總線執行傳輸。DMAC 在系統存儲器和 Zynq 的可編程邏輯 (PL) 之間采用 64 位 AXI 傳輸。如下所示,Zynq DMAC 有 8 個通道,允許 DMAC 同時執行 8 個 DMA 線程,并通過 AXI 互連實現流控制。
雖然 Zynq DMAC 允許在系統存儲器和 PL(包括 PL 中的 Zynq 外設)之間進行雙向傳輸,但它不支持 Zynq PS 中的外設的 DMA,因為這些外設沒有流控制信號來支持 DMA 操作。然而,Zynq SoC 中的一些 IO 外設具有自己的 DMA 控制器,以支持進出 IOP 和系統內存的高數據速率傳輸。這些外圍設備是:
- GigE Controller 千兆以太網控制器
- SDIO Controller SDIO 控制器
- USB Controller USB控制器
- Device Configuration Controller 設備配置控制器
如果設備使用 ARM TrustZone,Zynq SoC 還支持安全寄存器訪問。Xilinx 同時也提供了一個簡單的驅動程序文件 (xdmaps.h),我們可以在獨立 BSP 中使用它來配置和啟動 DMA 傳輸。在下一節中,我們將了解如何使用此文件創建簡單的 DMA 傳輸。
示例演示
本節創建一個非常簡單的示例來演示如何設置和使用 DMA。
為了演示這示例,將使用一個 DMA 控制器通道將一個內存位置傳輸到另一個內存位置。
首先需要在BSP中包含一部分Vivado中生成的頭文件。這些頭文件提供了我們可以用來驅動 DMA 的宏和函數。對于這個例子,我們需要包括:
#include"xscugic.h"
#include"xdmaps.h"
#include"xil_exception.h"
Xscugic.h 和 xil_exceptions.h 允許使用中斷控制器,而 xdmaps.h 允許配置并使用DMA。
使用 xparamters.h 提供的參數,我們可以定義 DMA 和中斷控制器的設備標識、將使用的中斷以及我們將傳輸的數據長度:
#defineDMA_DEVICE_IDXPAR_XDMAPS_1_DEVICE_ID
#defineINTC_DEVICE_IDXPAR_SCUGIC_SINGLE_DEVICE_ID
#defineDMA_FAULT_INTRXPAR_XDMAPS_0_FAULT_INTR
#defineDMA_DONE_INTR_0XPAR_XDMAPS_0_DONE_INTR_0
#defineDMA_LENGTH1024
開發的下一階段是編寫三個函數來配置DMA,配置中斷控制器,并在DMA傳輸完成時充當中斷服務程序。
在 DMA 配置函數中,我們首先使用 xdmaps.h 提供的命令結構創建一個 DMA 命令。DMA 命令由通道控制、塊描述符、用戶定義的程序、指向生成的程序的指針和傳輸結果組成。由于這是一個簡單的示例,我們不需要所有這些組件,但是我們將配置 DMA 控制器,如下所示:
DmaCmd.ChanCtrl.SrcBurstSize=4;
DmaCmd.ChanCtrl.SrcBurstLen=4;
DmaCmd.ChanCtrl.SrcInc=1;
DmaCmd.ChanCtrl.DstBurstSize=4;
DmaCmd.ChanCtrl.DstBurstLen=4;
DmaCmd.ChanCtrl.DstInc=1;
DmaCmd.BD.SrcAddr=(u32)Src;
DmaCmd.BD.DstAddr=(u32)Dst;
DmaCmd.BD.Length=DMA_LENGTH*sizeof(int);
下一步設置運行中斷函數以將 DMA 中斷連接到中斷控制器之前初始化和配置 DMA 控制器:
DmaCfg=XDmaPs_LookupConfig(DeviceId);
XDmaPs_CfgInitialize(DmaInst,DmaCfg,DmaCfg->BaseAddress);
SetupInterrupt(&GicInstance,DmaInst);
在此之后,在我們連接完成處理程序并開始傳輸之前,源內存位置被設置并清除目標位置,為了跟蹤進度,我們還調用了 DMA 進度函數:
DmaCfg=XDmaPs_LookupConfig(DeviceId);
XDmaPs_CfgInitialize(DmaInst,DmaCfg,DmaCfg->BaseAddress);
SetupInterrupt(&GicInstance,DmaInst);
XDmaPs_Print_DmaProg(&DmaCmd);
當附加的源代碼文件在ZYNQ上運行時,以下結果顯示串口輸出上。
源碼:
https://gitee.com/openfpga/zynq-chronicles/blob/master/part_29.c
原文標題:ZYNQ從放棄到入門(九)-DMA
文章出處:【微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
-
控制器
+關注
關注
112文章
16434瀏覽量
178965 -
dma
+關注
關注
3文章
566瀏覽量
100815 -
Zynq
+關注
關注
10文章
610瀏覽量
47249
原文標題:ZYNQ從放棄到入門(九)-DMA
文章出處:【微信號:Open_FPGA,微信公眾號:OpenFPGA】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論