📄 udma.c
字号:
//!
//! This function is used to set the parameters for a uDMA transfer. These are
//! typically parameters that are changed often. The function
//! uDMAChannelControlSet() MUST be called at least once for this channel prior
//! to calling this function.
//!
//! The \e ulChannel parameter is one of the choices documented in the
//! uDMAChannelEnable() function. It should be the logical OR of the channel
//! with either \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT to choose whether the
//! primary or alternate data structure is used.
//!
//! The \e ulMode parameter should be one of the following values:
//!
//! - \b UDMA_MODE_STOP stops the uDMA transfer. The controller sets the mode
//! to this value at the end of a transfer.
//! - \b UDMA_MODE_BASIC to perform a basic transfer based on request.
//! - \b UDMA_MODE_AUTO to perform a transfer that will always complete once
//! started even if request is removed.
//! - \b UDMA_MODE_PINGPONG to set up a transfer that switches between the
//! primary and alternate control structures for the channel. This allows
//! use of ping-pong buffering for uDMA transfers.
//! - \b UDMA_MODE_MEM_SCATTER_GATHER to set up a memory scatter-gather
//! transfer.
//! - \b UDMA_MODE_PER_SCATTER_GATHER to set up a peripheral scatter-gather
//! transfer.
//!
//! The \e pvSrcAddr and \e pvDstAddr parameters are pointers to the first
//! location of the data to be transferred. These addresses should be aligned
//! according to the item size. The compiler will take care of this if the
//! pointers are pointing to storage of the appropriate data type.
//!
//! The \e ulTransferSize parameter is the number of data items, not the number
//! of bytes.
//!
//! The two scatter/gather modes, memory and peripheral, are actually different
//! depending on whether the primary or alternate control structure is
//! selected. This function will look for the \b UDMA_PRI_SELECT and
//! \b UDMA_ALT_SELECT flag along with the channel number and will set the
//! scatter/gather mode as appropriate for the primary or alternate control
//! structure.
//!
//! The channel must also be enabled using uDMAChannelEnable() after calling
//! this function. The transfer will not begin until the channel has been set
//! up and enabled. Note that the channel is automatically disabled after the
//! transfer is completed, meaning that uDMAChannelEnable() must be called
//! again after setting up the next transfer.
//!
//! \note Great care must be taken to not modify a channel control stucture
//! that is in use or else the results will be unpredictable, including the
//! possibility of undesired data transfers to or from memory or peripherals.
//! For BASIC and AUTO modes, it is safe to make changes when the channel is
//! disabled, or the uDMAChannelModeGet() returns \b UDMA_MODE_STOP. For
//! PINGPONG or one of the SCATTER_GATHER modes, it is safe to modify the
//! primary or alternate control structure only when the other is being used.
//! The uDMAChannelModeGet() function will return \b UDMA_MODE_STOP when a
//! channel control structure is inactive and safe to modify.
//!
//! \return None.
//
//*****************************************************************************
void
uDMAChannelTransferSet(unsigned long ulChannel, unsigned long ulMode,
void *pvSrcAddr, void *pvDstAddr,
unsigned long ulTransferSize)
{
tDMAControlTable *pControlTable;
unsigned long ulControl;
unsigned long ulSize;
unsigned long ulInc;
//
// Check the arguments.
//
ASSERT(ulChannel < 64);
ASSERT(HWREG(UDMA_CTLBASE) != 0);
ASSERT(ulMode <= UDMA_MODE_PER_SCATTER_GATHER);
ASSERT((unsigned long)pvSrcAddr >= 0x20000000);
ASSERT((unsigned long)pvDstAddr >= 0x20000000);
ASSERT((ulTransferSize != 0) && (ulTransferSize <= 1024));
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(UDMA_CTLBASE);
//
// Get the current control word value and mask off the mode and size
// fields.
//
ulControl = (pControlTable[ulChannel].ulControl &
~(UDMA_CHCTL_XFERSIZE_M | UDMA_CHCTL_XFERMODE_M));
//
// Adjust the mode if the alt control structure is selected.
//
if(ulChannel & UDMA_ALT_SELECT)
{
if((ulMode == UDMA_MODE_MEM_SCATTER_GATHER) ||
(ulMode == UDMA_MODE_PER_SCATTER_GATHER))
{
ulMode |= UDMA_MODE_ALT_SELECT;
}
}
//
// Set the transfer size and mode in the control word (but dont write the
// control word yet as it could kick off a transfer).
//
ulControl |= ulMode | ((ulTransferSize - 1) << 4);
//
// Get the data item size from the control word (set previously).
//
ulSize = (ulControl & UDMA_CHCTL_DSTSIZE_M) >> 28;
//
// Convert the transfer size to be in units of bytes. Shift (multiply) to
// get the value in bytes, based on the data item size.
//
ulTransferSize = ulTransferSize << ulSize;
//
// Get the address increment value for the source, from the control word.
//
ulInc = (ulControl & UDMA_CHCTL_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(ulInc != UDMA_SRC_INC_NONE)
{
pvSrcAddr = (void *)((unsigned long)pvSrcAddr + ulTransferSize - 1);
}
//
// Load the source ending address into the control block.
//
pControlTable[ulChannel].pvSrcEndAddr = pvSrcAddr;
//
// Get the address increment value for the destination, from the control
// word.
//
ulInc = (ulControl & UDMA_CHCTL_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(ulInc != UDMA_DST_INC_NONE)
{
pvDstAddr = (void *)((unsigned long)pvDstAddr + ulTransferSize - 1);
}
//
// Load the destination ending address into the control block.
//
pControlTable[ulChannel].pvDstEndAddr = pvDstAddr;
//
// Write the new control word value.
//
pControlTable[ulChannel].ulControl = ulControl;
}
//*****************************************************************************
//
//! Gets the current transfer size for a uDMA channel.
//!
//! \param ulChannel is the logical or of the uDMA channel number with either
//! \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT.
//!
//! This function is used to get the uDMA transfer size for a channel. The
//! transfer size is the number of items to transfer, where the size of an item
//! might be 8, 16, or 32 bits. If a partial transfer has already occurred,
//! then the number of remaining items will be returned. If the transfer is
//! complete, then 0 will be returned.
//!
//! The \e ulChannel parameter is one of the choices documented in the
//! uDMAChannelEnable() function. It should be the logical OR of the channel
//! with either \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT to choose whether
//! the primary or alternate data structure is used.
//!
//! \return Returns the number of items remaining to transfer.
//
//*****************************************************************************
unsigned long
uDMAChannelSizeGet(unsigned long ulChannel)
{
tDMAControlTable *pControlTable;
unsigned long ulControl;
//
// Check the arguments.
//
ASSERT(ulChannel < 64);
ASSERT(HWREG(UDMA_CTLBASE) != 0);
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(UDMA_CTLBASE);
//
// Get the current control word value and mask off all but the size field.
//
ulControl = pControlTable[ulChannel].ulControl & UDMA_CHCTL_XFERSIZE_M;
//
// Shift the size field and add one, then return to user.
//
return((ulControl >> 4) + 1);
}
//*****************************************************************************
//
//! Gets the transfer mode for a uDMA channel.
//!
//! \param ulChannel is the logical or of the uDMA channel number with either
//! \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT.
//!
//! This function is used to get the transfer mode for the uDMA channel. It
//! can be used to query the status of a transfer on a channel. When the
//! transfer is complete the mode will be \b UDMA_MODE_STOP.
//!
//! The \e ulChannel parameter is one of the choices documented in the
//! uDMAChannelEnable() function. It should be the logical OR of the channel
//! with either \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT to choose whether the
//! primary or alternate data structure is used.
//!
//! \return Returns the transfer mode of the specified channel and control
//! structure, which will be one of the following values: \b UDMA_MODE_STOP,
//! \b UDMA_MODE_BASIC, \b UDMA_MODE_AUTO, \b UDMA_MODE_PINGPONG,
//! \b UDMA_MODE_MEM_SCATTER_GATHER, or \b UDMA_MODE_PER_SCATTER_GATHER.
//
//*****************************************************************************
unsigned long
uDMAChannelModeGet(unsigned long ulChannel)
{
tDMAControlTable *pControlTable;
unsigned long ulControl;
//
// Check the arguments.
//
ASSERT(ulChannel < 64);
ASSERT(HWREG(UDMA_CTLBASE) != 0);
//
// Get the base address of the control table.
//
pControlTable = (tDMAControlTable *)HWREG(UDMA_CTLBASE);
//
// Get the current control word value and mask off all but the mode field.
//
ulControl = pControlTable[ulChannel].ulControl & UDMA_CHCTL_XFERMODE_M;
//
// Check if scatter/gather mode, and if so, mask off the alt bit.
//
if(((ulControl & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_MEM_SCATTER_GATHER) ||
((ulControl & ~UDMA_MODE_ALT_SELECT) == UDMA_MODE_PER_SCATTER_GATHER))
{
ulControl &= ~UDMA_MODE_ALT_SELECT;
}
//
// Return the mode to the caller.
//
return(ulControl);
}
//*****************************************************************************
//
//! Registers an interrupt handler for the uDMA controller.
//!
//! \param ulIntChannel identifies which uDMA interrupt is to be registered.
//! \param pfnHandler is a pointer to the function to be called when the
//! interrupt is activated.
//!
//! This sets and enables the handler to be called when the uDMA controller
//! generates an interrupt. The \e ulIntChannel parameter should be one of the
//! following:
//!
//! - \b UDMA_INT_SW to register an interrupt handler to process interrupts
//! from the uDMA software channel (UDMA_CHANNEL_SW)
//! - \b UDMA_INT_ERR to register an interrupt handler to process uDMA error
//! interrupts
//!
//! \sa IntRegister() for important information about registering interrupt
//! handlers.
//!
//! \note The interrupt handler for uDMA is for transfer completion when the
//! channel UDMA_CHANNEL_SW is used, and for error interrupts. The
//! interrupts for each peripheral channel are handled through the individual
//! peripheral interrupt handlers.
//!
//! \return None.
//
//*****************************************************************************
void
uDMAIntRegister(unsigned long ulIntChannel, void (*pfnHandler)(void))
{
//
// Check the arguments.
//
ASSERT(pfnHandler);
ASSERT((ulIntChannel == UDMA_INT_SW) || (ulIntChannel == UDMA_INT_ERR));
//
// Register the interrupt handler.
//
IntRegister(ulIntChannel, pfnHandler);
//
// Enable the memory management fault.
//
IntEnable(ulIntChannel);
}
//*****************************************************************************
//
//! Unregisters an interrupt handler for the uDMA controller.
//!
//! \param ulIntChannel identifies which uDMA interrupt to unregister.
//!
//! This function will disable and clear the handler to be called for the
//! specified uDMA interrupt. The \e ulIntChannel parameter should be one of
//! \b UDMA_INT_SW or \b UDMA_INT_ERR as documented for the function
//! uDMAIntRegister().
//!
//! \sa IntRegister() for important information about registering interrupt
//! handlers.
//!
//! \return None.
//
//*****************************************************************************
void
uDMAIntUnregister(unsigned long ulIntChannel)
{
//
// Disable the interrupt.
//
IntDisable(ulIntChannel);
//
// Unregister the interrupt handler.
//
IntUnregister(ulIntChannel);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -