CC3000HostDriver for device TI CC3000 some changes were made due to mbed compiler and the use of void*
spi.cpp
- Committer:
- dflet
- Date:
- 2013-08-02
- Revision:
- 0:9cb694f00b7b
File content as of revision 0:9cb694f00b7b:
/***************************************************************************** * * spi.c - CC3000 Host Driver Implementation. * Copyright (C) 2011 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 link_buff_api //! @{ // //***************************************************************************** #include "hci.h" #include "spi.h" #include "evnt_handler.h" #include "mbed.h" #include "CC3000Core.h" //#include "board.h" //#include <msp430.h> SPI spi(p5, p6, p7); // mosi, miso, sclk DigitalOut cs(p8); // chip select #define READ 3 #define WRITE 1 #define HI(value) (((value) & 0xFF00) >> 8) #define LO(value) ((value) & 0x00FF) #define ASSERT_CS() (cs = 0)//(RF_CS_OUT &= ~RF_CS) #define DEASSERT_CS() (cs = 1)//(RF_CS_OUT |= RF_CS) #define HEADERS_SIZE_EVNT (SPI_HEADER_SIZE + 5) #define SPI_HEADER_SIZE (5) #define eSPI_STATE_POWERUP (0) #define eSPI_STATE_INITIALIZED (1) #define eSPI_STATE_IDLE (2) #define eSPI_STATE_WRITE_IRQ (3) #define eSPI_STATE_WRITE_FIRST_PORTION (4) #define eSPI_STATE_WRITE_EOT (5) #define eSPI_STATE_READ_IRQ (6) #define eSPI_STATE_READ_FIRST_PORTION (7) #define eSPI_STATE_READ_EOT (8) typedef struct { gcSpiHandleRx SPIRxHandler; unsigned short usTxPacketLength; unsigned short usRxPacketLength; unsigned long ulSpiState; unsigned char *pTxPacket; unsigned char *pRxPacket; }tSpiInformation; tSpiInformation sSpiInformation; // buffer for 5 bytes of SPI HEADER unsigned char tSpiReadHeader[] = {READ, 0, 0, 0, 0}; void SpiWriteDataSynchronous(unsigned char *data, unsigned short size); void SpiWriteAsync(const unsigned char *data, unsigned short size); void SpiPauseSpi(void); void SpiResumeSpi(void); void SSIContReadOperation(void); // The magic number that resides at the end of the TX/RX buffer (1 byte after // the allocated size) for the purpose of detection of the overrun. The location // of the memory where the magic number resides shall never be written. In case // it is written - the overrun occurred and either receive function or send // function will stuck forever. #define CC3000_BUFFER_MAGIC_NUMBER (0xDE) /////////////////////////////////////////////////////////////////////////////////////////////////////////// //__no_init is used to prevent the buffer initialization in order to prevent hardware WDT expiration /// // before entering to 'main()'. /// //for every IDE, different syntax exists : 1. __CCS__ for CCS v5 /// // 2. __IAR_SYSTEMS_ICC__ for IAR Embedded Workbench /// // *CCS does not initialize variables - therefore, __no_init is not needed. /// /////////////////////////////////////////////////////////////////////////////////////////////////////////// //#ifdef __CCS__ char spi_buffer[CC3000_RX_BUFFER_SIZE]; //#elif __IAR_SYSTEMS_ICC__ //__no_init char spi_buffer[CC3000_RX_BUFFER_SIZE]; //#endif //#ifdef __CCS__ unsigned char wlan_tx_buffer[CC3000_TX_BUFFER_SIZE]; //#elif __IAR_SYSTEMS_ICC__ //__no_init unsigned char wlan_tx_buffer[CC3000_TX_BUFFER_SIZE]; //#endif //***************************************************************************** // //! SpiCleanGPIOISR //! //! \param none //! //! \return none //! //! \brief This function get the reason for the GPIO interrupt and clear //! corresponding interrupt flag // //***************************************************************************** void SpiCleanGPIOISR(void) { WlanInterruptDisable(); //SPI_IFG_PORT &= ~SPI_IRQ_PIN; } //***************************************************************************** // //! SpiClose //! //! @param none //! //! @return none //! //! @brief Close Spi interface // //***************************************************************************** void SpiClose(void) { if (sSpiInformation.pRxPacket) { sSpiInformation.pRxPacket = 0; } // Disable Interrupt tSLInformation.WlanInterruptDisable(); } //***************************************************************************** // //! SpiOpen //! //! @param none //! //! @return none //! //! @brief Open Spi interface // //***************************************************************************** void SpiOpen(gcSpiHandleRx pfRxHandler) { sSpiInformation.ulSpiState = eSPI_STATE_POWERUP; sSpiInformation.SPIRxHandler = pfRxHandler; sSpiInformation.usTxPacketLength = 0; sSpiInformation.pTxPacket = NULL; sSpiInformation.pRxPacket = (unsigned char *)spi_buffer; sSpiInformation.usRxPacketLength = 0; spi_buffer[CC3000_RX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] = CC3000_BUFFER_MAGIC_NUMBER; // Enable interrupt on WLAN IRQ pin tSLInformation.WlanInterruptEnable(); } //***************************************************************************** // //! init_spi //! //! @param none //! //! @return none //! //! @brief initializes an SPI interface // //***************************************************************************** int init_spi(void) { spi.frequency(16000000); spi.format(8, 1); cs = 1; //UCB0CTL1 |= UCSWRST; // Put state machine in reset //UCB0CTL0 = UCMSB + UCMST + UCMODE_0 + UCSYNC; // 3-pin, 8-bit SPI master //UCB0CTL1 = UCSWRST + UCSSEL_2; // Use SMCLK, keep RESET // Set SPI clock //UCB0CTL1 |= UCSWRST; // Put state machine in reset //UCB0BR0 = 2; // f_UCxCLK = 25MHz/2 = 12.5MHz //UCB0BR1 = 0; //UCB0CTL1 &= ~UCSWRST; return(ESUCCESS); } //***************************************************************************** // //! SpiFirstWrite //! //! @param ucBuf buffer to write //! @param usLength buffer's length //! //! @return none //! //! @brief enter point for first write flow // //***************************************************************************** long SpiFirstWrite(unsigned char *ucBuf, unsigned short usLength) { // workaround for first transaction ASSERT_CS(); // Assuming we are running on 24 MHz ~50 micro delay is 1200 cycles; //__delay_cycles(1200); wait_us(50); // SPI writes first 4 bytes of data SpiWriteDataSynchronous(ucBuf, 4); //__delay_cycles(1200); wait_us(50); SpiWriteDataSynchronous(ucBuf + 4, usLength - 4); // From this point on - operate in a regular way sSpiInformation.ulSpiState = eSPI_STATE_IDLE; DEASSERT_CS(); return(0); } //***************************************************************************** // //! SpiWrite //! //! @param pUserBuffer buffer to write //! @param usLength buffer's length //! //! @return none //! //! @brief Spi write operation // //***************************************************************************** long SpiWrite(unsigned char *pUserBuffer, unsigned short usLength) { unsigned char ucPad = 0; // Figure out the total length of the packet in order to figure out if there // is padding or not if(!(usLength & 0x0001)) { ucPad++; } pUserBuffer[0] = WRITE; pUserBuffer[1] = HI(usLength + ucPad); pUserBuffer[2] = LO(usLength + ucPad); pUserBuffer[3] = 0; pUserBuffer[4] = 0; usLength += (SPI_HEADER_SIZE + ucPad); // The magic number that resides at the end of the TX/RX buffer (1 byte after // the allocated size) for the purpose of detection of the overrun. If the // magic number is overwritten - buffer overrun occurred - and we will stuck // here forever! if (wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) { while (1) { printf("Buffer over run\r\n"); }// ; } if (sSpiInformation.ulSpiState == eSPI_STATE_POWERUP) { while (sSpiInformation.ulSpiState != eSPI_STATE_INITIALIZED) ; } if (sSpiInformation.ulSpiState == eSPI_STATE_INITIALIZED) { // This is time for first TX/RX transactions over SPI: the IRQ is down - // so need to send read buffer size command SpiFirstWrite(pUserBuffer, usLength); } else { // We need to prevent here race that can occur in case 2 back to back // packets are sent to the device, so the state will move to IDLE and once //again to not IDLE due to IRQ tSLInformation.WlanInterruptDisable(); while (sSpiInformation.ulSpiState != eSPI_STATE_IDLE) { printf("Wait for eSPI_STATE_IDLE\r\n"); } sSpiInformation.ulSpiState = eSPI_STATE_WRITE_IRQ; sSpiInformation.pTxPacket = pUserBuffer; sSpiInformation.usTxPacketLength = usLength; // Assert the CS line and wait till SSI IRQ line is active and then // initialize write operation ASSERT_CS(); // Re-enable IRQ - if it was not disabled - this is not a problem... tSLInformation.WlanInterruptEnable(); // check for a missing interrupt between the CS assertion and enabling back the interrupts if (tSLInformation.ReadWlanInterruptPin() == 0) { SpiWriteDataSynchronous(sSpiInformation.pTxPacket, sSpiInformation.usTxPacketLength); sSpiInformation.ulSpiState = eSPI_STATE_IDLE; DEASSERT_CS(); } } // Due to the fact that we are currently implementing a blocking situation // here we will wait till end of transaction while (eSPI_STATE_IDLE != sSpiInformation.ulSpiState) ; return(0); } //***************************************************************************** // //! SpiWriteDataSynchronous //! //! @param data buffer to write //! @param size buffer's size //! //! @return none //! //! @brief Spi write operation // //***************************************************************************** void SpiWriteDataSynchronous(unsigned char *data, unsigned short size) { while (size) { //while (!(TXBufferIsEmpty())); //UCB0TXBUF = *data; spi.write(*data); //while (!(RXBufferIsEmpty())); //spi.write(0x00); //UCB0RXBUF; size --; //printf("data %x\r\n",*data); data++; } } //***************************************************************************** // //! SpiReadDataSynchronous //! //! @param data buffer to read //! @param size buffer's size //! //! @return none //! //! @brief Spi read operation // //***************************************************************************** void SpiReadDataSynchronous(unsigned char *data, unsigned short size) { unsigned char *data_to_send = tSpiReadHeader; //printf("SPI Read..\r\n"); for (int i = 0; i < size; i ++) { //while (!(TXBufferIsEmpty())); //Dummy write to trigger the clock //UCB0TXBUF = data_to_send[0]; //spi.write(data_to_send[0]); //while (!(RXBufferIsEmpty())); data[i] = spi.write(data_to_send[0]); //data[i] = UCB0RXBUF; //printf("SPI Read..%x\r\n",data[i]); } } //***************************************************************************** // //! SpiReadHeader //! //! \param buffer //! //! \return none //! //! \brief This function enter point for read flow: first we read minimal 5 //! SPI header bytes and 5 Event Data bytes // //***************************************************************************** void SpiReadHeader(void) { SpiReadDataSynchronous(sSpiInformation.pRxPacket, 10); } //***************************************************************************** // //! SpiReadDataCont //! //! @param None //! //! @return None //! //! @brief This function processes received SPI Header and in accordance with //! it - continues reading the packet // //***************************************************************************** long SpiReadDataCont(void) { long data_to_recv; unsigned char *evnt_buff, type; //determine what type of packet we have evnt_buff = sSpiInformation.pRxPacket; data_to_recv = 0; STREAM_TO_UINT8((char *)(evnt_buff + SPI_HEADER_SIZE), HCI_PACKET_TYPE_OFFSET, type); switch(type) { case HCI_TYPE_DATA: { // We need to read the rest of data.. STREAM_TO_UINT16((char *)(evnt_buff + SPI_HEADER_SIZE), HCI_DATA_LENGTH_OFFSET, data_to_recv); if (!((HEADERS_SIZE_EVNT + data_to_recv) & 1)) { data_to_recv++; } if (data_to_recv) { SpiReadDataSynchronous(evnt_buff + 10, data_to_recv); } break; } case HCI_TYPE_EVNT: { // Calculate the rest length of the data STREAM_TO_UINT8((char *)(evnt_buff + SPI_HEADER_SIZE), HCI_EVENT_LENGTH_OFFSET, data_to_recv); data_to_recv -= 1; // Add padding byte if needed if ((HEADERS_SIZE_EVNT + data_to_recv) & 1) { data_to_recv++; } if (data_to_recv) { SpiReadDataSynchronous(evnt_buff + 10, data_to_recv); } sSpiInformation.ulSpiState = eSPI_STATE_READ_EOT; break; } } return (0); } //***************************************************************************** // //! SpiPauseSpi //! //! @param none //! //! @return none //! //! @brief Spi pause operation // //***************************************************************************** void SpiPauseSpi(void) { WlanInterruptDisable(); //SPI_IRQ_IE &= ~SPI_IRQ_PIN; } //***************************************************************************** // //! SpiResumeSpi //! //! @param none //! //! @return none //! //! @brief Spi resume operation // //***************************************************************************** void SpiResumeSpi(void) { WlanInterruptEnable(); //SPI_IRQ_IE |= SPI_IRQ_PIN; } //***************************************************************************** // //! SpiTriggerRxProcessing //! //! @param none //! //! @return none //! //! @brief Spi RX processing // //***************************************************************************** void SpiTriggerRxProcessing(void) { // Trigger Rx processing SpiPauseSpi(); DEASSERT_CS(); // The magic number that resides at the end of the TX/RX buffer (1 byte after // the allocated size) for the purpose of detection of the overrun. If the // magic number is overwritten - buffer overrun occurred - and we will stuck // here forever! if (sSpiInformation.pRxPacket[CC3000_RX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) { while (1) printf("Buffer Over run....\r\n"); ; } sSpiInformation.ulSpiState = eSPI_STATE_IDLE; sSpiInformation.SPIRxHandler(sSpiInformation.pRxPacket + SPI_HEADER_SIZE); } //***************************************************************************** // //! IntSpiGPIOHandler //! //! @param none //! //! @return none //! //! @brief GPIO A interrupt handler. When the external SSI WLAN device is //! ready to interact with Host CPU it generates an interrupt signal. //! After that Host CPU has registered this interrupt request //! it set the corresponding /CS in active state. // //***************************************************************************** //#pragma vector=PORT2_VECTOR //__interrupt void IntSpiGPIOHandler(void) void IntSpiGPIOHandler(void) { //switch(__even_in_range(P2IV, P2IV_P2IFG7)) //printf("IRQ ISR\r\n"); //{ //case event: if (sSpiInformation.ulSpiState == eSPI_STATE_POWERUP) { //This means IRQ line was low call a callback of HCI Layer to inform //on event sSpiInformation.ulSpiState = eSPI_STATE_INITIALIZED; } else if (sSpiInformation.ulSpiState == eSPI_STATE_IDLE) { sSpiInformation.ulSpiState = eSPI_STATE_READ_IRQ; /* IRQ line goes down - we are start reception */ ASSERT_CS(); // Wait for TX/RX Compete which will come as DMA interrupt SpiReadHeader(); sSpiInformation.ulSpiState = eSPI_STATE_READ_EOT; SSIContReadOperation(); } else if (sSpiInformation.ulSpiState == eSPI_STATE_WRITE_IRQ) { SpiWriteDataSynchronous(sSpiInformation.pTxPacket, sSpiInformation.usTxPacketLength); sSpiInformation.ulSpiState = eSPI_STATE_IDLE; DEASSERT_CS(); } // break; //default: // break; //} } //***************************************************************************** // //! SSIContReadOperation //! //! @param none //! //! @return none //! //! @brief SPI read operation // //***************************************************************************** void SSIContReadOperation(void) { // The header was read - continue with the payload read if (!SpiReadDataCont()) { // All the data was read - finalize handling by switching to the task // and calling from task Event Handler SpiTriggerRxProcessing(); } } //***************************************************************************** // //! TXBufferIsEmpty //! //! @param //! //! @return returns 1 if buffer is empty, 0 otherwise //! //! @brief Indication if TX SPI buffer is empty // //***************************************************************************** long TXBufferIsEmpty(void) { //return (UCB0IFG&UCTXIFG); return (1); } //***************************************************************************** // //! RXBufferIsEmpty //! //! @param none //! //! @return returns 1 if buffer is empty, 0 otherwise //! //! @brief Indication if RX SPI buffer is empty // //***************************************************************************** long RXBufferIsEmpty(void) { //return (UCB0IFG&UCRXIFG); return (0); } //***************************************************************************** // // Close the Doxygen group. //! @} // //*****************************************************************************