summaryrefslogtreecommitdiffstatshomepage
path: root/cc3200/hal/spi.c
diff options
context:
space:
mode:
Diffstat (limited to 'cc3200/hal/spi.c')
-rw-r--r--cc3200/hal/spi.c1527
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.
+//! @}
+//
+//*****************************************************************************