DMA的英文拼寫是「Direct Memory Access」,是一種數據不通過CPU處理,直接由DMA控制器從一塊物理內存搬運到另外一塊物理內存的數據交換模式。在DMA模式下,CPU只須向DMA控制器下達指令,讓DMA控制器來處理數據的傳送,數據傳送完畢再把信息反饋給CPU,這樣就很大程度上減輕了CPU資源佔有率,能夠大大節省系統資源。架構
SylixOS中的DMA架構位於「libsylixos/SylixOS/system/device/dma/」下,DMA驅動多用於外設驅動或總線驅動中。主要功能是從一塊物理地址向另外一塊物理地址搬運數據。本文以mini2440的通用DMA驅動爲例。函數
DMA設備庫對DMA設備進行了封裝,設備驅動僅須要提供初始化函數和回調函數便可。ui
在註冊DMA設備驅動以前,須要先安裝DMA設備庫,其原型如程序清單 2‑1:spa
程序清單 2‑1指針
#include <SylixOS.h>索引 INT API_DmaDrvInstall (UINT uiChannel,隊列 PLW_DMA_FUNCS pdmafuncs,內存 size_t stMaxDataBytes)ci |
函數API_DmaDrvInstall原型分析:資源
l 此函數執行成功返回PLW_DMA_FUNCS的地址。
DMA設備須要調用dmaGetFuncs函數綁定驅動並建立設備,其函數原型如程序清單 2‑2:
程序清單 2‑2
#include <SylixOS.h> PLW_DMA_FUNCS dmaGetFuncs (UINT iChannel, ULONG *pulMaxBytes) |
函數dmaGetFuncs原型分析:
l 此函數成功返回ERROR_NONE,失敗返回PX_ERROR;
l 參數iChannel:DMA通道號;
l 參數pulMaxBytes:最大傳輸字節數;
結構體PLW_DMA_FUNCS 詳細描述如程序清單 2‑3:
程序清單 2‑3
typedef struct lw_dma_funcs { VOID (*DMAF_pfuncReset)( UINT uiChannel, struct lw_dma_funcs *pdmafuncs); INT (*DMAF_pfuncTrans)( UINT uiChannel, struct lw_dma_funcs *pdmafuncs, PLW_DMA_TRANSACTION pdmatMsg); INT (*DMAF_pfuncStatus)(UINT uiChannel, Struct lw_dma_funcs *pdmafuncs); } LW_DMA_FUNCS; typedef LW_DMA_FUNCS *PLW_DMA_FUNCS; |
結構體中包含三個須要提供給DMA設備庫的操做函數,其功能分別是復位當前DMA操做、啓動一次DMA傳輸、得到當前DMA工做狀態。這三個函數的第一個傳入參數都是DMA的通道號,第二個參數都是指向DMA驅動結構體的指針。
使用回調函數的目的是將DMA設備庫中的結構體保存到驅動中以供緩衝區數據操做,所以在驅動結構體中須要提供三個變量以保存數據,示例如程序清單 2‑4:
程序清單 2‑4
typedef struct { … VOID (*DMAT_pfuncStart)(UINT uiChannel, PVOID pvArg); /* 啓動本次傳輸以前的回調*/
PVOID *DMAT_pvArg; /* 回調函數參數 */ VOID (*DMAT_pfuncCallback)(UINT uiChannel, PVOID pvArg); /* 本次傳輸完成後的回調函*/ … } LW_DMA_TRANSACTION; |
在LW_DMA_TRANSACTION結構體中除了一些DMA回調函數,還有一些重要的DMA參數,實例如程序清單 2‑5:
程序清單 2‑5
typedef struct { UINT8 *DMAT_pucSrcAddress; /* 源端緩衝區地址 */ UINT8 *DMAT_pucDestAddress; /* 目的端緩衝區地址 */ size_t DMAT_stDataBytes; /* 傳輸的字節數 */ INT DMAT_iSrcAddrCtl; /* 源端地址方向控制 */ INT DMAT_iDestAddrCtl; /* 目的地址方向控制 */ INT DMAT_iHwReqNum; /* 外設請求端編號 */ BOOL DMAT_bHwReqEn; /* 是否爲外設啓動傳輸*/ BOOL DMAT_bHwHandshakeEn; /* 是否使用硬件握手 * INT DMAT_iTransMode; /* 傳輸模式, 自定義 */ PVOID DMAT_pvTransParam; /* 傳輸參數, 自定義 */ ULONG DMAT_ulOption; /* 體系結構相關參數 */ PVOID DMAT_pvArgStart; /* 啓動回調參數 */ … (回調函數上小節已經單獨說明) } LW_DMA_TRANSACTION; typedef LW_DMA_TRANSACTION *PLW_DMA_TRANSACTION; |
DMA 操做的是物理地址, 因此 Src 和 Dest 地址均爲物理地址。有些系統 CPU 體系構架的 CACHE 是使用虛擬地址做爲索引的, 有些是使用物理地址作索引的。因此 DMA 軟件層不處理任何 CACHE 相關的操做, 將這些操做留給驅動程序或應用程序完成。
程序清單 2‑6
LW_API INT API_DmaDrvInstall(UINT uiChannel, PLW_DMA_FUNCS pdmafuncs, size_t stMaxDataBytes); /* 安裝指定通道的 DMA 驅動程序 */
LW_API INT API_DmaReset(UINT uiChannel); /* 復位指定的 DMA 通道 */
LW_API INT API_DmaJobNodeNum(UINT uiChannel, INT *piNodeNum); /* 得到當前隊列節點數 */
LW_API INT API_DmaMaxNodeNumGet(UINT uiChannel, INT *piMaxNodeNum); /* 得到最大隊列節點數 */
LW_API INT API_DmaMaxNodeNumSet(UINT uiChannel, INT iMaxNodeNum); /* 設置最大隊列節點數 */
LW_API INT API_DmaJobAdd(UINT uiChannel, PLW_DMA_TRANSACTION pdmatMsg); /* 添加一個 DMA 傳輸請求 */
LW_API INT API_DmaGetMaxDataBytes(UINT uiChannel); /* 得到一次能夠傳輸的最大字節數*/
LW_API INT API_DmaFlush(UINT uiChannel); /* 刪除全部被延遲處理的傳輸請求*/
/********************************************************************************************************* API 中斷服務函數 *********************************************************************************************************/
LW_API INT API_DmaContext(UINT uiChannel); /* DMA 傳輸完成後的中斷處理函數*/
#define dmaDrv API_DmaDrvInstall #define dmaReset API_DmaReset #define dmaMaxNodeNumGet API_DmaMaxNodeNumGet #define dmaMaxNodeNumSet API_DmaMaxNodeNumSet #define dmaJobAdd API_DmaJobAdd #define dmaGetMaxDataBytes API_DmaGetMaxDataBytes #define dmaFlush API_DmaFlush |
如程序清單 2‑6是SylixOS中內核定義的DMA模塊,具體函數使用方法和調用流程在下篇文章中會作詳細介紹。