DMA 设备驱动模型

更新时间:
2024-01-09
下载文档

DMA 设备驱动模型

DMA 驱动模型简介

SylixOS 中的 DMA 相关驱动代码位于“libsylixos/SylixOS/system/device/dma/”目录下,DMA 驱动多用于外设驱动或总线驱动中。主要功能是从一块物理地址向另一块物理地址搬运数据。本文以 S3C2440 通用 DMA 驱动为例。

DMA 设备库对 DMA 设备进行了封装,设备驱动仅需要提供初始化函数和回调函数即可。

用户在注册 DMA 设备驱动之前,需要先调用 API_DmaDrvInstall 函数安装 DMA 设备库,此函数的功能是向系统内核加载一个 DMA 驱动。用户需在配置好 DMA 控制器之后,调用此函数把驱动加载到内核中。其原型如下:

#include <SylixOS.h>
INT    API_DmaDrvInstall (UINT                 uiChannel,
                          PLW_DMA_FUNCS        pdmafuncs,
                          size_t               stMaxDataBytes)

函数 API_DmaDrvInstall 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。
  • 参数 pdmafuncs 是 DMA 驱动加载函数。
  • 参数 stMaxDataBytes 是 DMA 驱动最大传输字节数。

DMA 设备需要调用 dmaGetFuncs 函数绑定驱动并创建设备,其函数原型如下:

#include <SylixOS.h>
PLW_DMA_FUNCS    dmaGetFuncs (UINT            iChannel, 
                              ULONG            *pulMaxBytes)

函数 dmaGetFuncs 原型分析:

  • 此函数成功返回 PLW_DMA_FUNCS ,失败返回 PX_ERROR
  • 参数 iChannel 是 DMA 通道号。
  • 参数 pulMaxBytes 是 DMA 驱动最大传输字节数。

结构体 PLW_DMA_FUNCS 详细描述如下:

#include <SylixOS.h>
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;
  • 参数 DMAF_pfuncReset 是复位 DMA 当前的操作。
  • 参数 DMAF_pfuncTrans 是启动一次 DMA 传输。
  • 参数 DMAF_pfuncStatus 是获得 DMA 当前的工作状态。

结构体中包含三个需要提供给 DMA 设备库的操作函数,其功能分别是复位当前 DMA 操作、启动一次 DMA 传输、获得当前 DMA 工作状态。这三个函数需要驱动程序根据不同的硬件去具体实现。

DMA 回调函数

DMA 驱动支持用户创建自己的回调函数来实现相应的操作。用户可根据实际情况自行添加或删除回调函数,示例如下:

#include <SylixOS.h>
typedef struct {

    VOID   (*DMAT_pfuncStart)(UINT        uiChannel,
                              PVOID        pvArg);            /* 启动本次传输之前的回调    */
    PVOID  *DMAT_pvArg;                                       /* 回调函数参数            */
    VOID   (*DMAT_pfuncCallback)(UINT        uiChannel,
                                 PVOID        pvArg);         /* 本次传输完成后的回调函    */

} LW_DMA_TRANSACTION;
  • 参数 DMAT_pfuncStart 是启动本次传输之前的回调。
  • 参数 DMAT_pvArg 是回调函数参数。
  • 参数 DMAT_pfuncCallback 是本次传输完成后的回调。

启动一次 DMA 传输前后,如果需要处理其他事务,可自行填充回调函数,进行相关操作。

DMA 传输参数

LW_DMA_TRANSACTION 结构体中除了一些 DMA 回调函数,还有一些重要的 DMA 参数,结构体定义如下:

