diff options
Diffstat (limited to 'cc3200/hal/spi.c')
-rw-r--r-- | cc3200/hal/spi.c | 1527 |
1 files changed, 1527 insertions, 0 deletions
diff --git a/cc3200/hal/spi.c b/cc3200/hal/spi.c new file mode 100644 index 0000000000..f89a9e5c7b --- /dev/null +++ b/cc3200/hal/spi.c @@ -0,0 +1,1527 @@ +//***************************************************************************** +// +// spi.c +// +// Driver for the SPI. +// +// 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 SPI_Serial_Peripheral_Interface_api +//! @{ +// +//***************************************************************************** + + +#include "inc/hw_ints.h" +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "inc/hw_mcspi.h" +#include "inc/hw_apps_config.h" +#include "interrupt.h" +#include "spi.h" + + +//***************************************************************************** +// +// A mapping of SPI base address to interupt number. +// +//***************************************************************************** +static const unsigned long g_ppulSPIIntMap[][3] = +{ + { SSPI_BASE, INT_SSPI }, // Shared SPI + { GSPI_BASE, INT_GSPI }, // Generic SPI + { LSPI_BASE, INT_LSPI }, // LINK SPI +}; + +//***************************************************************************** +// +// A mapping of SPI base address to DMA done interrupt mask bit(s). +// +//***************************************************************************** +static const unsigned long g_ulSPIDmaMaskMap[][2]= +{ + {SSPI_BASE,APPS_CONFIG_DMA_DONE_INT_MASK_SHSPI_WR_DMA_DONE_INT_MASK}, + {LSPI_BASE,APPS_CONFIG_DMA_DONE_INT_MASK_HOSTSPI_WR_DMA_DONE_INT_MASK}, + {GSPI_BASE,APPS_CONFIG_DMA_DONE_INT_MASK_APPS_SPI_WR_DMA_DONE_INT_MASK}, +}; + +//***************************************************************************** +// +//! \internal +//! Transfer bytes over SPI channel +//! +//! \param ulBase is the base address of SPI module +//! \param ucDout is the pointer to Tx data buffer or 0. +//! \param ucDin is pointer to Rx data buffer or 0 +//! \param ulCount is the size of data in bytes. +//! +//! This function transfers \e ulCount bytes of data over SPI channel. +//! +//! The function will not return until data has been transmitted +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +static long SPITransfer8(unsigned long ulBase, unsigned char *ucDout, + unsigned char *ucDin, unsigned long ulCount, + unsigned long ulFlags) +{ + unsigned long ulReadReg; + unsigned long ulWriteReg; + unsigned long ulStatReg; + unsigned long ulOutIncr; + unsigned long ulInIncr; + unsigned long ulTxDummy; + unsigned long ulRxDummy; + + // + // Initialize the variables + // + ulOutIncr = 1; + ulInIncr = 1; + + // + // Check if output buffer pointer is 0 + // + if(ucDout == 0) + { + ulOutIncr = 0; + ulTxDummy = 0xFFFFFFFF; + ucDout = (unsigned char *)&ulTxDummy; + } + + // + // Check if input buffer pointer is 0 + // + if(ucDin == 0) + { + ulInIncr = 0; + ucDin = (unsigned char *)&ulRxDummy; + } + + // + // Load the register addresses. + // + ulReadReg = (ulBase + MCSPI_O_RX0); + ulWriteReg = (ulBase + MCSPI_O_TX0); + ulStatReg = (ulBase + MCSPI_O_CH0STAT); + + // + // Enable CS based on Flag + // + if( ulFlags & SPI_CS_ENABLE) + { + HWREG( ulBase + MCSPI_O_CH0CONF) |= MCSPI_CH0CONF_FORCE; + } + + while(ulCount) + { + // + // Wait for space in output register/FIFO. + // + while( !(HWREG(ulStatReg) & MCSPI_CH0STAT_TXS) ) + { + } + + // + // Write the data + // + HWREG(ulWriteReg) = *ucDout; + + // + // Wait for data in input register/FIFO. + // + while( !( HWREG(ulStatReg) & MCSPI_CH0STAT_RXS) ) + { + } + + // + // Read the data + // + *ucDin = HWREG(ulReadReg); + + // + // Increment pointers. + // + ucDout = ucDout + ulOutIncr; + ucDin = ucDin + ulInIncr; + + // + // Decrement the count. + // + ulCount--; + } + + // + // Disable CS based on Flag + // + if( ulFlags & SPI_CS_DISABLE) + { + HWREG( ulBase + MCSPI_O_CH0CONF) &= ~MCSPI_CH0CONF_FORCE; + } + + return 0; +} + +//***************************************************************************** +// +//! \internal +//! Transfer half-words over SPI channel +//! +//! \param ulBase is the base address of SPI module +//! \param usDout is the pointer to Tx data buffer or 0. +//! \param usDin is pointer to Rx data buffer or 0 +//! \param ulCount is the size of data in bytes. +//! +//! This function transfers \e ulCount bytes of data over SPI channel. Since +//! the API sends a half-word at a time \e ulCount should be a multiple +//! of two. +//! +//! The function will not return until data has been transmitted +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +static long SPITransfer16(unsigned long ulBase, unsigned short *usDout, + unsigned short *usDin, unsigned long ulCount, + unsigned long ulFlags) +{ + unsigned long ulReadReg; + unsigned long ulWriteReg; + unsigned long ulStatReg; + unsigned long ulOutIncr; + unsigned long ulInIncr; + unsigned long ulTxDummy; + unsigned long ulRxDummy; + + // + // Initialize the variables. + // + ulOutIncr = 1; + ulInIncr = 1; + + // + // Check if count is multiple of half-word + // + if(ulCount%2) + { + return -1; + } + + // + // Compute number of half words. + // + ulCount = ulCount/2; + + // + // Check if output buffer pointer is 0 + // + if(usDout == 0) + { + ulOutIncr = 0; + ulTxDummy = 0xFFFFFFFF; + usDout = (unsigned short *)&ulTxDummy; + } + + // + // Check if input buffer pointer is 0 + // + if(usDin == 0) + { + ulInIncr = 0; + usDin = (unsigned short *)&ulRxDummy; + } + + // + // Load the register addresses. + // + ulReadReg = (ulBase + MCSPI_O_RX0); + ulWriteReg = (ulBase + MCSPI_O_TX0); + ulStatReg = (ulBase + MCSPI_O_CH0STAT); + + // + // Enable CS based on Flag + // + if( ulFlags & SPI_CS_ENABLE) + { + HWREG( ulBase + MCSPI_O_CH0CONF) |= MCSPI_CH0CONF_FORCE; + } + + while(ulCount) + { + // + // Wait for space in output register/FIFO. + // + while( !(HWREG(ulStatReg) & MCSPI_CH0STAT_TXS) ) + { + } + + // + // Write the data + // + HWREG(ulWriteReg) = *usDout; + + // + // Wait for data in input register/FIFO. + // + while( !( HWREG(ulStatReg) & MCSPI_CH0STAT_RXS) ) + { + } + + // + // Read the data + // + *usDin = HWREG(ulReadReg); + + // + // Increment pointers. + // + usDout = usDout + ulOutIncr; + usDin = usDin + ulInIncr; + + // + // Decrement the count. + // + ulCount--; + } + + // + // Disable CS based on Flag + // + if( ulFlags & SPI_CS_DISABLE) + { + HWREG( ulBase + MCSPI_O_CH0CONF) &= ~MCSPI_CH0CONF_FORCE; + } + + return 0; +} + +//***************************************************************************** +// +//! \internal +//! Transfer words over SPI channel +//! +//! \param ulBase is the base address of SPI module +//! \param ulDout is the pointer to Tx data buffer or 0. +//! \param ulDin is pointer to Rx data buffer or 0 +//! \param ulCount is the size of data in bytes. +//! +//! This function transfers \e ulCount bytes of data over SPI channel. Since +//! the API sends a word at a time \e ulCount should be a multiple of four. +//! +//! The function will not return until data has been transmitted +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +static long SPITransfer32(unsigned long ulBase, unsigned long *ulDout, + unsigned long *ulDin, unsigned long ulCount, + unsigned long ulFlags) +{ + unsigned long ulReadReg; + unsigned long ulWriteReg; + unsigned long ulStatReg; + unsigned long ulOutIncr; + unsigned long ulInIncr; + unsigned long ulTxDummy; + unsigned long ulRxDummy; + + // + // Initialize the variables. + // + ulOutIncr = 1; + ulInIncr = 1; + + // + // Check if count is multiple of word + // + if(ulCount%4) + { + return -1; + } + + // + // Compute the number of words to be transferd + // + ulCount = ulCount/4; + + // + // Check if output buffer pointer is 0 + // + if(ulDout == 0) + { + ulOutIncr = 0; + ulTxDummy = 0xFFFFFFFF; + ulDout = &ulTxDummy; + } + + // + // Check if input buffer pointer is 0 + // + if(ulDin == 0) + { + ulInIncr = 0; + ulDin = &ulRxDummy; + } + + + // + // Load the register addresses. + // + ulReadReg = (ulBase + MCSPI_O_RX0); + ulWriteReg = (ulBase + MCSPI_O_TX0); + ulStatReg = (ulBase + MCSPI_O_CH0STAT); + + // + // Enable CS based on Flag + // + if( ulFlags & SPI_CS_ENABLE) + { + HWREG( ulBase + MCSPI_O_CH0CONF) |= MCSPI_CH0CONF_FORCE; + } + + while(ulCount) + { + // + // Wait for space in output register/FIFO. + // + while( !(HWREG(ulStatReg) & MCSPI_CH0STAT_TXS) ) + { + } + + // + // Write the data + // + HWREG(ulWriteReg) = *ulDout; + + // + // Wait for data in input register/FIFO. + // + while( !( HWREG(ulStatReg) & MCSPI_CH0STAT_RXS) ) + { + } + + // + // Read the data + // + *ulDin = HWREG(ulReadReg); + + // + // Increment pointers. + // + ulDout = ulDout + ulOutIncr; + ulDin = ulDin + ulInIncr; + + // + // Decrement the count. + // + ulCount--; + } + + // + // Disable CS based on Flag + // + if( ulFlags & SPI_CS_DISABLE) + { + HWREG( ulBase + MCSPI_O_CH0CONF) &= ~MCSPI_CH0CONF_FORCE; + } + + return 0; +} + +//***************************************************************************** +// +//! \internal +//! Gets the SPI interrupt number. +//! +//! \param ulBase is the base address of the SPI module +//! +//! Given a SPI base address, returns the corresponding interrupt number. +//! +//! \return Returns a SPI interrupt number, or -1 if \e ulBase is invalid. +// +//***************************************************************************** +static long +SPIIntNumberGet(unsigned long ulBase) +{ + unsigned long ulIdx; + + // + // Loop through the table that maps SPI base addresses to interrupt + // numbers. + // + for(ulIdx = 0; ulIdx < (sizeof(g_ppulSPIIntMap) / + sizeof(g_ppulSPIIntMap[0])); ulIdx++) + { + // + // See if this base address matches. + // + if(g_ppulSPIIntMap[ulIdx][0] == ulBase) + { + // + // Return the corresponding interrupt number. + // + return(g_ppulSPIIntMap[ulIdx][1]); + } + } + + // + // The base address could not be found, so return an error. + // + return(-1); +} + +//***************************************************************************** +// +//! \internal +//! Gets the SPI DMA interrupt mask bit. +//! +//! \param ulBase is the base address of the SPI module +//! +//! Given a SPI base address, DMA interrupt mask bit. +//! +//! \return Returns a DMA interrupt mask bit, or -1 if \e ulBase is invalid. +// +//***************************************************************************** +static long +SPIDmaMaskGet(unsigned long ulBase) +{ + unsigned long ulIdx; + + // + // Loop through the table that maps SPI base addresses to interrupt + // numbers. + // + for(ulIdx = 0; ulIdx < (sizeof(g_ulSPIDmaMaskMap) / + sizeof(g_ulSPIDmaMaskMap[0])); ulIdx++) + { + // + // See if this base address matches. + // + if(g_ulSPIDmaMaskMap[ulIdx][0] == ulBase) + { + // + // Return the corresponding interrupt number. + // + return(g_ulSPIDmaMaskMap[ulIdx][1]); + } + } + + // + // The base address could not be found, so return an error. + // + return(-1); +} + +//***************************************************************************** +// +//! Enables transmitting and receiving. +//! +//! \param ulBase is the base address of the SPI module +//! +//! This function enables the SPI channel for transmitting and receiving. +//! +//! \return None +//! +// +//***************************************************************************** +void +SPIEnable(unsigned long ulBase) +{ + // + // Set Channel Enable Bit + // + HWREG(ulBase + MCSPI_O_CH0CTRL) |= MCSPI_CH0CTRL_EN; +} + +//***************************************************************************** +// +//! Disables the transmitting and receiving. +//! +//! \param ulBase is the base address of the SPI module +//! +//! This function disables the SPI channel for transmitting and receiving. +//! +//! \return None +//! +// +//***************************************************************************** +void +SPIDisable(unsigned long ulBase) +{ + // + // Reset Channel Enable Bit + // + HWREG(ulBase + MCSPI_O_CH0CTRL) &= ~MCSPI_CH0CTRL_EN; +} + + +//***************************************************************************** +// +//! Enables the SPI DMA operation for transmitting and/or receving. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulFlags selectes the DMA signal for transmit and/or receive. +//! +//! This function enables transmit and/or receive DMA request based on the +//! \e ulFlags parameter. +//! +//! The parameter \e ulFlags is the logical OR of one or more of +//! the following : +//! - \b SPI_RX_DMA +//! - \b SPI_TX_DMA +//! +//! \return None. +// +//***************************************************************************** +void +SPIDmaEnable(unsigned long ulBase, unsigned long ulFlags) +{ + // + // Enable DMA based on ulFlags + // + HWREG(ulBase + MCSPI_O_CH0CONF) |= ulFlags; +} + +//***************************************************************************** +// +//! Disables the SPI DMA operation for transmitting and/or receving. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulFlags selectes the DMA signal for transmit and/or receive. +//! +//! This function disables transmit and/or receive DMA request based on the +//! \e ulFlags parameter. +//! +//! The parameter \e ulFlags is the logical OR of one or more of +//! the following : +//! - \b SPI_RX_DMA +//! - \b SPI_TX_DMA +//! +//! \return None. +// +//***************************************************************************** +void +SPIDmaDisable(unsigned long ulBase, unsigned long ulFlags) +{ + // + // Disable DMA based on ulFlags + // + HWREG(ulBase + MCSPI_O_CH0CONF) &= ulFlags; +} + +//***************************************************************************** +// +//! Performs a software reset of the specified SPI module +//! +//! \param ulBase is the base address of the SPI module +//! +//! This function performs a software reset of the specified SPI module +//! +//! \return None. +// +//***************************************************************************** +void +SPIReset(unsigned long ulBase) +{ + + // + // Assert soft reset (auto clear) + // + HWREG(ulBase + MCSPI_O_SYSCONFIG) |= MCSPI_SYSCONFIG_SOFTRESET; + + // + // wait until reset is done + // + while(!(HWREG(ulBase + MCSPI_O_SYSSTATUS)& MCSPI_SYSSTATUS_RESETDONE)) + { + } +} + +//***************************************************************************** +// +//! Sets the configuration of a SPI module +//! +//! \param ulBase is the base address of the SPI module +//! \param ulSPIClk is the rate of clock supplied to the SPI module. +//! \param ulBitRate is the desired bit rate.(master mode) +//! \param ulMode is the mode of operation. +//! \param ulSubMode is one of the valid sub-modes. +//! \param ulConfig is logical OR of configuration paramaters. +//! +//! This function configures SPI port for operation in specified sub-mode and +//! required bit rated as specified by \e ulMode and \e ulBitRate parameters +//! respectively. +//! +//! The SPI module can operate in either master or slave mode. The parameter +//! \e ulMode can be one of the following +//! -\b SPI_MODE_MASTER +//! -\b SPI_MODE_SLAVE +//! +//! The SPI module supports 4 sub modes based on SPI clock polarity and phase. +//! +//! <pre> +//! Polarity Phase Sub-Mode +//! 0 0 0 +//! 0 1 1 +//! 1 0 2 +//! 1 1 3 +//! </pre> +//! +//! Required sub mode can be select by setting \e ulSubMode parameter to one +//! of the following +//! - \b SPI_SUB_MODE_0 +//! - \b SPI_SUB_MODE_1 +//! - \b SPI_SUB_MODE_2 +//! - \b SPI_SUB_MODE_3 +//! +//! The parameter \e ulConfig is logical OR of five values: the word length, +//! active level for chip select, software or hardware controled chip select, +//! 3 or 4 pin mode and turbo mode. +//! mode. +//! +//! SPI support 8, 16 and 32 bit word lengths defined by:- +//! - \b SPI_WL_8 +//! - \b SPI_WL_16 +//! - \b SPI_WL_32 +//! +//! Active state of Chip[ Selece can be defined by:- +//! - \b SPI_CS_ACTIVELOW +//! - \b SPI_CS_ACTIVEHIGH +//! +//! SPI chip select can be configured to be controlled either by hardware or +//! software:- +//! - \b SPI_SW_CS +//! - \b SPI_HW_CS +//! +//! The module can work in 3 or 4 pin mode defined by:- +//! - \b SPI_3PIN_MODE +//! - \b SPI_4PIN_MODE +//! +//! Turbo mode can be set on or turned off using:- +//! - \b SPI_TURBO_MODE_ON +//! - \b SPI_TURBO_MODE_OFF +//! +//! \return None. +// +//***************************************************************************** +void +SPIConfigSetExpClk(unsigned long ulBase,unsigned long ulSPIClk, + unsigned long ulBitRate, unsigned long ulMode, + unsigned long ulSubMode, unsigned long ulConfig) +{ + + unsigned long ulRegData; + unsigned long ulDivider; + + // + // Read MODULCTRL register + // + ulRegData = HWREG(ulBase + MCSPI_O_MODULCTRL); + + // + // Set Master mode with h/w chip select + // + ulRegData &= ~(MCSPI_MODULCTRL_MS | + MCSPI_MODULCTRL_SINGLE); + + // + // Enable software control Chip Select, Init delay + // and 3-pin mode + // + ulRegData |= (((ulConfig >> 24) | ulMode) & 0xFF); + + // + // Write the configuration + // + HWREG(ulBase + MCSPI_O_MODULCTRL) = ulRegData; + + // + // Set IS, DPE0, DPE1 based on master or slave mode + // + if(ulMode == SPI_MODE_MASTER) + { + ulRegData = 0x1 << 16; + } + else + { + ulRegData = 0x6 << 16; + } + + // + // Mask the configurations and set clock divider granularity + // to 1 cycle + // + ulRegData = (ulRegData & (~(MCSPI_CH0CONF_WL_M | + MCSPI_CH0CONF_EPOL | + MCSPI_CH0CONF_POL | + MCSPI_CH0CONF_PHA | + MCSPI_CH0CONF_TURBO ) | + MCSPI_CH0CONF_CLKG)); + + // + // Get the divider value + // + ulDivider = ((ulSPIClk/ulBitRate) - 1); + + // + // The least significant four bits of the divider is used fo configure + // CLKD in MCSPI_CHCONF next eight least significant bits are used to + // configure the EXTCLK in MCSPI_CHCTRL + // + ulRegData |= ((ulDivider & 0x0000000F) << 2); + HWREG(ulBase + MCSPI_O_CH0CTRL) = ((ulDivider & 0x00000FF0) << 4); + + // + // Set the protocol, CS polarity, word length + // and turbo mode + // + ulRegData = ((ulRegData | + ulSubMode) | (ulConfig & 0x0008FFFF)); + + // + // Write back the CONF register + // + HWREG(ulBase + MCSPI_O_CH0CONF) = ulRegData; + +} + +//***************************************************************************** +// +//! Receives a word from the specified port. +//! +//! \param ulBase is the base address of the SPI module. +//! \param pulData is pointer to receive data variable. +//! +//! This function gets a SPI word from the receive FIFO for the specified +//! port. +//! +//! \return Returns the number of elements read from the receive FIFO. +// +//***************************************************************************** +long +SPIDataGetNonBlocking(unsigned long ulBase, unsigned long *pulData) +{ + unsigned long ulRegVal; + + // + // Read register status register + // + ulRegVal = HWREG(ulBase + MCSPI_O_CH0STAT); + + // + // Check is data is available + // + if(ulRegVal & MCSPI_CH0STAT_RXS) + { + *pulData = HWREG(ulBase + MCSPI_O_RX0); + return(1); + } + + return(0); +} + +//***************************************************************************** +// +//! Waits for the word to be received on the specified port. +//! +//! \param ulBase is the base address of the SPI module. +//! \param pulData is pointer to receive data variable. +//! +//! This function gets a SPI word from the receive FIFO for the specified +//! port. If there is no word available, this function waits until a +//! word is received before returning. +//! +//! \return Returns the word read from the specified port, cast as an +//! \e unsigned long. +// +//***************************************************************************** +void +SPIDataGet(unsigned long ulBase, unsigned long *pulData) +{ + // + // Wait for Rx data + // + while(!(HWREG(ulBase + MCSPI_O_CH0STAT) & MCSPI_CH0STAT_RXS)) + { + } + + // + // Read the value + // + *pulData = HWREG(ulBase + MCSPI_O_RX0); +} + +//***************************************************************************** +// +//! Transmits a word on the specified port. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulData is data to be transmitted. +//! +//! This function transmits a SPI word on the transmit FIFO for the specified +//! port. +//! +//! \return Returns the number of elements written to the transmit FIFO. +//! +//***************************************************************************** +long +SPIDataPutNonBlocking(unsigned long ulBase, unsigned long ulData) +{ + unsigned long ulRegVal; + + // + // Read status register + // + ulRegVal = HWREG(ulBase + MCSPI_O_CH0STAT); + + // + // Write value into Tx register/FIFO + // if space is available + // + if(ulRegVal & MCSPI_CH0STAT_TXS) + { + HWREG(ulBase + MCSPI_O_TX0) = ulData; + return(1); + } + + return(0); +} + +//***************************************************************************** +// +//! Waits until the word is transmitted on the specified port. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulData is data to be transmitted. +//! +//! This function transmits a SPI word on the transmit FIFO for the specified +//! port. This function waits until the space is available on transmit FIFO +//! +//! \return None +//! +//***************************************************************************** +void +SPIDataPut(unsigned long ulBase, unsigned long ulData) +{ + // + // Wait for space in FIFO + // + while(!(HWREG(ulBase + MCSPI_O_CH0STAT)&MCSPI_CH0STAT_TXS)) + { + } + + // + // Write the data + // + HWREG(ulBase + MCSPI_O_TX0) = ulData; +} + +//***************************************************************************** +// +//! Enables the transmit and/or receive FIFOs. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulFlags selects the FIFO(s) to be enabled +//! +//! This function enables the transmit and/or receive FIFOs as specified by +//! \e ulFlags. +//! The parameter \e ulFlags shoulde be logical OR of one or more of the +//! following: +//! - \b SPI_TX_FIFO +//! - \b SPI_RX_FIFO +//! +//! \return None. +// +//***************************************************************************** +void +SPIFIFOEnable(unsigned long ulBase, unsigned long ulFlags) +{ + // + // Set FIFO enable bits. + // + HWREG(ulBase + MCSPI_O_CH0CONF) |= ulFlags; +} + +//***************************************************************************** +// +//! Disables the transmit and/or receive FIFOs. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulFlags selects the FIFO(s) to be enabled +//! +//! This function disables transmit and/or receive FIFOs. as specified by +//! \e ulFlags. +//! The parameter \e ulFlags shoulde be logical OR of one or more of the +//! following: +//! - \b SPI_TX_FIFO +//! - \b SPI_RX_FIFO +//! +//! \return None. +// +//***************************************************************************** +void +SPIFIFODisable(unsigned long ulBase, unsigned long ulFlags) +{ + // + // Reset FIFO Enable bits. + // + HWREG(ulBase + MCSPI_O_CH0CONF) &= ~(ulFlags); +} + +//***************************************************************************** +// +//! Sets the FIFO level at which DMA requests or interrupts are generated. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulTxLevel is the Almost Empty Level for transmit FIFO. +//! \param ulRxLevel is the Almost Full Level for the receive FIFO. +//! +//! This function Sets the FIFO level at which DMA requests or interrupts +//! are generated. +//! +//! \return None. +// +//***************************************************************************** +void SPIFIFOLevelSet(unsigned long ulBase, unsigned long ulTxLevel, + unsigned long ulRxLevel) +{ + unsigned long ulRegVal; + + // + // Read the current configuration + // + ulRegVal = HWREG(ulBase + MCSPI_O_XFERLEVEL); + + // + // Mask and set new FIFO thresholds. + // + ulRegVal = ((ulRegVal & 0xFFFF0000) | (((ulRxLevel-1) << 8) | (ulTxLevel-1))); + + // + // Set the transmit and receive FIFO thresholds. + // + HWREG(ulBase + MCSPI_O_XFERLEVEL) = ulRegVal; + +} + +//***************************************************************************** +// +//! Gets the FIFO level at which DMA requests or interrupts are generated. +//! +//! \param ulBase is the base address of the SPI module +//! \param pulTxLevel is a pointer to storage for the transmit FIFO level +//! \param pulRxLevel is a pointer to storage for the receive FIFO level +//! +//! This function gets the FIFO level at which DMA requests or interrupts +//! are generated. +//! +//! \return None. +// +//***************************************************************************** +void +SPIFIFOLevelGet(unsigned long ulBase, unsigned long *pulTxLevel, + unsigned long *pulRxLevel) +{ + unsigned long ulRegVal; + + // + // Read the current configuration + // + ulRegVal = HWREG(ulBase + MCSPI_O_XFERLEVEL); + + *pulTxLevel = (ulRegVal & 0xFF); + + *pulRxLevel = ((ulRegVal >> 8) & 0xFF); + +} + +//***************************************************************************** +// +//! Sets the word count. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulWordCount is number of SPI words to be transmitted. +//! +//! This function sets the word count, which is the number of SPI word to +//! be transferred on channel when using the FIFO buffer. +//! +//! \return None. +// +//***************************************************************************** +void +SPIWordCountSet(unsigned long ulBase, unsigned long ulWordCount) +{ + unsigned long ulRegVal; + + // + // Read the current configuration + // + ulRegVal = HWREG(ulBase + MCSPI_O_XFERLEVEL); + + // + // Mask and set the word count + // + HWREG(ulBase + MCSPI_O_XFERLEVEL) = ((ulRegVal & 0x0000FFFF)| + (ulWordCount & 0xFFFF) << 16); +} + +//***************************************************************************** +// +//! Registers an interrupt handler for a SPI interrupt. +//! +//! \param ulBase is the base address of the SPI module +//! \param pfnHandler is a pointer to the function to be called when the +//! SPI interrupt occurs. +//! +//! This function does the actual registering of the interrupt handler. This +//! function enables the global interrupt in the interrupt controller; specific +//! SPI interrupts must be enabled via SPIIntEnable(). It is the interrupt +//! handler's responsibility to clear the interrupt source. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntRegister(unsigned long ulBase, void(*pfnHandler)(void)) +{ + unsigned long ulInt; + + // + // Determine the interrupt number based on the SPI module + // + ulInt = SPIIntNumberGet(ulBase); + + // + // Register the interrupt handler. + // + IntRegister(ulInt, pfnHandler); + + // + // Enable the SPI interrupt. + // + IntEnable(ulInt); +} + +//***************************************************************************** +// +//! Unregisters an interrupt handler for a SPI interrupt. +//! +//! \param ulBase is the base address of the SPI module +//! +//! This function does the actual unregistering of the interrupt handler. It +//! clears the handler to be called when a SPI interrupt occurs. This +//! function also masks off the interrupt in the interrupt controller so that +//! the interrupt handler no longer is called. +//! +//! \sa IntRegister() for important information about registering interrupt +//! handlers. +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntUnregister(unsigned long ulBase) +{ + unsigned long ulInt; + + // + // Determine the interrupt number based on the SPI module + // + ulInt = SPIIntNumberGet(ulBase); + + // + // Disable the interrupt. + // + IntDisable(ulInt); + + // + // Unregister the interrupt handler. + // + IntUnregister(ulInt); +} + +//***************************************************************************** +// +//! Enables individual SPI interrupt sources. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled. +//! +//! This function enables the indicated SPI interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter is the logical OR of any of the following: +//! +//! - \b SPI_INT_DMATX +//! - \b SPI_INT_DMARX +//! - \b SPI_INT_EOW +//! - \b SPI_INT_RX_OVRFLOW +//! - \b SPI_INT_RX_FULL +//! - \b SPI_INT_TX_UDRFLOW +//! - \b SPI_INT_TX_EMPTY +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntEnable(unsigned long ulBase, unsigned long ulIntFlags) +{ + unsigned long ulDmaMsk; + + // + // Enable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMATX) + { + ulDmaMsk = SPIDmaMaskGet(ulBase); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) = ulDmaMsk; + } + + // + // Enable DMA Rx Interrupt + // + if(ulIntFlags & SPI_INT_DMARX) + { + ulDmaMsk = (SPIDmaMaskGet(ulBase) >> 1); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_CLR) = ulDmaMsk; + } + + // + // Enable the specific Interrupts + // + HWREG(ulBase + MCSPI_O_IRQENABLE) |= (ulIntFlags & 0x0003000F); +} + + +//***************************************************************************** +// +//! Disables individual SPI interrupt sources. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled. +//! +//! This function disables the indicated SPI interrupt sources. Only the +//! sources that are enabled can be reflected to the processor interrupt; +//! disabled sources have no effect on the processor. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to SPIIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntDisable(unsigned long ulBase, unsigned long ulIntFlags) +{ + unsigned long ulDmaMsk; + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMATX) + { + ulDmaMsk = SPIDmaMaskGet(ulBase); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) = ulDmaMsk; + } + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMARX) + { + ulDmaMsk = (SPIDmaMaskGet(ulBase) >> 1); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_MASK_SET) = ulDmaMsk; + } + + // + // Disable the specific Interrupts + // + HWREG(ulBase + MCSPI_O_IRQENABLE) &= ~(ulIntFlags & 0x0003000F); +} + +//***************************************************************************** +// +//! Gets the current interrupt status. +//! +//! \param ulBase is the base address of the SPI module +//! \param bMasked is \b false if the raw interrupt status is required and +//! \b true if the masked interrupt status is required. +//! +//! This function returns the interrupt status for the specified SPI. +//! The status of interrupts that are allowed to reflect to the processor can +//! be returned. +//! +//! \return Returns the current interrupt status, enumerated as a bit field of +//! values described in SPIIntEnable(). +// +//***************************************************************************** +unsigned long +SPIIntStatus(unsigned long ulBase, tBoolean bMasked) +{ + unsigned long ulIntStat; + unsigned long ulIntFlag; + unsigned long ulDmaMsk; + + // + // Get SPI interrupt status + // + ulIntFlag = HWREG(ulBase + MCSPI_O_IRQSTATUS) & 0x0003000F; + + if(bMasked) + { + ulIntFlag &= HWREG(ulBase + MCSPI_O_IRQENABLE); + } + + // + // Get the interrupt bit + // + ulDmaMsk = SPIDmaMaskGet(ulBase); + + // + // Get the DMA interrupt status + // + if(bMasked) + { + ulIntStat = HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_MASKED); + } + else + { + ulIntStat = HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_STS_RAW); + } + + // + // Get SPI Tx DMA done status + // + if(ulIntStat & ulDmaMsk) + { + ulIntFlag |= SPI_INT_DMATX; + } + + // + // Get SPI Rx DMA done status + // + if(ulIntStat & (ulDmaMsk >> 1)) + { + ulIntFlag |= SPI_INT_DMARX; + } + + // + // Return status + // + return(ulIntFlag); +} + +//***************************************************************************** +// +//! Clears SPI interrupt sources. +//! +//! \param ulBase is the base address of the SPI module +//! \param ulIntFlags is a bit mask of the interrupt sources to be cleared. +//! +//! The specified SPI interrupt sources are cleared, so that they no longer +//! assert. This function must be called in the interrupt handler to keep the +//! interrupt from being recognized again immediately upon exit. +//! +//! The \e ulIntFlags parameter has the same definition as the \e ulIntFlags +//! parameter to SPIIntEnable(). +//! +//! \return None. +// +//***************************************************************************** +void +SPIIntClear(unsigned long ulBase, unsigned long ulIntFlags) +{ + unsigned long ulDmaMsk; + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMATX) + { + ulDmaMsk = SPIDmaMaskGet(ulBase); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) = ulDmaMsk; + } + + // + // Disable DMA Tx Interrupt + // + if(ulIntFlags & SPI_INT_DMARX) + { + ulDmaMsk = (SPIDmaMaskGet(ulBase) >> 1); + HWREG(APPS_CONFIG_BASE + APPS_CONFIG_O_DMA_DONE_INT_ACK) = ulDmaMsk; + } + + // + // Clear Interrupts + // + HWREG(ulBase + MCSPI_O_IRQSTATUS) = (ulIntFlags & 0x0003000F); +} + +//***************************************************************************** +// +//! Enables the chip select in software controlled mode +//! +//! \param ulBase is the base address of the SPI module. +//! +//! This function enables the Chip select in software controlled mode. The +//! active state of CS will depend on the configuration done via +//! \sa SPIConfigExpClkSet(). +//! +//! \return None. +// +//***************************************************************************** +void SPICSEnable(unsigned long ulBase) +{ + // + // Set Chip Select enable bit. + // + HWREG( ulBase+MCSPI_O_CH0CONF) |= MCSPI_CH0CONF_FORCE; +} + +//***************************************************************************** +// +//! Disables the chip select in software controlled mode +//! +//! \param ulBase is the base address of the SPI module. +//! +//! This function disables the Chip select in software controlled mode. The +//! active state of CS will depend on the configuration done via +//! sa SPIConfigSetExpClk(). +//! +//! \return None. +// +//***************************************************************************** +void SPICSDisable(unsigned long ulBase) +{ + // + // Reset Chip Select enable bit. + // + HWREG( ulBase+MCSPI_O_CH0CONF) &= ~MCSPI_CH0CONF_FORCE; +} + +//***************************************************************************** +// +//! Send/Receive data buffer over SPI channel +//! +//! \param ulBase is the base address of SPI module +//! \param ucDout is the pointer to Tx data buffer or 0. +//! \param ucDin is pointer to Rx data buffer or 0 +//! \param ulCount is the size of data in bytes. +//! \param ulFlags controlls chip select toggling. +//! +//! This function transfers \e ulCount bytes of data over SPI channel. Since +//! the API sends a SPI word at a time \e ulCount should be a multiple of +//! word length set using SPIConfigSetExpClk(). +//! +//! If the \e ucDout parameter is set to 0, the function will send 0xFF over +//! the SPI MOSI line. +//! +//! If the \e ucDin parameter is set to 0, the function will ignore data on SPI +//! MISO line. +//! +//! The parameter \e ulFlags is logical OR of one or more of the following +//! +//! - \b SPI_CS_ENABLE if CS needs to be enabled at start of transfer. +//! - \b SPI_CS_DISABLE if CS need to be disabled at the end of transfer. +//! +//! This function will not return until data has been transmitted +//! +//! \return Returns 0 on success, -1 otherwise. +// +//***************************************************************************** +long SPITransfer(unsigned long ulBase, unsigned char *ucDout, + unsigned char *ucDin, unsigned long ulCount, + unsigned long ulFlags) +{ + unsigned long ulWordLength; + long lRet; + + // + // Get the word length + // + ulWordLength = (HWREG(ulBase + MCSPI_O_CH0CONF) & MCSPI_CH0CONF_WL_M); + + // + // Check for word length. + // + if( !((ulWordLength == SPI_WL_8) || (ulWordLength == SPI_WL_16) || + (ulWordLength == SPI_WL_32)) ) + { + return -1; + } + + if( ulWordLength == SPI_WL_8 ) + { + // + // Do byte transfer + // + lRet = SPITransfer8(ulBase,ucDout,ucDin,ulCount,ulFlags); + } + else if( ulWordLength == SPI_WL_16 ) + { + + // + // Do half-word transfer + // + lRet = SPITransfer16(ulBase,(unsigned short *)ucDout, + (unsigned short *)ucDin,ulCount,ulFlags); + } + else + { + // + // Do word transfer + // + lRet = SPITransfer32(ulBase,(unsigned long *)ucDout, + (unsigned long *)ucDin,ulCount,ulFlags); + } + + // + // return + // + return lRet; + +} +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** |