MotorControlModuleSDFM_TMS3.../Projects/EFC_Communication/Platform/device/udma.c
2024-06-07 11:12:56 +03:00

468 lines
15 KiB
C

//###########################################################################
//
// FILE: udma.c
//
// TITLE: Driver for the micro-DMA controller.
//
//###########################################################################
// $TI Release: F2838x Support Library v3.04.00.00 $
// $Release Date: Fri Feb 12 19:08:49 IST 2021 $
// $Copyright:
// Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// $
//###########################################################################
#include "udma.h"
//*****************************************************************************
//
// UDMA_enableChannelAttribute()
//
//*****************************************************************************
void
UDMA_enableChannelAttribute(uint32_t base, uint32_t channelNum,
uint32_t channelAttr)
{
//
// Check the arguments.
//
ASSERT(UDMA_isBaseValid(base));
ASSERT((channelNum & 0xFFFFU) < 32U);
ASSERT((channelAttr & ~(UDMA_CH_ATTR_USEBURST | UDMA_CH_ATTR_ALTSELECT |
UDMA_CH_ATTR_HIGH_PRIORITY | UDMA_CH_ATTR_REQMASK)) == 0U);
//
// Set the useburst bit for this channel if set in channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_USEBURST) == UDMA_CH_ATTR_USEBURST)
{
HWREG(base + UDMA_O_DMAUSEBURSTSET) = 1U << channelNum;
}
//
// Set the alternate control select bit for this channel,
// if set in channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_ALTSELECT) == UDMA_CH_ATTR_ALTSELECT)
{
HWREG(base + UDMA_O_DMAALTSET) = 1U << channelNum;
}
//
// Set the high priority bit for this channel, if set in channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_HIGH_PRIORITY) == UDMA_CH_ATTR_HIGH_PRIORITY)
{
HWREG(base + UDMA_O_DMAPRIOSET) = 1U << channelNum;
}
//
// Set the request mask bit for this channel, if set in channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_REQMASK) == UDMA_CH_ATTR_REQMASK)
{
HWREG(base + UDMA_O_DMAREQMASKSET) = 1U << channelNum;
}
}
//*****************************************************************************
//
// UDMA_disableChannelAttribute()
//
//*****************************************************************************
void
UDMA_disableChannelAttribute(uint32_t base, uint32_t channelNum,
uint32_t channelAttr)
{
//
// Check the arguments.
//
ASSERT(UDMA_isBaseValid(base));
ASSERT((channelNum & 0xFFFFU) < 32U);
ASSERT((channelAttr & ~(UDMA_CH_ATTR_USEBURST | UDMA_CH_ATTR_ALTSELECT |
UDMA_CH_ATTR_HIGH_PRIORITY | UDMA_CH_ATTR_REQMASK)) == 0U);
//
// Clear the useburst bit for this channel if set in channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_USEBURST) == UDMA_CH_ATTR_USEBURST)
{
HWREG(base + UDMA_O_DMAUSEBURSTCLR) = 1U << channelNum;
}
//
// Clear the alternate control select bit for this channel, if set in
// channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_ALTSELECT) == UDMA_CH_ATTR_ALTSELECT)
{
HWREG(base + UDMA_O_DMAALTCLR) = 1U << channelNum;
}
//
// Clear the high priority bit for this channel, if set in channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_HIGH_PRIORITY) == UDMA_CH_ATTR_HIGH_PRIORITY)
{
HWREG(base + UDMA_O_DMAPRIOCLR) = 1U << channelNum;
}
//
// Clear the request mask bit for this channel, if set in channelAttr.
//
if((channelAttr & UDMA_CH_ATTR_REQMASK) == UDMA_CH_ATTR_REQMASK)
{
HWREG(base + UDMA_O_DMAREQMASKCLR) = 1U << channelNum;
}
}
//*****************************************************************************
//
// UDMA_getChannelAttribute()
//
//*****************************************************************************
uint32_t
UDMA_getChannelAttribute(uint32_t base, uint32_t channelNum)
{
uint32_t channelAttr = 0U;
uint32_t offset = 1U << channelNum;
//
// Check the arguments.
//
ASSERT(UDMA_isBaseValid(base));
ASSERT((channelNum & 0xFFFFU) < 32U);
//
// Check to see if useburst bit is set for this channel.
//
if((HWREG(base + UDMA_O_DMAUSEBURSTSET) & offset) == offset)
{
channelAttr |= UDMA_CH_ATTR_USEBURST;
}
//
// Check to see if the alternate control bit is set for this channel.
//
if((HWREG(base + UDMA_O_DMAALTSET) & offset) == offset)
{
channelAttr |= UDMA_CH_ATTR_ALTSELECT;
}
//
// Check to see if the high priority bit is set for this channel.
//
if((HWREG(base + UDMA_O_DMAPRIOSET) & offset) == offset)
{
channelAttr |= UDMA_CH_ATTR_HIGH_PRIORITY;
}
//
// Check to see if the request mask bit is set for this channel.
//
if((HWREG(base + UDMA_O_DMAREQMASKSET) & offset) == offset)
{
channelAttr |= UDMA_CH_ATTR_REQMASK;
}
//
// Return the configuration flags.
//
return(channelAttr);
}
//*****************************************************************************
//
// UDMA_setChannelTransferParams()
//
//*****************************************************************************
extern void
UDMA_setChannelTransferParams(uint32_t base, uint32_t index, void *srcAddr,
void *dstAddr, uint32_t transferMode,
uint32_t transferSize)
{
UDMA_ControlTable *controlTable;
uint32_t chControlAttr;
uint32_t addrInc;
uint32_t bufferBytes;
uint32_t txModeTemp, srcAddrTemp, dstAddrTemp;
//
// Check the arguments.
//
ASSERT(UDMA_isBaseValid(base));
ASSERT(index < 64U);
ASSERT(HWREG(base + UDMA_O_DMACTLBASE) != 0U);
ASSERT(transferMode <= UDMA_MODE_PER_SCATTER_GATHER);
ASSERT((uint32_t)srcAddr >= 0x20000000U);
ASSERT((uint32_t)dstAddr >= 0x20000000U);
ASSERT((transferSize != 0U) && (transferSize <= 1024U));
//
// Get the base address of the control table.
//
controlTable = (UDMA_ControlTable *)HWREG(base + UDMA_O_DMACTLBASE);
ASSERT(controlTable != 0U);
//
// Get the current control word value and mask off the mode and size
// fields.
//
chControlAttr = (controlTable[index].chControlAttr &
~(UDMA_DMACHCTL_XFERSIZE_M | UDMA_DMACHCTL_XFERMODE_M));
//
// Adjust the mode if the alt control structure is selected.
//
if((index & UDMA_ALT_SELECT) == UDMA_ALT_SELECT)
{
if((transferMode == UDMA_MODE_MEM_SCATTER_GATHER) ||
(transferMode == UDMA_MODE_PER_SCATTER_GATHER))
{
txModeTemp = transferMode | UDMA_MODE_ALT_SELECT;
}
else
{
txModeTemp = transferMode;
}
}
else
{
txModeTemp = transferMode;
}
//
// Set the transfer size and mode in the control word (but don't write the
// control word yet as it could kick off a transfer).
//
chControlAttr |= txModeTemp |
((transferSize - 1U) << UDMA_DMACHCTL_XFERSIZE_S);
//
// Get the address increment value for the source, from the control word.
//
addrInc = (chControlAttr & UDMA_DMACHCTL_SRCINC_M);
//
// Compute the ending source address of the transfer. If the source
// increment is set to none, then the ending address is the same as the
// beginning.
//
if(addrInc != UDMA_SRC_INC_NONE)
{
addrInc = addrInc >> UDMA_DMACHCTL_SRCINC_S;
bufferBytes = transferSize << addrInc;
srcAddrTemp = ((uint32_t)srcAddr + bufferBytes - 1U);
}
else
{
srcAddrTemp = (uint32_t)srcAddr;
}
//
// Load the source ending address into the control block.
//
controlTable[index].srcEndAddr = (void *)srcAddrTemp;
//
// Get the address increment value for the destination, from the control
// word.
//
addrInc = chControlAttr & UDMA_DMACHCTL_DSTINC_M;
//
// Compute the ending destination address of the transfer. If the
// destination increment is set to none, then the ending address is the
// same as the beginning.
//
if(addrInc != UDMA_DST_INC_NONE)
{
//
// There is a special case if this is setting up a scatter-gather
// transfer. The destination pointer must point to the end of
// the alternate structure for this channel instead of calculating
// the end of the buffer in the normal way.
//
if((transferMode == UDMA_MODE_MEM_SCATTER_GATHER) ||
(transferMode == UDMA_MODE_PER_SCATTER_GATHER))
{
dstAddrTemp = (uint32_t)&controlTable[index |
UDMA_ALT_SELECT].spare;
}
//
// Not a scatter-gather transfer, calculate end pointer normally.
//
else
{
addrInc = addrInc >> UDMA_DMACHCTL_DSTINC_S;
bufferBytes = transferSize << addrInc;
dstAddrTemp = ((uint32_t)dstAddr + bufferBytes - 1U);
}
}
else
{
dstAddrTemp = (uint32_t)dstAddr;
}
//
// Load the destination ending address into the control block.
//
controlTable[index].dstEndAddr = (void *)dstAddrTemp;
//
// Write the new control word value.
//
controlTable[index].chControlAttr = chControlAttr;
}
//*****************************************************************************
//
// UDMA_getChannelTransferSize()
//
//*****************************************************************************
uint32_t
UDMA_getChannelTransferSize(uint32_t base, uint32_t index)
{
UDMA_ControlTable *controlTable;
uint32_t chControlAttr, txSize;
//
// Check the arguments.
//
ASSERT(UDMA_isBaseValid(base));
ASSERT((index & 0xFFFFU) < 64U);
ASSERT(HWREG(base + UDMA_O_DMACTLBASE) != 0U);
//
// Get the base address of the control table.
//
controlTable = (UDMA_ControlTable *)HWREG(base + UDMA_O_DMACTLBASE);
ASSERT(controlTable != 0U);
//
// Get the current control word value and mask off all but the size field
// and the mode field.
//
chControlAttr = (controlTable[index].chControlAttr &
(UDMA_DMACHCTL_XFERSIZE_M | UDMA_DMACHCTL_XFERMODE_M));
//
// If the size field and mode field are 0 then the transfer is finished
// and there are no more items to transfer
//
if(chControlAttr == 0U)
{
txSize = 0U;
}
//
// Otherwise, if either the size field or more field is non-zero, then
// not all the items have been transferred.
//
else
{
//
// Shift the size field and add one, then return to user.
//
txSize = (chControlAttr >> UDMA_DMACHCTL_XFERSIZE_S) + 1U;
}
return(txSize);
}
//*****************************************************************************
//
// UDMA_setChannelScatterGatherMode()
//
//*****************************************************************************
void
UDMA_setChannelScatterGatherMode(uint32_t base, uint32_t channelNum,
uint32_t taskCount, UDMA_ControlTable *taskList,
bool isPeriphScatterGather)
{
volatile UDMA_ControlTable *controlTable;
UDMA_ControlTable *taskTable;
//
// Check the parameters
//
ASSERT(UDMA_isBaseValid(base));
ASSERT(channelNum < 32U);
ASSERT(HWREG(base + UDMA_O_DMACTLBASE) != 0U);
ASSERT(taskList != 0U);
ASSERT((taskCount != 0U) && (taskCount <= 1024U));
//
// Get the base address of the control table.
//
controlTable = (UDMA_ControlTable *)HWREG(base + UDMA_O_DMACTLBASE);
//
// Get a handy pointer to the task list.
//
taskTable = taskList;
ASSERT(taskTable);
//
// Compute the ending address for the source pointer. This address is the
// last element of the last task in the task table.
//
controlTable[channelNum].srcEndAddr = &taskTable[taskCount - 1U].spare;
//
// Compute the ending address for the destination pointer. This address
// is the end of the alternate structure for this channel.
//
controlTable[channelNum].dstEndAddr = &controlTable[channelNum |
UDMA_ALT_SELECT].spare;
//
// Compute the control word. Most configurable items are fixed for
// scatter-gather. Item and increment sizes are all 32-bit and arb
// size must be 4. The count is the number of items in the task list
// times 4 (4 words per task).
//
controlTable[channelNum].chControlAttr =
(UDMA_DST_INC_32 | UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_ARB_4 |
((uint32_t)((taskCount * 4U) - 1U) << UDMA_DMACHCTL_XFERSIZE_S) |
((isPeriphScatterGather == true) ? UDMA_MODE_PER_SCATTER_GATHER :
UDMA_MODE_MEM_SCATTER_GATHER));
//
// Scatter-gather operations can leave the alt bit set. So if doing
// back to back scatter-gather transfers, the second attempt may not
// work correctly because the alt bit is set. Therefore, clear the
// alt bit here to ensure that it is always cleared before a new SG
// transfer is started.
//
HWREG(base + UDMA_O_DMAALTCLR) = 1U << channelNum;
}