#include <SylixOS.h>
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;
  • 参数 DMAT_pucSrcAddress 是 DMA 源端缓冲区地址。
  • 参数 DMAT_pucDestAddress 是 DMA 目的端缓冲区地址。
  • 参数 DMAT_stDataBytes 是 DMA 传输的字节数。
  • 参数 DMAT_iSrcAddrCtl 是 DMA 源端地址方向控制。
  • 参数 DMAT_iDestAddrCtl 是 DMA 目的地址方向控制。
  • 参数 DMAT_iHwReqNum 是外设请求端编号。
  • 参数 DMAT_bHwReqEn 是 DMA 是否为外设启动传输。
  • 参数 DMAT_bHwHandshakeEn 是 DMA 是否使用硬件握手。
  • 参数 DMAT_iTransMode 是传输模式,自定义。
  • 参数 DMAT_pvTransParam 是传输参数,自定义。
  • 参数 DMAT_ulOption 是体系结构相关参数。
  • 参数 DMAT_pvArgStart 是启动回调参数。

DMA 操作的是物理地址,所以 Src 和 Dest 地址均为物理地址。有些系统CPU体系架构的CACHE是使用虚拟地址作为索引的,有些是使用物理地址做索引的。

DMA 函数简介

SylixOS 内核中提供很多有关 DMA 操作的内核函数。除 API_DmaDrvInstall 函数是在驱动加载中调用,其余的函数可在 DMA 驱动挂载到内核完成之后调用。用户也可在其他驱动中调用相关函数来控制已经加载的 DMA 驱动完成相关操作。系统内核函数无需用户编写,包含对应头文件传入正确的参数即可使用。

API_DmaReset 函数实现复位制定的 DMA 通道,函数如下:

#include <SylixOS.h>
INT     API_DmaReset(UINT    uiChannel);    

函数 API_DmaReset 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。

API_DmaJobNodeNum 函数可获得当前队列节点数,函数如下:

#include <SylixOS.h>
INT     API_DmaJobNodeNum(UINT         uiChannel, 
                          INT         *piNodeNum);                 

函数 API_DmaJobNodeNum 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。
  • 参数 piNodeNum 是 DMA 驱动函数节点号。

API_DmaMaxNodeNumGet 函数可获得最大队列节点数,函数如下:

#include <SylixOS.h>
INT     API_DmaMaxNodeNumGet(UINT         uiChannel, 
                             INT         *piMaxNodeNum);  

函数 API_DmaMaxNodeNumGet 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。
  • 参数 piMaxNodeNum 是最大节点数。

API_DmaMaxNodeNumSet 函数可设置最大队列节点数,函数如下:

#include <SylixOS.h>
INT     API_DmaMaxNodeNumSet(UINT        uiChannel, 
                             INT         iMaxNodeNum); 

函数 API_DmaMaxNodeNumSet 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。
  • 参数 piMaxNodeNum 是最大节点数。

API_DmaJobAdd 函数可添加一个 DMA 传输请求,函数如下:

#include <SylixOS.h>
INT     API_DmaJobAdd(UINT                    uiChannel,
                      PLW_DMA_TRANSACTION     pdmatMsg); 

函数 API_DmaJobAdd 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。
  • 参数 pdmatMsg 是传入数据指针。

API_DmaGetMaxDataBytes 函数可获得一次可以传输的最大字节数,函数如下:

#include <SylixOS.h>
INT     API_DmaGetMaxDataBytes(UINT        uiChannel);

函数 API_DmaGetMaxDataBytes 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。

API_DmaFlush 可删除所有被延迟处理的传输请求,函数如下:

#include <SylixOS.h>
INT     API_DmaFlush(UINT   uiChannel);  

函数 API_DmaFlush 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。

DMA 传输完成后的中断处理函数,在 DMA 中断服务程序中需要调用 API_DmaContext 函数,函数如下:

#include <SylixOS.h>
INT     API_DmaContext(UINT   uiChannel);                     

函数 API_DmaContext 原型分析:

  • 此函数成功返回 ERROR_NONE ,失败返回 PX_ERROR
  • 参数 uiChannel 是 DMA 通道号。
文档内容是否对您有所帮助?
有帮助
没帮助