rt-thread/bsp/lpc5410x/Libraries/lpc_chip/chip_5410x/hw_dmaaltd.c

625 lines
20 KiB
C

/*
* @brief DMA controller ROM API declarations and functions
*
* @note
* Copyright(C) NXP Semiconductors, 2014
* All rights reserved.
*
* @par
* Software that is described herein is for illustrative purposes only
* which provides customers with programming information regarding the
* LPC products. This software is supplied "AS IS" without any warranties of
* any kind, and NXP Semiconductors and its licensor disclaim any and
* all warranties, express or implied, including all implied warranties of
* merchantability, fitness for a particular purpose and non-infringement of
* intellectual property rights. NXP Semiconductors assumes no responsibility
* or liability for the use of the software, conveys no license or rights under any
* patent, copyright, mask work right, or any other intellectual property rights in
* or to any products. NXP Semiconductors reserves the right to make changes
* in the software without notification. NXP Semiconductors also makes no
* representation or warranty that such application will be suitable for the
* specified use without further testing or modification.
*
* @par
* Permission to use, copy, modify, and distribute this software and its
* documentation is hereby granted, under NXP Semiconductors' and its
* licensor's relevant copyrights in the software, without fee, provided that it
* is used in conjunction with NXP Semiconductors microcontrollers. This
* copyright, permission, and disclaimer notice must appear in all copies of
* this code.
*/
#include <stdint.h>
#include <string.h>
#include "hw_dmaaltd.h"
#define DRVVERSION 0x0100
typedef PRE_PACK struct POST_PACK {
uint32_t xfercfg; /*!< DMA Configuration register */
uint32_t src; /*!< DMA source address */
uint32_t dest; /*!< DMA destination address */
ROM_DMA_DESC_T *pNextLink; /*!< Pointer to next descriptor link in a chain, NULL to end */
} ROM_DMA_PRVXFERDESC_T;
/* Private data structure used for the DMA controller driver, holds the driver and
peripheral context */
typedef struct {
void *pUserData; /*!< Pointer to user data used by driver instance, use NULL if not used */
LPC_DMA_T *base; /*!< Base address of DMA controller to use */
ROM_DMA_PRVXFERDESC_T *sramBase; /*!< SRAM descriptor table (all channels) */
ROM_DMA_QUEUE_T *pQueueHead; /*!< Pointer to linked list of queue descriptors */
} DMA_DATACONTEXT_T;
static const uint8_t mskAlign[3] = {0x0, 0x1, 0x3};
static const uint8_t widthBytes[3] = {0x1, 0x2, 0x4};
#define _dma_ch_int_enable(p, ch) ((p)->DMACOMMON[0].INTENSET = (1 << (ch))) /* Enable interrupts for a channel */
#define _dma_ch_int_disable(p, ch) ((p)->DMACOMMON[0].INTENCLR = (1 << (ch))) /* Disable interrupts for a channel */
#define _dma_ch_enable(p, ch) ((p)->DMACOMMON[0].ENABLESET = (1 << (ch))) /* Enable a channel */
#define _dma_ch_disable(p, ch) ((p)->DMACOMMON[0].ENABLECLR = (1 << (ch))) /* Disable a channel */
static void _dma_abort_ch(LPC_DMA_T *pDMA, uint8_t dmaCh)
{
_dma_ch_disable(pDMA, dmaCh);
/* Wait for channel to go unbusy */
while ((pDMA->DMACOMMON[0].BUSY & (1 << dmaCh)) != 0) {}
/* Abort */
pDMA->DMACOMMON[0].ABORT = (1 << dmaCh);
}
static void _dma_start_desc_chain(DMA_DATACONTEXT_T *pDrv, uint8_t dmaCh, ROM_DMA_DESC_T *pDesc)
{
/* Switch to busy state */
pDesc->status = ROM_DMA_DESC_STS_BUSY;
/* Move transfer descriptor to DMA table */
pDrv->sramBase[dmaCh].xfercfg = pDesc->xfercfg;
pDrv->sramBase[dmaCh].src = pDesc->src;
pDrv->sramBase[dmaCh].dest = pDesc->dest;
pDrv->sramBase[dmaCh].pNextLink = (ROM_DMA_DESC_T *) pDesc->pNextLink;
/* Start transfer */
pDrv->base->DMACH[dmaCh].XFERCFG = pDesc->xfercfg;
}
// **********************************************************
uint32_t dmaalt_get_mem_size(void)
{
return sizeof(DMA_DATACONTEXT_T);
}
ROM_DMA_HANDLE_T dmaalt_init(void *mem, const ROM_DMA_INIT_T *pInit)
{
DMA_DATACONTEXT_T *pDrv;
/* Verify alignment is at least 4 bytes */
if (((uint32_t) mem & 0x3) != 0) {
return NULL;
}
pDrv = (DMA_DATACONTEXT_T *) mem;
memset(pDrv, 0, sizeof(DMA_DATACONTEXT_T));
/* Save pointer to user data */
pDrv->pUserData = pInit->pUserData;
pDrv->base = (LPC_DMA_T *) pInit->base;
pDrv->sramBase = (ROM_DMA_PRVXFERDESC_T *) pInit->sramBase;
/* Enable DMA controller */
pDrv->base->CTRL = 1;
pDrv->base->SRAMBASE = (uint32_t) pInit->sramBase;
return (ROM_DMA_HANDLE_T) pDrv;
}
ErrorCode_t dmaalt_setup_channel(ROM_DMA_HANDLE_T pHandle, ROM_DMA_CHAN_CFG_T *pCfg, uint8_t dmaCh)
{
uint32_t cfg;
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
/* Parameter checks */
if ((pCfg->burstSize > (uint32_t) ROM_DMA_BURSTPOWER_1024) || (pCfg->channelPrio > 7)) {
return ERR_DMA_PARAM;
}
/* Enable DMA channel, clear any errors, enable interrupts */
pDrv->base->DMACOMMON[0].ENABLECLR = (1 << dmaCh);
pDrv->base->DMACOMMON[0].ERRINT = (1 << dmaCh);
pDrv->base->DMACOMMON[0].INTA = (1 << dmaCh);
pDrv->base->DMACOMMON[0].INTB = (1 << dmaCh);
/* Basic DMA configuration */
if (pCfg->periphReq) {
cfg = DMA_CFG_PERIPHREQEN;
}
else {
/* Hardware triggering */
cfg = DMA_CFG_HWTRIGEN;
cfg |= (pCfg->triggerPolHi << 4) | (pCfg->triggerLevel << 5) | (pCfg->triggerBurst << 6);
}
cfg |= (pCfg->burstSize << 8) | (pCfg->srcBurstWrap << 14) | (pCfg->dstBurstWrap << 15) | (pCfg->channelPrio << 16);
pDrv->base->DMACH[dmaCh].CFG = cfg;
return LPC_OK;
}
ErrorCode_t dmaalt_init_queue(ROM_DMA_HANDLE_T pHandle, uint8_t dmaCh, ROM_DMA_QUEUE_T *pQueue)
{
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
/* Check queue structure alignment */
if (((uint32_t) pQueue & 0x3) != 0) {
/* Not aligned at 4 bytes, error */
return ERR_DMA_NOT_ALIGNMENT;
}
memset(pQueue, 0, sizeof(ROM_DMA_QUEUE_T));
/* Save DMA channekl for this queue */
pQueue->dmaCh = dmaCh;
/* Append to existing queue */
if (pDrv->pQueueHead) {
pQueue->pQueueHead = (struct ROM_DMA_QUEUE *) pDrv->pQueueHead;
}
pDrv->pQueueHead = pQueue;
pQueue->queueSt = (uint8_t) ROM_QUEUE_ST_IDLE;
return LPC_OK;
}
void dmaalt_register_queue_callback(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue, uint32_t cbIndex, void *pCB)
{
switch (cbIndex) {
case ROM_DMA_XFERCOMPLETE_CB:
pQueue->dmaCompCB = (dmaTransferCompleteCB) pCB;
break;
case ROM_DMA_XFERDESCCOMPLETE_CB:
pQueue->dmaDescCompCB = (dmaTransferDescCompleteCB) pCB;
break;
case ROM_DMA_XFERERROR_CB:
pQueue->dmaErrorCB = (dmaTransferErrorCB) pCB;
break;
}
}
ErrorCode_t dmaalt_build_descriptor_chain(ROM_DMA_HANDLE_T pHandle,
ROM_DMA_XFERDESC_CFG_T *pXferCfg,
ROM_DMA_DESC_T *pDesc,
ROM_DMA_DESC_T *pDescPrev)
{
uint32_t cfg, xfercnt, burstSize;
uint8_t srcWrap, destWrap;
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
/* Parameter checks */
if (pDesc == NULL) {
return ERR_DMA_PARAM;
}
/* Passed descriptor must be correctly aligned */
if (((uint32_t) pDesc & 0xF) != 0) {
return ERR_DMA_NOT_ALIGNMENT;
}
/* Parameter checks */
if (pXferCfg->width > (uint8_t) ROM_DMA_WIDTH_4) {
return ERR_DMA_PARAM;
}
if ((pXferCfg->srcInc > (uint8_t) ROM_DMA_ADDRINC_4X) ||
(pXferCfg->dstInc > (uint8_t) ROM_DMA_ADDRINC_4X)) {
return ERR_DMA_PARAM;
}
if ((pXferCfg->xferCount < 1) || (pXferCfg->xferCount > 1024)) {
return ERR_DMA_PARAM;
}
xfercnt = pXferCfg->xferCount - 1; /* Adjust for use with DMA */
/* Check source and destination address alignment */
if (((uint32_t) pXferCfg->src & mskAlign[pXferCfg->width]) != 0) {
return ERR_DMA_NOT_ALIGNMENT;
}
if (((uint32_t) pXferCfg->dest & mskAlign[pXferCfg->width]) != 0) {
return ERR_DMA_NOT_ALIGNMENT;
}
/* Get source and destination wrap states for the channel */
cfg = pDrv->base->DMACH[pXferCfg->dmaCh].CFG;
/* Get burst size in datum count, used for wrap end address, offset by
(-1) for end address computation */
burstSize = (1 << ((cfg >> 8) & 0xF)) - 1;
/* Setup source transfer address */
if (pXferCfg->srcInc == ROM_DMA_ADDRINC_0X) {
/* No address increment - even with burst - so source address doesn't need
to be adjusted */
pDesc->src = (uint32_t) pXferCfg->src;
}
else {
srcWrap = (uint8_t) ((cfg & (1 << 14)) != 0);
if (srcWrap) {
/* Wrap enabled - compute end address based on burst size and datum width */
pDesc->src = (uint32_t) pXferCfg->src + ((uint32_t) widthBytes[pXferCfg->width] *
burstSize * (1 << ((uint32_t) pXferCfg->srcInc - 1)));
}
else {
/* No wrap - compute end address based on transfer size and datum width */
pDesc->src = (uint32_t) pXferCfg->src + ((uint32_t) widthBytes[pXferCfg->width] *
xfercnt * (1 << ((uint32_t) pXferCfg->srcInc - 1)));
}
}
/* Setup destination transfer address */
if (pXferCfg->dstInc == ROM_DMA_ADDRINC_0X) {
/* No address increment - even with burst - so destination address doesn't need
to be adjusted */
pDesc->dest = (uint32_t) pXferCfg->dest;
}
else {
destWrap = (uint8_t) ((cfg & (1 << 15)) != 0);
if (destWrap) {
/* Wrap enabled - compute end address based on burst size and datum width */
pDesc->dest = (uint32_t) pXferCfg->dest + ((uint32_t) widthBytes[pXferCfg->width] *
burstSize * (1 << ((uint32_t) pXferCfg->dstInc - 1)));
}
else {
/* No wrap - compute end address based on transfer size and datum width */
pDesc->dest = (uint32_t) pXferCfg->dest + ((uint32_t) widthBytes[pXferCfg->width] *
xfercnt * (1 << ((uint32_t) pXferCfg->dstInc - 1)));
}
}
/* Save pointer to user data context */
pDesc->pUserData = pXferCfg->pUserData;
/* Is the descriptor linked from a previous descriptor? */
if (pDescPrev) {
pDescPrev->pNextLink = (struct ROM_DMA_DESC *) pDesc;
if (pXferCfg->enabCirc == 0) {
pDescPrev->xfercfg &= ~(1 << 5);/* Disables INTB on previous descriptor link */
pDescPrev->xfercfg |= (1 << 1); /* Reload on chained links */
}
}
else {
pDesc->pNextLink = NULL;
}
/* NULL out next chain descriptor pointers. The next chain descriptor is
managed by the queue function, while the next link descriptor indicates the end
of a chain. */
pDesc->pNextChain = NULL;
/* Current descriptor status is queueing. Status only applies to the first descriptor
in a chain. */
pDesc->status = ROM_DMA_DESC_STS_QUEUEING;
pDesc->savedXferSize = pXferCfg->xferCount;
/* Normalize parameters that are multibit to single bit */
pXferCfg->swTrig = (pXferCfg->swTrig != 0);
pXferCfg->clrTrig = (pXferCfg->clrTrig != 0);
pXferCfg->fireDescCB = (pXferCfg->fireDescCB != 0);
if (pXferCfg->enabCirc) {
cfg = (1 << 1); /* Reload on chained links */
}
else {
cfg = (1 << 5); /* INTB support for completion and next descriptor */
}
if (pXferCfg->stallDesc == 0) {
cfg |= 0x1; /* CFGVALID */
}
/* Setup transfer configuration */
cfg |= (pXferCfg->swTrig << 2) | (pXferCfg->clrTrig << 3) |
(pXferCfg->fireDescCB << 4) | (pXferCfg->width << 8) | (pXferCfg->srcInc << 12) |
(pXferCfg->dstInc << 14);
cfg |= (xfercnt << 16);
pDesc->xfercfg = cfg;
return LPC_OK;
}
uint32_t dmaalt_get_transfer_count(ROM_DMA_HANDLE_T pHandle, ROM_DMA_DESC_T *pDesc)
{
uint32_t dataCount = 0;
/* Count is only valid if descriptor is used */
while (pDesc != NULL) {
if (pDesc->status == ROM_DMA_DESC_STS_SPENT) {
dataCount += (uint32_t) pDesc->savedXferSize;
}
pDesc = (ROM_DMA_DESC_T *) pDesc->pNextLink;
}
return dataCount;
}
void dmaalt_unstall_descriptor_chain(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
pDrv->base->DMACOMMON[0].SETVALID = (1 << pQueue->dmaCh);
}
void dmaalt_queue_descriptor(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue, ROM_DMA_DESC_T *pDescChainHead)
{
/* Add the link to the passed descriptor to the end of the queue */
if (pQueue->pDescEnd != NULL) {
pQueue->pDescEnd->pNextChain = (struct ROM_DMA_DESC *) pDescChainHead;
}
pQueue->pDescEnd = pDescChainHead;
/* Next descriptor in queue */
if (pQueue->pDescNext == NULL) {
pQueue->pDescNext = pDescChainHead;
}
/* Descriptor is ready */
pDescChainHead->status = ROM_DMA_DESC_STS_READY;
}
ROM_DMA_DESC_STS_T dmaalt_get_queue_pop_descriptor_status(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
if (pQueue->pDescPop) {
return (ROM_DMA_DESC_STS_T) pQueue->pDescPop->status;
}
return ROM_DMA_DESC_STS_INVALID;
}
ROM_DMA_DESC_T *dmaalt_unqueue_descriptor(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
ROM_DMA_DESC_T *pDesc = NULL;
/* Get current queue pop descriptor */
if (pQueue->pDescPop) {
/* Only expired (spent, error, or aborted descriptors can be unqueued. Use StopQueue to halt all
descriptors queued. */
if (pQueue->pDescPop->status >= ROM_DMA_DESC_STS_SPENT) {
pDesc = (ROM_DMA_DESC_T *) pQueue->pDescPop;
pQueue->pDescPop = (ROM_DMA_DESC_T *) pQueue->pDescPop->pNextChain;
}
}
return pDesc;
}
ErrorCode_t dmaalt_start_queue(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
/* Is DMA already running? No need to restart */
if ((pDrv->base->DMACOMMON[0].ACTIVE & (1 << pQueue->dmaCh)) != 0) {
return LPC_OK;
}
/* Is queue empty? */
if (pQueue->pDescNext == NULL) {
return ERR_DMA_QUEUE_EMPTY;
}
/* Does the queue currently have a descriptor in it? */
if (pQueue->pDescNext) {
/* Is current descriptor chain ready? */
if (pQueue->pDescNext->status == ROM_DMA_DESC_STS_READY) {
/* Queue is now running */
pQueue->queueSt = (uint8_t) ROM_QUEUE_ST_RUNNING;
/* Enable this channel */
_dma_ch_enable(pDrv->base, pQueue->dmaCh);
_dma_ch_int_enable(pDrv->base, pQueue->dmaCh);
_dma_start_desc_chain(pDrv, pQueue->dmaCh, pQueue->pDescNext);
}
}
return LPC_OK;
}
ErrorCode_t dmaalt_stop_queue(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
ErrorCode_t error = LPC_OK;
/* Disable interrupts for this channel */
_dma_ch_int_disable(pDrv->base, pQueue->dmaCh);
/* If queue is empty, no need to stop */
if (pQueue->pDescNext == NULL) {
return LPC_OK;
}
/* If current transfer is queued or ready, then switch it to aborted status
and call completion callback if needed. */
if (pQueue->pDescNext->status == ROM_DMA_DESC_STS_BUSY) {
/* Abort transfer */
_dma_abort_ch(pDrv->base, pQueue->dmaCh);
}
else if (!((pQueue->pDescNext->status == ROM_DMA_DESC_STS_QUEUEING) ||
(pQueue->pDescNext->status == ROM_DMA_DESC_STS_READY))) {
/* Other statuses are not legal for a queued descriptor */
error = ERR_DMA_GENERAL;
}
/* Unlatch interrupts */
pDrv->base->DMACOMMON[0].ERRINT = (1 << pQueue->dmaCh);
pDrv->base->DMACOMMON[0].INTA = (1 << pQueue->dmaCh);
pDrv->base->DMACOMMON[0].INTB = (1 << pQueue->dmaCh);
/* Call completion callback to indicate abort state */
pQueue->pDescNext->status = ROM_DMA_DESC_STS_ABORT;
if (pQueue->dmaCompCB) {
pQueue->dmaCompCB(pHandle, (struct ROM_DMA_QUEUE *) pQueue, pQueue->pDescNext);
}
/* Increment to next available descriptor since this one was aborted */
pQueue->pDescNext = (ROM_DMA_DESC_T *) pQueue->pDescNext->pNextChain;
/* Queue is now idle */
pQueue->queueSt = (uint8_t) ROM_QUEUE_ST_IDLE;
return error;
}
void dmaalt_flush_queue(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
/* Disable interrupts for this channel */
_dma_ch_int_disable(pDrv->base, pQueue->dmaCh);
/* Abort transfer */
_dma_abort_ch(pDrv->base, pQueue->dmaCh);
/* Unlatch interrupts */
pDrv->base->DMACOMMON[0].ERRINT = (1 << pQueue->dmaCh);
pDrv->base->DMACOMMON[0].INTA = (1 << pQueue->dmaCh);
pDrv->base->DMACOMMON[0].INTB = (1 << pQueue->dmaCh);
/* No callbacks on abort, all descriptors flushed */
pQueue->pDescEnd = pQueue->pDescNext = pQueue->pDescPop = NULL;
/* Queue is now idle */
pQueue->queueSt = (uint8_t) ROM_QUEUE_ST_IDLE;
}
uint8_t dmaalt_get_queue_state(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
return pQueue->queueSt;
}
void dmaalt_force_trigger(ROM_DMA_HANDLE_T pHandle, ROM_DMA_QUEUE_T *pQueue)
{
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
pDrv->base->DMACOMMON[0].SETTRIG = (1 << pQueue->dmaCh);
}
// Otime = "optimize for speed of code execution"
// ...add this pragma 1 line above the interrupt service routine function.
void dmaalt_handler(ROM_DMA_HANDLE_T pHandle)
{
uint32_t err, inta, intb, all, dmaChMask;
ROM_DMA_QUEUE_T *pQueue;
ROM_DMA_DESC_T *pDesc;
DMA_DATACONTEXT_T *pDrv = (DMA_DATACONTEXT_T *) pHandle;
uint8_t nextChain = 0;
/* DMA interrupt fires on one of three possible events:
1) ERROR : A DMA error has occured
Calls error callback and stops queue
2) INTA on descriptor completion
Calls descriptor completed callback
3) INTB on descriptor chain completion
Calls descriptor chain completion callback */
/* Loop through all enabled DMA channels */
pQueue = pDrv->pQueueHead;
err = pDrv->base->DMACOMMON[0].ERRINT;
inta = pDrv->base->DMACOMMON[0].INTA;
intb = pDrv->base->DMACOMMON[0].INTB;
all = err | inta | intb;
while (pQueue) {
dmaChMask = (1 << pQueue->dmaCh);
if ((all & dmaChMask) != 0) {
/* DMA interrupt fire for this channel */
if ((err & dmaChMask) != 0) {
/* Abort current descriptor */
_dma_ch_int_disable(pDrv->base, pQueue->dmaCh);
_dma_abort_ch(pDrv->base, pQueue->dmaCh);
/* Error interrupt, clear */
pDrv->base->DMACOMMON[0].ERRINT = dmaChMask;
pDrv->base->DMACOMMON[0].INTA = dmaChMask;
pDrv->base->DMACOMMON[0].INTB = dmaChMask;
/* Update status to error */
pQueue->pDescNext->status = ROM_DMA_DESC_STS_ERROR;
pQueue->queueSt = (uint8_t) ROM_QUEUE_ST_ERROR;
/* Call error callback for channel */
if (pQueue->dmaErrorCB) {
pQueue->dmaErrorCB(pHandle, (struct ROM_DMA_QUEUE *) pQueue, pQueue->pDescNext);
}
nextChain = 1;
}
/* Interrupt A is used for user defined interrupt tied to a descriptor */
if ((inta & dmaChMask) != 0) {
pDrv->base->DMACOMMON[0].INTA = dmaChMask;
/* Call transfer descriptor completion for channel */
if (pQueue->dmaDescCompCB) {
pQueue->dmaDescCompCB(pHandle, (struct ROM_DMA_QUEUE *) pQueue, pQueue->pDescNext);
}
}
/* Interrupt B is used for user transfer descriptor chain completion */
if ((intb & dmaChMask) != 0) {
pDrv->base->DMACOMMON[0].INTB = dmaChMask;
/* Update status to spent/complete */
pQueue->pDescNext->status = ROM_DMA_DESC_STS_SPENT;
/* Start the next descriptor chain? */
pDesc = (ROM_DMA_DESC_T *) pQueue->pDescNext->pNextChain;
if ((pDesc) && (pDesc->status == ROM_DMA_DESC_STS_READY)) {
/* A queued descriptor is available and ready, so start it */
_dma_start_desc_chain(pDrv, pQueue->dmaCh, pDesc);
}
/* Call transfer descriptor completion for channel */
if (pQueue->dmaCompCB) {
pQueue->dmaCompCB(pHandle, (struct ROM_DMA_QUEUE *) pQueue, pQueue->pDescNext);
}
nextChain = 1;
}
if (nextChain) {
/* Need to save in pop queue? */
if (pQueue->pDescPop == NULL) {
pQueue->pDescPop = pQueue->pDescNext;
}
/* Advance to next queued descriptor */
pQueue->pDescNext = (ROM_DMA_DESC_T *) pQueue->pDescNext->pNextChain;
if (pQueue->pDescNext == NULL) {
/* No more descriptors */
pQueue->pDescEnd = NULL;
}
}
all &= ~dmaChMask;
}
/* Next queue */
pQueue = (ROM_DMA_QUEUE_T *) pQueue->pQueueHead;
}
if (all) {
/* Unexpected interrupts, clear and disable */
pDrv->base->DMACOMMON[0].ENABLECLR = all;
pDrv->base->DMACOMMON[0].INTENCLR = all;
pDrv->base->DMACOMMON[0].ERRINT = all;
pDrv->base->DMACOMMON[0].INTA = all;
pDrv->base->DMACOMMON[0].INTB = all;
}
}
uint32_t dmaalt_get_driver_version(void)
{
return DRVVERSION;
}
// *********************************************************