//***************************************************************************** // // 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. //! //!
//! Polarity Phase  Sub-Mode
//!   0       0        0
//!   0       1        1
//!   1       0        2
//!   1       1        3
//! 
//! //! 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. //! @} // //*****************************************************************************