1. 文件结构简介
SylixOS 系统下 dma 代码文件结构,目录:libsylixos/SylixOS/system/device/dma
文件名 | 描述 |
---|---|
dma.c | 主要是 dma 通用抽象,提供 dma 通用的结构抽象,以及 dma 过程的同步 |
dma.h | dma 数据结构的抽象和对外接口 |
dmaLib.c | 主要是 dma 使用中链表结构的抽象,用于 dma 任务的增删更改 |
dmaLib.h | dma 链表使用的相关结构抽象 |
2. 数据框架流程图
dma 框架的主要流程,使用 API_DmaJobAdd 向任务队列添加相关传输信息,在传输完成中断中清除已经完成的任务,并设置新的任务;
3. 主要数据结构
/*********************************************************************************************************
DMA 传输参数
DMA 操作的为物理地址, 所以 Src 和 Dest 地址均为物理地址.
有些系统 CPU 体系构架的 CACHE 是使用虚拟地址作为索引的, 有些是使用物理地址做索引的.
所以 DMA 软件层不处理任何 CACHE 相关的操作, 将这些操作留给驱动程序或应用程序完成.
注意: 回调函数将可能会在中断上下文中执行.
*********************************************************************************************************/
typedef struct {
UINT8 *DMAT_pucSrcAddress; /* 源端缓冲区地址 */
UINT8 *DMAT_pucDestAddress; /* 目的端缓冲区地址 */
size_t DMAT_stDataBytes; /* 传输的字节数 */
INT DMAT_iSrcAddrCtl; /* 源端地址方向控制 */
INT DMAT_iDestAddrCtl; /* 目的地址方向控制 */
INT DMAT_iHwReqNum; /* 外设请求端编号 */
BOOL DMAT_bHwReqEn; /* 是否为外设启动 DMA 传输 */
BOOL DMAT_bHwHandshakeEn; /* 是否使用硬件握手 */
INT DMAT_iTransMode; /* 传输模式, 自定义 */
PVOID DMAT_pvTransParam; /* 传输参数, 自定义 */
ULONG DMAT_ulOption; /* 体系结构相关参数 */
PVOID DMAT_pvArgStart; /* 启动回调参数 */
VOID (*DMAT_pfuncStart)(UINT uiChannel,
PVOID pvArg); /* 启动本次传输之前的回调函数 */
PVOID *DMAT_pvArg; /* 回调函数参数 */
VOID (*DMAT_pfuncCallback)(UINT uiChannel,
PVOID pvArg); /* 本次传输完成后的回调函数 */
} LW_DMA_TRANSACTION;
typedef LW_DMA_TRANSACTION *PLW_DMA_TRANSACTION;
/*********************************************************************************************************
DMA 设备定义 (驱动程序接口)
*********************************************************************************************************/
typedef struct lw_dma_funcs {
VOID (*DMAF_pfuncReset)(UINT uiChannel,
struct lw_dma_funcs *pdmafuncs);
/* 复位 DMA 当前的操作 */
INT (*DMAF_pfuncTrans)(UINT uiChannel,
struct lw_dma_funcs *pdmafuncs,
PLW_DMA_TRANSACTION pdmatMsg);
/* 启动一次 DMA 传输 */
INT (*DMAF_pfuncStatus)(UINT uiChannel,
struct lw_dma_funcs *pdmafuncs);
/* 获得 DMA 当前的工作状态 */
} LW_DMA_FUNCS;
typedef LW_DMA_FUNCS *PLW_DMA_FUNCS;
/*********************************************************************************************************
DMA 传输控制节点
*********************************************************************************************************/
typedef struct {
LW_LIST_RING DMAN_ringManage; /* 双向管理链表 */
BOOL DMAN_bDontFree; /* 是否释放内存 */
LW_DMA_TRANSACTION DMAN_pdmatMsg; /* 传输传输控制块 */
} __DMA_WAITNODE;
typedef __DMA_WAITNODE *__PDMA_WAITNODE;
/*********************************************************************************************************
DMA 通道控制块
*********************************************************************************************************/
typedef struct {
PLW_LIST_RING DMAC_pringHead; /* 传输控制链表头 */
INT DMAC_iNodeCounter; /* 节点计数器, 调试使用 */
INT DMAC_iMaxNode; /* 列队中可以存在的最多 NODE */
/* 当 dma job add 超过此数量时 */
/* 将阻塞, 直到少于此值 */
LW_OBJECT_HANDLE DMAC_ulJobSync; /* 任务队列同步锁 */
BOOL DMAC_bIsInFlush; /* 是否正在清除队列 */
PLW_DMA_FUNCS DMAC_pdmafuncs; /* DMA 驱动程序 */
size_t DMAC_stMaxDataBytes; /* 最大传输传输长度 */
} __DMA_CHANNEL;
typedef __DMA_CHANNEL *__PDMA_CHANNEL;
4. 主要函数
- API_DmaDrvInstall
dma 驱动函数安装,根据不同的 dma 外设,安装相应的驱动;
/*********************************************************************************************************
** 函数名称: API_DmaDrvInstall
** 功能描述: 安装通用 DMA 驱动程序
** 输 入 : uiChannel 通道
** pdmafuncs 驱动函数集
** stMaxDataBytes 每一次传输的最多字节数
** 输 出 : ERROR
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaDrvInstall (UINT uiChannel,
PLW_DMA_FUNCS pdmafuncs,
size_t stMaxDataBytes)
{
#define __DMA_CHANNEL_MAX_NODE 8 /* 默认单通道最大任务节点数 */
static BOOL bIsInit = LW_FALSE;
if (bIsInit == LW_FALSE) {
bIsInit = LW_TRUE;
LW_SPIN_INIT(&_G_slDmaManage); /* 初始化自旋锁 */
_dmaInit(); /* 初始化相关结构 */
}
if (__DMA_CHANNEL_INVALID(uiChannel)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
_ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
return (PX_ERROR);
}
if ((pdmafuncs == LW_NULL) || (stMaxDataBytes == 0)) { /* 检查参数 */
_ErrorHandle(EINVAL);
return (PX_ERROR);
}
_G_dmacChannel[uiChannel].DMAC_pdmafuncs = pdmafuncs;
_G_dmacChannel[uiChannel].DMAC_stMaxDataBytes = stMaxDataBytes;
/* 没有安装过驱动 */
if (_G_dmacChannel[uiChannel].DMAC_ulJobSync == LW_OBJECT_HANDLE_INVALID) {
_G_dmacChannel[uiChannel].DMAC_pringHead = LW_NULL;
_G_dmacChannel[uiChannel].DMAC_iNodeCounter = 0;
_G_dmacChannel[uiChannel].DMAC_iMaxNode = __DMA_CHANNEL_MAX_NODE;
/* 默认最多 8 个节点 */
_G_dmacChannel[uiChannel].DMAC_ulJobSync = API_SemaphoreBCreate("dma_jobsync",
LW_FALSE,
LW_OPTION_WAIT_FIFO |
LW_OPTION_OBJECT_GLOBAL,
LW_NULL);
/* 创建同步工作队列 */
if (!_G_dmacChannel[uiChannel].DMAC_ulJobSync) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "can not create dma_jobsync.\r\n");
return (PX_ERROR);
}
}
__DMA_CHANNEL_RESET(uiChannel);
return (ERROR_NONE);
}
- API_DmaReset
操作驱动对指定通道的 DMA 进行复位
/*********************************************************************************************************
** 函数名称: API_DmaReset
** 功能描述: 复位指定通道的 DMA 控制器
** 输 入 : uiChannel DMA 通道号
** 输 出 : PX_ERROR or ERROR_NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaReset (UINT uiChannel)
{
if (__DMA_CHANNEL_INVALID(uiChannel)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
_ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
return (PX_ERROR);
}
__DMA_CHANNEL_RESET(uiChannel);
return (ERROR_NONE);
}
- API_DmaJobNodeNum
获取指定通道 dma 缓存节点个数
/*********************************************************************************************************
** 函数名称: API_DmaJobNodeNum
** 功能描述: 获得指定 DMA 通道当前等待队列的节点数
** 输 入 : uiChannel DMA 通道号
** piNodeNum 当前节点数量缓存
** 输 出 : PX_ERROR or ERROR_NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaJobNodeNum (UINT uiChannel, INT *piNodeNum)
{
INTREG iregInterLevel;
REGISTER __PDMA_CHANNEL pdmacChannel;
if (__DMA_CHANNEL_INVALID(uiChannel)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
_ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
return (PX_ERROR);
}
pdmacChannel = __DMA_CHANNEL_GET(uiChannel);
if (piNodeNum) {
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
*piNodeNum = pdmacChannel->DMAC_iNodeCounter;
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
}
return (ERROR_NONE);
}
- API_DmaMaxNodeNumGet
获取指定 dma 通道允许的最大节点数
/*********************************************************************************************************
** 函数名称: API_DmaMaxNodeNumGet
** 功能描述: 获得指定 DMA 通道当前等待队列的节点数
** 输 入 : uiChannel DMA 通道号
** piMaxNodeNum 允许最大节点缓冲
** 输 出 : PX_ERROR or ERROR_NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaMaxNodeNumGet (UINT uiChannel, INT *piMaxNodeNum)
{
INTREG iregInterLevel;
REGISTER __PDMA_CHANNEL pdmacChannel;
if (__DMA_CHANNEL_INVALID(uiChannel)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
_ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
return (PX_ERROR);
}
pdmacChannel = __DMA_CHANNEL_GET(uiChannel);
if (piMaxNodeNum) {
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
*piMaxNodeNum = pdmacChannel->DMAC_iMaxNode;
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
}
return (ERROR_NONE);
}
- API_DmaMaxNodeNumSet
设置指定通道 dma 最大允许的节点数;
/*********************************************************************************************************
** 函数名称: API_DmaMaxNodeNumSet
** 功能描述: 设置指定 DMA 通道当前等待队列的节点数
** 输 入 : uiChannel DMA 通道号
** iMaxNodeNum 允许最大节点缓冲
** 输 出 : PX_ERROR or ERROR_NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaMaxNodeNumSet (UINT uiChannel, INT iMaxNodeNum)
{
INTREG iregInterLevel;
REGISTER __PDMA_CHANNEL pdmacChannel;
if (__DMA_CHANNEL_INVALID(uiChannel)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
_ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
return (PX_ERROR);
}
pdmacChannel = __DMA_CHANNEL_GET(uiChannel);
/*
* 注意, 这里并没有判断 iMaxNodeNum 有效性, 可能设置为 0 或者负数停止工作队列执行.
*/
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
pdmacChannel->DMAC_iMaxNode = iMaxNodeNum;
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
return (ERROR_NONE);
}
- API_DmaJobAdd
向指定通道的 dma 添加相关传输请求;
/*********************************************************************************************************
** 函数名称: API_DmaJobAdd
** 功能描述: 添加一个 DMA 传输请求
** 输 入 : uiChannel DMA 通道号
** pdmatMsg DMA 相关信息
** 输 出 : PX_ERROR or ERROR_NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaJobAdd (UINT uiChannel,
PLW_DMA_TRANSACTION pdmatMsg)
{
#define __SAFE() if (!bInterContext) { LW_THREAD_SAFE(); }
#define __UNSAFE() if (!bInterContext) { LW_THREAD_UNSAFE(); }
INTREG iregInterLevel;
REGISTER __PDMA_CHANNEL pdmacChannel;
REGISTER __PDMA_WAITNODE pdmanNodeNew;
BOOL bInterContext;
if (__DMA_CHANNEL_INVALID(uiChannel)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
_ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
return (PX_ERROR);
}
if (!pdmatMsg) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "pdmatMsg invalid.\r\n");
_ErrorHandle(ERROR_DMA_TRANSMSG_INVALID);
return (PX_ERROR);
}
if (pdmatMsg->DMAT_stDataBytes >
_G_dmacChannel[uiChannel].DMAC_stMaxDataBytes) { /* 数据量过大 */
_DebugHandle(__ERRORMESSAGE_LEVEL, "data too large.\r\n");
_ErrorHandle(ERROR_DMA_DATA_TOO_LARGE);
return (PX_ERROR);
}
bInterContext = API_InterContext();
pdmacChannel = __DMA_CHANNEL_GET(uiChannel);
do {
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
if (pdmacChannel->DMAC_iNodeCounter >=
pdmacChannel->DMAC_iMaxNode) {
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
if (bInterContext) { /* 在中断中调用 */
_ErrorHandle(ERROR_DMA_MAX_NODE);
return (PX_ERROR);
} else if (API_SemaphoreBPend(pdmacChannel->DMAC_ulJobSync,
LW_OPTION_WAIT_INFINITE) != ERROR_NONE) { /* 等待 */
return (PX_ERROR);
}
} else { /* 满足插入节点条件 */
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
break;
}
} while (1); /* 循环等待 */
__SAFE();
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
pdmanNodeNew = _dmaWaitnodeAlloc(); /* 使用快速分配节点 */
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
if (pdmanNodeNew) { /* 有可供快速使用的节点 */
pdmanNodeNew->DMAN_bDontFree = LW_TRUE; /* 不需要释放操作 */
} else { /* 需要进行动态内存分配 */
if (bInterContext) { /* 在中断中调用 */
__UNSAFE();
_ErrorHandle(ERROR_DMA_NO_FREE_NODE); /* 缺少空闲节点 */
return (PX_ERROR);
}
pdmanNodeNew = (__PDMA_WAITNODE)__SHEAP_ALLOC(sizeof(__DMA_WAITNODE));
if (pdmanNodeNew) {
pdmanNodeNew->DMAN_bDontFree = LW_FALSE; /* 需要释放操作 */
} else {
__UNSAFE();
_ErrorHandle(ERROR_SYSTEM_LOW_MEMORY); /* 缺少内存 */
return (PX_ERROR);
}
}
pdmanNodeNew->DMAN_pdmatMsg = *pdmatMsg; /* 保存消息 */
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
_dmaInsertToWaitList(pdmacChannel, pdmanNodeNew); /* 插入 DMA 待处理队列 */
if (pdmacChannel->DMAC_iNodeCounter == 1) { /* 只有唯一的一个节点 */
if (pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart) {
pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart(uiChannel,
pdmanNodeNew->DMAN_pdmatMsg.DMAT_pvArgStart); /* 执行启动回调 */
}
{
INT iRet = ERROR_NONE;
__DMA_CHANNEL_TRANS(uiChannel, pdmatMsg, iRet); /* 初始化传输诸元 */
(VOID)iRet; /* 暂不处理错误 */
}
}
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
__UNSAFE();
return (ERROR_NONE);
}
- API_DmaFlush
删除指定通道下 dma 所有的任务节点;
/*********************************************************************************************************
** 函数名称: API_DmaFlush
** 功能描述: 删除所有被延迟处理的传输请求 (不调用回调函数)
** 输 入 : uiChannel DMA 通道号
** 输 出 : PX_ERROR or ERROR_NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaFlush (UINT uiChannel)
{
INTREG iregInterLevel;
REGISTER __PDMA_CHANNEL pdmacChannel;
REGISTER __PDMA_WAITNODE pdmanNode;
if (__DMA_CHANNEL_INVALID(uiChannel)) {
_DebugHandle(__ERRORMESSAGE_LEVEL, "dma channel invalid.\r\n");
_ErrorHandle(ERROR_DMA_CHANNEL_INVALID);
return (PX_ERROR);
}
if (LW_CPU_GET_CUR_NESTING()) { /* 不能在中断中调用 */
_ErrorHandle(ERROR_KERNEL_IN_ISR);
return (PX_ERROR);
}
pdmacChannel = __DMA_CHANNEL_GET(uiChannel); /* 获得通道控制块 */
LW_THREAD_SAFE();
pdmacChannel->DMAC_bIsInFlush = LW_TRUE; /* 开始进行 FLUSH 操作 */
for (;;) {
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
pdmanNode = _dmaGetFirstInWaitList(pdmacChannel); /* 获得最近的一个节点 */
if (!pdmanNode) { /* 没有节点了 */
__DMA_CHANNEL_RESET(uiChannel); /* 复位通道 */
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
break; /* 跳出循环 */
}
_dmaDeleteFromWaitList(pdmacChannel, pdmanNode); /* 从等待队列删除这个节点 */
if (pdmanNode->DMAN_bDontFree) {
_dmaWaitnodeFree(pdmanNode); /* 加入到空闲队列 */
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
} else {
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
__SHEAP_FREE(pdmanNode); /* 释放到内存堆中 */
}
}
pdmacChannel->DMAC_bIsInFlush = LW_FALSE; /* 结束 FLUSH 操作 */
API_SemaphoreBPost(pdmacChannel->DMAC_ulJobSync); /* 释放同步信号量 */
LW_THREAD_UNSAFE();
return (ERROR_NONE);
}
- API_DmaContext
指定通道 DMA 中断服务函数;
/*********************************************************************************************************
** 函数名称: API_DmaContext
** 功能描述: 指定通道 DMA 中断服务函数.这里不判断通道有效性,使用时请小心!
** 输 入 : uiChannel DMA 通道号
** 输 出 : PX_ERROR or ERROR_NONE
** 全局变量:
** 调用模块:
API 函数
*********************************************************************************************************/
LW_API
INT API_DmaContext (UINT uiChannel)
{
INTREG iregInterLevel;
REGISTER __PDMA_CHANNEL pdmacChannel;
REGISTER __PDMA_WAITNODE pdmanNode;
REGISTER __PDMA_WAITNODE pdmanNodeNew; /* 最新需要处理的节点 */
pdmacChannel = __DMA_CHANNEL_GET(uiChannel); /* 获得通道控制块 */
if (pdmacChannel->DMAC_bIsInFlush) { /* 在执行 FLUSH 操作 */
return (ERROR_NONE);
}
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
pdmanNode = _dmaGetFirstInWaitList(pdmacChannel); /* 获得最近的一个节点 */
if (!pdmanNode) { /* 没有节点了 */
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
return (ERROR_NONE);
}
_dmaDeleteFromWaitList(pdmacChannel, pdmanNode); /* 从等待队列删除这个节点 */
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
/*
* 以最快方式插入新节点, 防止音频播放断续.
*/
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
pdmanNodeNew = _dmaGetFirstInWaitList(pdmacChannel); /* 获得最近的一个节点 */
if (pdmanNodeNew) { /* 存在新节点 */
if (pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart) {
pdmanNodeNew->DMAN_pdmatMsg.DMAT_pfuncStart(uiChannel,
pdmanNodeNew->DMAN_pdmatMsg.DMAT_pvArgStart); /* 执行启动回调 */
}
{
INT iRet = ERROR_NONE;
__DMA_CHANNEL_TRANS(uiChannel,
&pdmanNodeNew->DMAN_pdmatMsg,
iRet); /* 初始化传输诸元 */
(VOID)iRet; /* 暂不处理错误 */
}
}
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
if (pdmanNode->DMAN_pdmatMsg.DMAT_pfuncCallback) {
pdmanNode->DMAN_pdmatMsg.DMAT_pfuncCallback(uiChannel,
pdmanNode->DMAN_pdmatMsg.DMAT_pvArg); /* 调用回调函数 */
}
/*
* 释放原有节点
*/
if (pdmanNode->DMAN_bDontFree) {
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
_dmaWaitnodeFree(pdmanNode); /* 加入到空闲队列 */
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
} else {
_excJobAdd((VOIDFUNCPTR)_HeapFree,
(PVOID)_K_pheapSystem,
(PVOID)pdmanNode, /* 释放节点 */
(PVOID)LW_FALSE,
0, 0, 0); /* 添加到延迟作业队列处理 */
}
/*
* 检查是否需要释放同步信号量.
*/
LW_SPIN_LOCK_QUICK(&_G_slDmaManage, &iregInterLevel); /* 关闭中断同时锁住 spinlock */
if ((pdmacChannel->DMAC_iMaxNode - pdmacChannel->DMAC_iNodeCounter) == 1) {
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
API_SemaphoreBPost(pdmacChannel->DMAC_ulJobSync); /* 释放同步信号量 */
} else {
LW_SPIN_UNLOCK_QUICK(&_G_slDmaManage, iregInterLevel); /* 打开中断同时解锁 spinlock */
}
return (ERROR_NONE);
}