CC3000HostDriver for device TI CC3000 some changes were made due to mbed compiler and the use of void*
Diff: spi.cpp
- Revision:
- 0:9cb694f00b7b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/spi.cpp Fri Aug 02 15:06:15 2013 +0000
@@ -0,0 +1,722 @@
+
+/*****************************************************************************
+*
+* 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.
+//! @}
+//
+//*****************************************************************************
+