| //***************************************************************************** |
| // |
| // udma.c |
| // |
| // Driver for the micro-DMA controller. |
| // |
| // Copyright (C) 2014 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. |
| // |
| //***************************************************************************** |
| |
| //***************************************************************************** |
| // |
| //! \addtogroup uDMA_Micro_Direct_Memory_Access_api |
| //! @{ |
| // |
| //***************************************************************************** |
| |
| |
| #include "inc/hw_types.h" |
| #include "inc/hw_udma.h" |
| #include "inc/hw_ints.h" |
| #include "inc/hw_memmap.h" |
| #include "debug.h" |
| #include "interrupt.h" |
| #include "udma.h" |
| |
| |
| //***************************************************************************** |
| // |
| //! Enables the uDMA controller for use. |
| //! |
| //! This function enables the uDMA controller. The uDMA controller must be |
| //! enabled before it can be configured and used. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAEnable(void) |
| { |
| // |
| // Set the master enable bit in the config register. |
| // |
| HWREG(UDMA_BASE + UDMA_O_CFG) = UDMA_CFG_MASTEN; |
| } |
| |
| //***************************************************************************** |
| // |
| //! Disables the uDMA controller for use. |
| //! |
| //! This function disables the uDMA controller. Once disabled, the uDMA |
| //! controller cannot operate until re-enabled with uDMAEnable(). |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMADisable(void) |
| { |
| // |
| // Clear the master enable bit in the config register. |
| // |
| HWREG(UDMA_BASE + UDMA_O_CFG) = 0; |
| } |
| |
| //***************************************************************************** |
| // |
| //! Gets the uDMA error status. |
| //! |
| //! This function returns the uDMA error status. It should be called from |
| //! within the uDMA error interrupt handler to determine if a uDMA error |
| //! occurred. |
| //! |
| //! \return Returns non-zero if a uDMA error is pending. |
| // |
| //***************************************************************************** |
| unsigned long |
| uDMAErrorStatusGet(void) |
| { |
| // |
| // Return the uDMA error status. |
| // |
| return(HWREG(UDMA_BASE + UDMA_O_ERRCLR)); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Clears the uDMA error interrupt. |
| //! |
| //! This function clears a pending uDMA error interrupt. This function should |
| //! be called from within the uDMA error interrupt handler to clear the |
| //! interrupt. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAErrorStatusClear(void) |
| { |
| // |
| // Clear the uDMA error interrupt. |
| // |
| HWREG(UDMA_BASE + UDMA_O_ERRCLR) = 1; |
| } |
| |
| //***************************************************************************** |
| // |
| //! Enables a uDMA channel for operation. |
| //! |
| //! \param ulChannelNum is the channel number to enable. |
| //! |
| //! This function enables a specific uDMA channel for use. This function must |
| //! be used to enable a channel before it can be used to perform a uDMA |
| //! transfer. |
| //! |
| //! When a uDMA transfer is completed, the channel is automatically disabled by |
| //! the uDMA controller. Therefore, this function should be called prior to |
| //! starting up any new transfer. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelEnable(unsigned long ulChannelNum) |
| { |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| |
| // |
| // Set the bit for this channel in the enable set register. |
| // |
| HWREG(UDMA_BASE + UDMA_O_ENASET) = 1 << (ulChannelNum & 0x1f); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Disables a uDMA channel for operation. |
| //! |
| //! \param ulChannelNum is the channel number to disable. |
| //! |
| //! This function disables a specific uDMA channel. Once disabled, a channel |
| //! cannot respond to uDMA transfer requests until re-enabled via |
| //! uDMAChannelEnable(). |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelDisable(unsigned long ulChannelNum) |
| { |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| |
| // |
| // Set the bit for this channel in the enable clear register. |
| // |
| HWREG(UDMA_BASE + UDMA_O_ENACLR) = 1 << (ulChannelNum & 0x1f); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Checks if a uDMA channel is enabled for operation. |
| //! |
| //! \param ulChannelNum is the channel number to check. |
| //! |
| //! This function checks to see if a specific uDMA channel is enabled. This |
| //! function can be used to check the status of a transfer, as the channel is |
| //! automatically disabled at the end of a transfer. |
| //! |
| //! \return Returns \b true if the channel is enabled, \b false if disabled. |
| // |
| //***************************************************************************** |
| tBoolean |
| uDMAChannelIsEnabled(unsigned long ulChannelNum) |
| { |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| |
| // |
| // AND the specified channel bit with the enable register and return the |
| // result. |
| // |
| return((HWREG(UDMA_BASE + UDMA_O_ENASET) & |
| (1 << (ulChannelNum & 0x1f))) ? true : false); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Sets the base address for the channel control table. |
| //! |
| //! \param pControlTable is a pointer to the 1024-byte-aligned base address |
| //! of the uDMA channel control table. |
| //! |
| //! This function configures the base address of the channel control table. |
| //! This table resides in system memory and holds control information for each |
| //! uDMA channel. The table must be aligned on a 1024-byte boundary. The base |
| //! address must be configured before any of the channel functions can be used. |
| //! |
| //! The size of the channel control table depends on the number of uDMA |
| //! channels and the transfer modes that are used. Refer to the introductory |
| //! text and the microcontroller datasheet for more information about the |
| //! channel control table. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAControlBaseSet(void *pControlTable) |
| { |
| // |
| // Check the arguments. |
| // |
| ASSERT(((unsigned long)pControlTable & ~0x3FF) == |
| (unsigned long)pControlTable); |
| ASSERT((unsigned long)pControlTable >= 0x20000000); |
| |
| // |
| // Program the base address into the register. |
| // |
| HWREG(UDMA_BASE + UDMA_O_CTLBASE) = (unsigned long)pControlTable; |
| } |
| |
| //***************************************************************************** |
| // |
| //! Gets the base address for the channel control table. |
| //! |
| //! This function gets the base address of the channel control table. This |
| //! table resides in system memory and holds control information for each uDMA |
| //! channel. |
| //! |
| //! \return Returns a pointer to the base address of the channel control table. |
| // |
| //***************************************************************************** |
| void * |
| uDMAControlBaseGet(void) |
| { |
| // |
| // Read the current value of the control base register and return it to |
| // the caller. |
| // |
| return((void *)HWREG(UDMA_BASE + UDMA_O_CTLBASE)); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Gets the base address for the channel control table alternate structures. |
| //! |
| //! This function gets the base address of the second half of the channel |
| //! control table that holds the alternate control structures for each channel. |
| //! |
| //! \return Returns a pointer to the base address of the second half of the |
| //! channel control table. |
| // |
| //***************************************************************************** |
| void * |
| uDMAControlAlternateBaseGet(void) |
| { |
| // |
| // Read the current value of the control base register and return it to |
| // the caller. |
| // |
| return((void *)HWREG(UDMA_BASE + UDMA_O_ALTBASE)); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Requests a uDMA channel to start a transfer. |
| //! |
| //! \param ulChannelNum is the channel number on which to request a uDMA |
| //! transfer. |
| //! |
| //! This function allows software to request a uDMA channel to begin a |
| //! transfer. This function could be used for performing a memory-to-memory |
| //! transfer or if for some reason, a transfer needs to be initiated by software |
| //! instead of the peripheral associated with that channel. |
| //! |
| //! \note If the channel is \b UDMA_CHANNEL_SW and interrupts are used, then |
| //! the completion is signaled on the uDMA dedicated interrupt. If a |
| //! peripheral channel is used, then the completion is signaled on the |
| //! peripheral's interrupt. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelRequest(unsigned long ulChannelNum) |
| { |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| |
| // |
| // Set the bit for this channel in the software uDMA request register. |
| // |
| HWREG(UDMA_BASE + UDMA_O_SWREQ) = 1 << (ulChannelNum & 0x1f); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Enables attributes of a uDMA channel. |
| //! |
| //! \param ulChannelNum is the channel to configure. |
| //! \param ulAttr is a combination of attributes for the channel. |
| //! |
| //! This function is used to enable attributes of a uDMA channel. |
| //! |
| //! The \e ulAttr parameter is the logical OR of any of the following: |
| //! |
| //! - \b UDMA_ATTR_USEBURST is used to restrict transfers to use only burst |
| //! mode. |
| //! - \b UDMA_ATTR_ALTSELECT is used to select the alternate control structure |
| //! for this channel (it is very unlikely that this flag should be used). |
| //! - \b UDMA_ATTR_HIGH_PRIORITY is used to set this channel to high priority. |
| //! - \b UDMA_ATTR_REQMASK is used to mask the hardware request signal from the |
| //! peripheral for this channel. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelAttributeEnable(unsigned long ulChannelNum, unsigned long ulAttr) |
| { |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| ASSERT((ulAttr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | |
| UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelNum parameter, extract just the channel number |
| // from this parameter. |
| // |
| ulChannelNum &= 0x1f; |
| |
| // |
| // Set the useburst bit for this channel if set in ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_USEBURST) |
| { |
| HWREG(UDMA_BASE + UDMA_O_USEBURSTSET) = 1 << ulChannelNum; |
| } |
| |
| // |
| // Set the alternate control select bit for this channel, |
| // if set in ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_ALTSELECT) |
| { |
| HWREG(UDMA_BASE + UDMA_O_ALTSET) = 1 << ulChannelNum; |
| } |
| |
| // |
| // Set the high priority bit for this channel, if set in ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_HIGH_PRIORITY) |
| { |
| HWREG(UDMA_BASE + UDMA_O_PRIOSET) = 1 << ulChannelNum; |
| } |
| |
| // |
| // Set the request mask bit for this channel, if set in ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_REQMASK) |
| { |
| HWREG(UDMA_BASE + UDMA_O_REQMASKSET) = 1 << ulChannelNum; |
| } |
| } |
| |
| //***************************************************************************** |
| // |
| //! Disables attributes of a uDMA channel. |
| //! |
| //! \param ulChannelNum is the channel to configure. |
| //! \param ulAttr is a combination of attributes for the channel. |
| //! |
| //! This function is used to disable attributes of a uDMA channel. |
| //! |
| //! The \e ulAttr parameter is the logical OR of any of the following: |
| //! |
| //! - \b UDMA_ATTR_USEBURST is used to restrict transfers to use only burst |
| //! mode. |
| //! - \b UDMA_ATTR_ALTSELECT is used to select the alternate control structure |
| //! for this channel. |
| //! - \b UDMA_ATTR_HIGH_PRIORITY is used to set this channel to high priority. |
| //! - \b UDMA_ATTR_REQMASK is used to mask the hardware request signal from the |
| //! peripheral for this channel. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelAttributeDisable(unsigned long ulChannelNum, unsigned long ulAttr) |
| { |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| ASSERT((ulAttr & ~(UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | |
| UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)) == 0); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelNum parameter, extract just the channel number |
| // from this parameter. |
| // |
| ulChannelNum &= 0x1f; |
| |
| // |
| // Clear the useburst bit for this channel if set in ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_USEBURST) |
| { |
| HWREG(UDMA_BASE + UDMA_O_USEBURSTCLR) = 1 << ulChannelNum; |
| } |
| |
| // |
| // Clear the alternate control select bit for this channel, if set in |
| // ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_ALTSELECT) |
| { |
| HWREG(UDMA_BASE + UDMA_O_ALTCLR) = 1 << ulChannelNum; |
| } |
| |
| // |
| // Clear the high priority bit for this channel, if set in ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_HIGH_PRIORITY) |
| { |
| HWREG(UDMA_BASE + UDMA_O_PRIOCLR) = 1 << ulChannelNum; |
| } |
| |
| // |
| // Clear the request mask bit for this channel, if set in ulConfig. |
| // |
| if(ulAttr & UDMA_ATTR_REQMASK) |
| { |
| HWREG(UDMA_BASE + UDMA_O_REQMASKCLR) = 1 << ulChannelNum; |
| } |
| } |
| |
| //***************************************************************************** |
| // |
| //! Gets the enabled attributes of a uDMA channel. |
| //! |
| //! \param ulChannelNum is the channel to configure. |
| //! |
| //! This function returns a combination of flags representing the attributes of |
| //! the uDMA channel. |
| //! |
| //! \return Returns the logical OR of the attributes of the uDMA channel, which |
| //! can be any of the following: |
| //! - \b UDMA_ATTR_USEBURST is used to restrict transfers to use only burst |
| //! mode. |
| //! - \b UDMA_ATTR_ALTSELECT is used to select the alternate control structure |
| //! for this channel. |
| //! - \b UDMA_ATTR_HIGH_PRIORITY is used to set this channel to high priority. |
| //! - \b UDMA_ATTR_REQMASK is used to mask the hardware request signal from the |
| //! peripheral for this channel. |
| // |
| //***************************************************************************** |
| unsigned long |
| uDMAChannelAttributeGet(unsigned long ulChannelNum) |
| { |
| unsigned long ulAttr = 0; |
| |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelNum parameter, extract just the channel number |
| // from this parameter. |
| // |
| ulChannelNum &= 0x1f; |
| |
| // |
| // Check to see if useburst bit is set for this channel. |
| // |
| if(HWREG(UDMA_BASE + UDMA_O_USEBURSTSET) & (1 << ulChannelNum)) |
| { |
| ulAttr |= UDMA_ATTR_USEBURST; |
| } |
| |
| // |
| // Check to see if the alternate control bit is set for this channel. |
| // |
| if(HWREG(UDMA_BASE + UDMA_O_ALTSET) & (1 << ulChannelNum)) |
| { |
| ulAttr |= UDMA_ATTR_ALTSELECT; |
| } |
| |
| // |
| // Check to see if the high priority bit is set for this channel. |
| // |
| if(HWREG(UDMA_BASE + UDMA_O_PRIOSET) & (1 << ulChannelNum)) |
| { |
| ulAttr |= UDMA_ATTR_HIGH_PRIORITY; |
| } |
| |
| // |
| // Check to see if the request mask bit is set for this channel. |
| // |
| if(HWREG(UDMA_BASE + UDMA_O_REQMASKSET) & (1 << ulChannelNum)) |
| { |
| ulAttr |= UDMA_ATTR_REQMASK; |
| } |
| |
| // |
| // Return the configuration flags. |
| // |
| return(ulAttr); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Sets the control parameters for a uDMA channel control structure. |
| //! |
| //! \param ulChannelStructIndex is the logical OR of the uDMA channel number |
| //! with \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT. |
| //! \param ulControl is logical OR of several control values to set the control |
| //! parameters for the channel. |
| //! |
| //! This function is used to set control parameters for a uDMA transfer. These |
| //! parameters are typically not changed often. |
| //! |
| //! The \e ulChannelStructIndex parameter should be the logical OR of the |
| //! channel number with one of \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT to |
| //! choose whether the primary or alternate data structure is used. |
| //! |
| //! The \e ulControl parameter is the logical OR of five values: the data size, |
| //! the source address increment, the destination address increment, the |
| //! arbitration size, and the use burst flag. The choices available for each |
| //! of these values is described below. |
| //! |
| //! Choose the data size from one of \b UDMA_SIZE_8, \b UDMA_SIZE_16, or |
| //! \b UDMA_SIZE_32 to select a data size of 8, 16, or 32 bits. |
| //! |
| //! Choose the source address increment from one of \b UDMA_SRC_INC_8, |
| //! \b UDMA_SRC_INC_16, \b UDMA_SRC_INC_32, or \b UDMA_SRC_INC_NONE to select |
| //! an address increment of 8-bit bytes, 16-bit halfwords, 32-bit words, or |
| //! to select non-incrementing. |
| //! |
| //! Choose the destination address increment from one of \b UDMA_DST_INC_8, |
| //! \b UDMA_DST_INC_16, \b UDMA_DST_INC_32, or \b UDMA_DST_INC_NONE to select |
| //! an address increment of 8-bit bytes, 16-bit halfwords, 32-bit words, or |
| //! to select non-incrementing. |
| //! |
| //! The arbitration size determines how many items are transferred before |
| //! the uDMA controller re-arbitrates for the bus. Choose the arbitration size |
| //! from one of \b UDMA_ARB_1, \b UDMA_ARB_2, \b UDMA_ARB_4, \b UDMA_ARB_8, |
| //! through \b UDMA_ARB_1024 to select the arbitration size from 1 to 1024 |
| //! items, in powers of 2. |
| //! |
| //! The value \b UDMA_NEXT_USEBURST is used to force the channel to only |
| //! respond to burst requests at the tail end of a scatter-gather transfer. |
| //! |
| //! \note The address increment cannot be smaller than the data size. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelControlSet(unsigned long ulChannelStructIndex, |
| unsigned long ulControl) |
| { |
| tDMAControlTable *pCtl; |
| |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelStructIndex & 0xffff) < 64); |
| ASSERT(HWREG(UDMA_BASE + UDMA_O_CTLBASE) != 0); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelStructIndex parameter, extract just the channel |
| // index from this parameter. |
| // |
| ulChannelStructIndex &= 0x3f; |
| |
| // |
| // Get the base address of the control table. |
| // |
| pCtl = (tDMAControlTable *)HWREG(UDMA_BASE+UDMA_O_CTLBASE); |
| |
| // |
| // Get the current control word value and mask off the fields to be |
| // changed, then OR in the new settings. |
| // |
| pCtl[ulChannelStructIndex].ulControl = |
| ((pCtl[ulChannelStructIndex].ulControl & |
| ~(UDMA_CHCTL_DSTINC_M | |
| UDMA_CHCTL_DSTSIZE_M | |
| UDMA_CHCTL_SRCINC_M | |
| UDMA_CHCTL_SRCSIZE_M | |
| UDMA_CHCTL_ARBSIZE_M | |
| UDMA_CHCTL_NXTUSEBURST)) | |
| ulControl); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Sets the transfer parameters for a uDMA channel control structure. |
| //! |
| //! \param ulChannelStructIndex is the logical OR of the uDMA channel number |
| //! with either \b UDMA_PRI_SELECT or \b UDMA_ALT_SELECT. |
| //! \param ulMode is the type of uDMA transfer. |
| //! \param pvSrcAddr is the source address for the transfer. |
| //! \param pvDstAddr is the destination address for the transfer. |
| //! \param ulTransferSize is the number of data items to transfer. |
| //! |
| //! This function is used to configure the parameters for a uDMA transfer. |
| //! These parameters are typically changed often. The function |
| //! uDMAChannelControlSet() MUST be called at least once for this channel prior |
| //! to calling this function. |
| //! |
| //! The \e ulChannelStructIndex parameter should be the logical OR of the |
| //! channel number with one of \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 always completes once |
| //! started even if the 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 mode |
| //! 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 takes care of this alignment 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 value of this parameter should not exceed 1024. |
| //! |
| //! The two scatter-gather modes, memory and peripheral, are actually different |
| //! depending on whether the primary or alternate control structure is |
| //! selected. This function looks for the \b UDMA_PRI_SELECT and |
| //! \b UDMA_ALT_SELECT flag along with the channel number and sets 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 does not begin until the channel has been |
| //! configured 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 structure |
| //! that is in use or else the results are 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 returns \b UDMA_MODE_STOP when a |
| //! channel control structure is inactive and safe to modify. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelTransferSet(unsigned long ulChannelStructIndex, |
| unsigned long ulMode, void *pvSrcAddr, void *pvDstAddr, |
| unsigned long ulTransferSize) |
| { |
| tDMAControlTable *pControlTable; |
| unsigned long ulControl; |
| unsigned long ulInc; |
| unsigned long ulBufferBytes; |
| |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelStructIndex & 0xffff) < 64); |
| ASSERT(HWREG(UDMA_BASE + UDMA_O_CTLBASE) != 0); |
| ASSERT(ulMode <= UDMA_MODE_PER_SCATTER_GATHER); |
| ASSERT((unsigned long)pvSrcAddr >= 0x20000000); |
| ASSERT((unsigned long)pvDstAddr >= 0x20000000); |
| ASSERT((ulTransferSize != 0) && (ulTransferSize <= 1024)); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelStructIndex parameter, extract just the channel |
| // index from this parameter. |
| // |
| ulChannelStructIndex &= 0x3f; |
| |
| // |
| // Get the base address of the control table. |
| // |
| pControlTable = (tDMAControlTable *)HWREG(UDMA_BASE + UDMA_O_CTLBASE); |
| |
| // |
| // Get the current control word value and mask off the mode and size |
| // fields. |
| // |
| ulControl = (pControlTable[ulChannelStructIndex].ulControl & |
| ~(UDMA_CHCTL_XFERSIZE_M | UDMA_CHCTL_XFERMODE_M)); |
| |
| // |
| // Adjust the mode if the alt control structure is selected. |
| // |
| if(ulChannelStructIndex & 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 don't write the |
| // control word yet as it could kick off a transfer). |
| // |
| ulControl |= ulMode | ((ulTransferSize - 1) << 4); |
| |
| // |
| // 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) |
| { |
| ulInc = ulInc >> 26; |
| ulBufferBytes = ulTransferSize << ulInc; |
| pvSrcAddr = (void *)((unsigned long)pvSrcAddr + ulBufferBytes - 1); |
| } |
| |
| // |
| // Load the source ending address into the control block. |
| // |
| pControlTable[ulChannelStructIndex].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) |
| { |
| // |
| // 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((ulMode == UDMA_MODE_MEM_SCATTER_GATHER) || |
| (ulMode == UDMA_MODE_PER_SCATTER_GATHER)) |
| { |
| pvDstAddr = |
| (void *)&pControlTable[ulChannelStructIndex | |
| UDMA_ALT_SELECT].ulSpare; |
| } |
| // |
| // Not a scatter-gather transfer, calculate end pointer normally. |
| // |
| else |
| { |
| ulInc = ulInc >> 30; |
| ulBufferBytes = ulTransferSize << ulInc; |
| pvDstAddr = (void *)((unsigned long)pvDstAddr + ulBufferBytes - 1); |
| } |
| } |
| |
| // |
| // Load the destination ending address into the control block. |
| // |
| pControlTable[ulChannelStructIndex].pvDstEndAddr = pvDstAddr; |
| |
| // |
| // Write the new control word value. |
| // |
| pControlTable[ulChannelStructIndex].ulControl = ulControl; |
| } |
| |
| //***************************************************************************** |
| // |
| //! Configures a uDMA channel for scatter-gather mode. |
| //! |
| //! \param ulChannelNum is the uDMA channel number. |
| //! \param ulTaskCount is the number of scatter-gather tasks to execute. |
| //! \param pvTaskList is a pointer to the beginning of the scatter-gather |
| //! task list. |
| //! \param ulIsPeriphSG is a flag to indicate it is a peripheral scatter-gather |
| //! transfer (else it is memory scatter-gather transfer) |
| //! |
| //! This function is used to configure a channel for scatter-gather mode. |
| //! The caller must have already set up a task list and must pass a pointer to |
| //! the start of the task list as the \e pvTaskList parameter. The |
| //! \e ulTaskCount parameter is the count of tasks in the task list, not the |
| //! size of the task list. The flag \e bIsPeriphSG should be used to indicate |
| //! if scatter-gather should be configured for peripheral or memory |
| //! operation. |
| //! |
| //! \sa uDMATaskStructEntry |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelScatterGatherSet(unsigned long ulChannelNum, unsigned ulTaskCount, |
| void *pvTaskList, unsigned long ulIsPeriphSG) |
| { |
| tDMAControlTable *pControlTable; |
| tDMAControlTable *pTaskTable; |
| |
| // |
| // Check the parameters |
| // |
| ASSERT((ulChannelNum & 0xffff) < 32); |
| ASSERT(HWREG(UDMA_BASE + UDMA_O_CTLBASE) != 0); |
| ASSERT(pvTaskList != 0); |
| ASSERT(ulTaskCount <= 1024); |
| ASSERT(ulTaskCount != 0); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelNum parameter, extract just the channel number |
| // from this parameter. |
| // |
| ulChannelNum &= 0x1f; |
| |
| // |
| // Get the base address of the control table. |
| // |
| pControlTable = (tDMAControlTable *)HWREG(UDMA_BASE + UDMA_O_CTLBASE); |
| |
| // |
| // Get a handy pointer to the task list |
| // |
| pTaskTable = (tDMAControlTable *)pvTaskList; |
| |
| // |
| // Compute the ending address for the source pointer. This address is the |
| // last element of the last task in the task table |
| // |
| pControlTable[ulChannelNum].pvSrcEndAddr = |
| &pTaskTable[ulTaskCount - 1].ulSpare; |
| |
| // |
| // Compute the ending address for the destination pointer. This address |
| // is the end of the alternate structure for this channel. |
| // |
| pControlTable[ulChannelNum].pvDstEndAddr = |
| &pControlTable[ulChannelNum | UDMA_ALT_SELECT].ulSpare; |
| |
| // |
| // 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). |
| // |
| pControlTable[ulChannelNum].ulControl = |
| (UDMA_CHCTL_DSTINC_32 | UDMA_CHCTL_DSTSIZE_32 | |
| UDMA_CHCTL_SRCINC_32 | UDMA_CHCTL_SRCSIZE_32 | |
| UDMA_CHCTL_ARBSIZE_4 | |
| (((ulTaskCount * 4) - 1) << UDMA_CHCTL_XFERSIZE_S) | |
| (ulIsPeriphSG ? UDMA_CHCTL_XFERMODE_PER_SG : |
| UDMA_CHCTL_XFERMODE_MEM_SG)); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Gets the current transfer size for a uDMA channel control structure. |
| //! |
| //! \param ulChannelStructIndex 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 is returned. If the transfer is |
| //! complete, then 0 is returned. |
| //! |
| //! \return Returns the number of items remaining to transfer. |
| // |
| //***************************************************************************** |
| unsigned long |
| uDMAChannelSizeGet(unsigned long ulChannelStructIndex) |
| { |
| tDMAControlTable *pControlTable; |
| unsigned long ulControl; |
| |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelStructIndex & 0xffff) < 64); |
| ASSERT(HWREG(UDMA_BASE + UDMA_O_CTLBASE) != 0); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelStructIndex parameter, extract just the channel |
| // index from this parameter. |
| // |
| ulChannelStructIndex &= 0x3f; |
| |
| // |
| // Get the base address of the control table. |
| // |
| pControlTable = (tDMAControlTable *)HWREG(UDMA_BASE + UDMA_O_CTLBASE); |
| |
| // |
| // Get the current control word value and mask off all but the size field |
| // and the mode field. |
| // |
| ulControl = (pControlTable[ulChannelStructIndex].ulControl & |
| (UDMA_CHCTL_XFERSIZE_M | UDMA_CHCTL_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(ulControl == 0) |
| { |
| return(0); |
| } |
| |
| // |
| // 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. |
| // |
| return((ulControl >> 4) + 1); |
| } |
| } |
| |
| //***************************************************************************** |
| // |
| //! Gets the transfer mode for a uDMA channel control structure. |
| //! |
| //! \param ulChannelStructIndex 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 and |
| //! to query the status of a transfer on a channel. When the transfer is |
| //! complete the mode is \b UDMA_MODE_STOP. |
| //! |
| //! \return Returns the transfer mode of the specified channel and control |
| //! structure, which is 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 ulChannelStructIndex) |
| { |
| tDMAControlTable *pControlTable; |
| unsigned long ulControl; |
| |
| // |
| // Check the arguments. |
| // |
| ASSERT((ulChannelStructIndex & 0xffff) < 64); |
| ASSERT(HWREG(UDMA_O_CTLBASE) != 0); |
| |
| // |
| // In case a channel selector macro (like UDMA_CH0_USB0EP1RX) was |
| // passed as the ulChannelStructIndex parameter, extract just the channel |
| // index from this parameter. |
| // |
| ulChannelStructIndex &= 0x3f; |
| |
| // |
| // Get the base address of the control table. |
| // |
| pControlTable = (tDMAControlTable *)HWREG(UDMA_BASE + UDMA_O_CTLBASE); |
| |
| // |
| // Get the current control word value and mask off all but the mode field. |
| // |
| ulControl = (pControlTable[ulChannelStructIndex].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 function registers 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 the 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 disables and unregisters 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); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Gets the uDMA controller channel interrupt status. |
| //! |
| //! This function is used to get the interrupt status of the uDMA controller. |
| //! The returned value is a 32-bit bit mask that indicates which channels are |
| //! requesting an interrupt. This function can be used from within an |
| //! interrupt handler to determine or confirm which uDMA channel has requested |
| //! an interrupt. |
| //! |
| //! \note This function is only available on devices that have the DMA Channel |
| //! Interrupt Status Register (DMACHIS). Please consult the data sheet for |
| //! your part. |
| //! |
| //! \return Returns a 32-bit mask which indicates requesting uDMA channels. |
| //! There is a bit for each channel and a 1 indicates that the channel |
| //! is requesting an interrupt. Multiple bits can be set. |
| // |
| //***************************************************************************** |
| unsigned long |
| uDMAIntStatus(void) |
| { |
| |
| |
| // |
| // Return the value of the uDMA interrupt status register |
| // |
| return(HWREG(UDMA_BASE + UDMA_O_CHIS)); |
| } |
| |
| //***************************************************************************** |
| // |
| //! Clears uDMA interrupt status. |
| //! |
| //! \param ulChanMask is a 32-bit mask with one bit for each uDMA channel. |
| //! |
| //! This function clears bits in the uDMA interrupt status register according |
| //! to which bits are set in \e ulChanMask. There is one bit for each channel. |
| //! If a a bit is set in \e ulChanMask, then that corresponding channel's |
| //! interrupt status is cleared (if it was set). |
| //! |
| //! \note This function is only available on devices that have the DMA Channel |
| //! Interrupt Status Register (DMACHIS). Please consult the data sheet for |
| //! your part. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAIntClear(unsigned long ulChanMask) |
| { |
| |
| // |
| // Clear the requested bits in the uDMA interrupt status register |
| // |
| HWREG(UDMA_BASE + UDMA_O_CHIS) = ulChanMask; |
| } |
| |
| //***************************************************************************** |
| // |
| //! Assigns a peripheral mapping for a uDMA channel. |
| //! |
| //! \param ulMapping is a macro specifying the peripheral assignment for |
| //! a channel. |
| //! |
| //! This function assigns a peripheral mapping to a uDMA channel. It is |
| //! used to select which peripheral is used for a uDMA channel. The parameter |
| //! \e ulMapping should be one of the macros named \b UDMA_CHn_tttt from the |
| //! header file \e udma.h. For example, to assign uDMA channel 0 to the |
| //! UART2 RX channel, the parameter should be the macro \b UDMA_CH0_UART2RX. |
| //! |
| //! Please consult the data sheet for a table showing all the |
| //! possible peripheral assignments for the uDMA channels for a particular |
| //! device. |
| //! |
| //! \note This function is only available on devices that have the DMA Channel |
| //! Map Select registers (DMACHMAP0-3). Please consult the data sheet for |
| //! your part. |
| //! |
| //! \return None. |
| // |
| //***************************************************************************** |
| void |
| uDMAChannelAssign(unsigned long ulMapping) |
| { |
| unsigned long ulMapReg; |
| unsigned long ulMapShift; |
| unsigned long ulChannelNum; |
| |
| // |
| // Check the parameters |
| // |
| ASSERT((ulMapping & 0xffffff00) < 0x00050000); |
| |
| |
| // |
| // Extract the channel number and map encoding value from the parameter. |
| // |
| ulChannelNum = ulMapping & 0x1f; |
| ulMapping = ulMapping >> 16; |
| |
| // |
| // Find the uDMA channel mapping register and shift value to use for this |
| // channel |
| // |
| ulMapReg = UDMA_BASE + UDMA_O_CHMAP0 + ((ulChannelNum / 8) * 4); |
| ulMapShift = (ulChannelNum % 8) * 4; |
| |
| // |
| // Set the channel map encoding for this channel |
| // |
| HWREG(ulMapReg) = (HWREG(ulMapReg) & ~(0xf << ulMapShift)) | |
| ulMapping << ulMapShift; |
| } |
| |
| //***************************************************************************** |
| // |
| // Close the Doxygen group. |
| //! @} |
| // |
| //***************************************************************************** |