diff options
Diffstat (limited to 'stmhal/cc3k/ccspi.c')
-rw-r--r-- | stmhal/cc3k/ccspi.c | 737 |
1 files changed, 737 insertions, 0 deletions
diff --git a/stmhal/cc3k/ccspi.c b/stmhal/cc3k/ccspi.c new file mode 100644 index 0000000000..4785897e13 --- /dev/null +++ b/stmhal/cc3k/ccspi.c @@ -0,0 +1,737 @@ +/***************************************************************************** +* +* spi.c - CC3000 Host Driver Implementation. +* Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ +* +* Adapted for use with the Arduino/AVR by KTOWN (Kevin Townsend) +* & Limor Fried for Adafruit Industries +* This library works with the Adafruit CC3000 breakout +* ----> https://www.adafruit.com/products/1469 +* Adafruit invests time and resources providing this open source code, +* please support Adafruit and open-source hardware by purchasing +* products from Adafruit! +* +* 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. +* +*****************************************************************************/ +#include <stdint.h> +#include <string.h> // for memset + +#include "ccspi.h" +#include "hci.h" +#include "netapp.h" +#include "evnt_handler.h" +#include "cc3000_common.h" +#include "ccdebug.h" +#include "pybcc3k.h" + +#define READ (3) +#define WRITE (1) +#define HI(value) (((value) & 0xFF00) >> 8) +#define LO(value) ((value) & 0x00FF) +#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) + +// CC3000 chip select +#define CC3000_ASSERT_CS() pyb_cc3000_set_cs(0) +// CC3000 chip deselect +#define CC3000_DEASSERT_CS() pyb_cc3000_set_cs(1) + +/* smartconfig flags (defined in Adafruit_CC3000.cpp) */ +// extern unsigned long ulSmartConfigFinished, ulCC3000DHCP; + +typedef struct +{ + gcSpiHandleRx SPIRxHandler; + + unsigned short usTxPacketLength; + unsigned short usRxPacketLength; + unsigned long ulSpiState; + unsigned char *pTxPacket; + unsigned char *pRxPacket; + +} tSpiInformation; + +tSpiInformation sSpiInformation; + +/* Static 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); +void cc3k_int_poll(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 occured and either recevie function +// or send function will stuck forever. +#define CC3000_BUFFER_MAGIC_NUMBER (0xDE) + +char spi_buffer[CC3000_RX_BUFFER_SIZE]; +unsigned char wlan_tx_buffer[CC3000_TX_BUFFER_SIZE]; + +static volatile char ccspi_is_in_irq = 0; +static volatile char ccspi_int_enabled = 0; + +/* Mandatory functions are: + - SpiOpen + - SpiWrite + - SpiRead + - SpiClose + - SpiResumeSpi + - ReadWlanInterruptPin + - WlanInterruptEnable + - WlanInterruptDisable + - WriteWlanPin + */ + +void SpiInit(void) +{ + pyb_cc3000_spi_init(); +} + + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiClose(void) +{ + DEBUGPRINT_F("\tCC3000: SpiClose"); + + if (sSpiInformation.pRxPacket) + { + sSpiInformation.pRxPacket = 0; + } + + /* Disable Interrupt in GPIOA module... */ + tSLInformation.WlanInterruptDisable(); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiOpen(gcSpiHandleRx pfRxHandler) +{ + DEBUGPRINT_F("\tCC3000: SpiOpen"); + + sSpiInformation.ulSpiState = eSPI_STATE_POWERUP; + + memset(spi_buffer, 0, sizeof(spi_buffer)); + memset(wlan_tx_buffer, 0, sizeof(spi_buffer)); + + 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 the GPIO pin of WLAN IRQ */ + tSLInformation.WlanInterruptEnable(); + + DEBUGPRINT_F("\tCC3000: Finished SpiOpen\n\r"); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +#if 0 +extern uint8_t g_csPin, g_irqPin, g_vbatPin, g_IRQnum, g_SPIspeed; + +int init_spi(void) +{ + + DEBUGPRINT_F("\tCC3000: init_spi\n\r"); + + /* Set POWER_EN pin to output and disable the CC3000 by default */ + pinMode(g_vbatPin, OUTPUT); + digitalWrite(g_vbatPin, 0); + delay(500); + + /* Set CS pin to output (don't de-assert yet) */ + pinMode(g_csPin, OUTPUT); + + /* Set interrupt/gpio pin to input */ +#if defined(INPUT_PULLUP) + pinMode(g_irqPin, INPUT_PULLUP); +#else + pinMode(g_irqPin, INPUT); + digitalWrite(g_irqPin, HIGH); // w/weak pullup +#endif + + /* Initialise SPI (Mode 1) */ + SPI.begin(); + SPI.setDataMode(SPI_MODE1); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider(g_SPIspeed); + + // Newly-initialized SPI is in the same state that ASSERT_CS will set it + // to. Invoke DEASSERT (which also restores SPI registers) so the next + // ASSERT call won't clobber the ccspi_old* values -- we need those! + CC3000_DEASSERT_CS(); + + /* ToDo: Configure IRQ interrupt! */ + + DEBUGPRINT_F("\tCC3000: Finished init_spi\n\r"); + + return(ESUCCESS); +} +#endif + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +long SpiFirstWrite(unsigned char *ucBuf, unsigned short usLength) +{ + DEBUGPRINT_F("\tCC3000: SpiWriteFirst\n\r"); + + /* Workaround for the first transaction */ + CC3000_ASSERT_CS(); + + /* delay (stay low) for ~50us */ + pyb_delay_us(50); + + /* SPI writes first 4 bytes of data */ + SpiWriteDataSynchronous(ucBuf, 4); + + pyb_delay_us(50); + + SpiWriteDataSynchronous(ucBuf + 4, usLength - 4); + + /* From this point on - operate in a regular manner */ + sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + + CC3000_DEASSERT_CS(); + + return(0); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +long SpiWrite(unsigned char *pUserBuffer, unsigned short usLength) +{ + unsigned char ucPad = 0; + + DEBUGPRINT_F("\tCC3000: SpiWrite\n\r"); + + /* 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 overrun detection. If the magic number is overwritten - buffer overrun + * occurred - and we will be stuck here forever! */ + if (wlan_tx_buffer[CC3000_TX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) + { + DEBUGPRINT_F("\tCC3000: Error - No magic number found in SpiWrite\n\r"); + while (1); + } + + 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 two 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); + + 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 */ + CC3000_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; + + CC3000_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); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiWriteDataSynchronous(unsigned char *data, unsigned short size) +{ + int bSend = 0, bRecv = 0; + while (bSend<size || bRecv<size) { + int r = pyb_cc3000_spi_send((bSend<size)?data[bSend]:-1); + bSend++; + if (bSend>0 && r>=0) bRecv++; + } + + pyb_delay_us(10); // because of final clock pulse + + DEBUG_printf("SpiWriteDataSynchronous: data=%p size=%u bSend=%d bRecv=%d [%x %x %x %x]\n", data, size, bSend, bRecv, data[0], data[1], data[2], data[3]); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiReadDataSynchronous(unsigned char *data, unsigned short size) +{ + int bSend = 0, bRecv = 0; + while (bSend<size || bRecv<size) { + int r = pyb_cc3000_spi_send((bSend<size)?READ:-1); + bSend++; + if (bSend>0 && r>=0) data[bRecv++] = r; + } + + pyb_delay_us(10); // because of final clock pulse + + DEBUG_printf("SpiReadDataSynchronous: data=%p size=%u bSend=%d bRecv=%d [%x %x %x %x]\n", data, size, bSend, bRecv, data[0], data[1], data[2], data[3]); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiReadHeader(void) +{ + DEBUGPRINT_F("\tCC3000: SpiReadHeader\n\r"); + + SpiReadDataSynchronous(sSpiInformation.pRxPacket, HEADERS_SIZE_EVNT); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +long SpiReadDataCont(void) +{ + long data_to_recv; + unsigned char *evnt_buff, type; + + DEBUGPRINT_F("\tCC3000: SpiReadDataCont\n\r"); + + /* Determine what type of packet we have */ + evnt_buff = sSpiInformation.pRxPacket; + data_to_recv = 0; + STREAM_TO_UINT8((uint8_t *)(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 + HEADERS_SIZE_EVNT, 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 + HEADERS_SIZE_EVNT, data_to_recv); + } + + sSpiInformation.ulSpiState = eSPI_STATE_READ_EOT; + break; + } + } + + return (0); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiPauseSpi(void) +{ + DEBUGPRINT_F("\tCC3000: SpiPauseSpi\n\r"); + + ccspi_int_enabled = 0; + pyb_cc3000_pause_spi(); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiResumeSpi(void) +{ + DEBUGPRINT_F("\tCC3000: SpiResumeSpi\n\r"); + + ccspi_int_enabled = 1; + pyb_cc3000_resume_spi(); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SpiTriggerRxProcessing(void) +{ + DEBUGPRINT_F("\tCC3000: SpiTriggerRxProcessing\n\r"); + + /* Trigger Rx processing */ + SpiPauseSpi(); + CC3000_DEASSERT_CS(); + + //DEBUGPRINT_F("Magic?\n\r"); + /* 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 overriten - buffer overrun + * occurred - and we will stuck here forever! */ + if (sSpiInformation.pRxPacket[CC3000_RX_BUFFER_SIZE - 1] != CC3000_BUFFER_MAGIC_NUMBER) + { + /* You've got problems if you're here! */ + DEBUGPRINT_F("\tCC3000: ERROR - magic number missing!\n\r"); + while (1); + } + + //DEBUGPRINT_F("OK!\n\r"); + sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + sSpiInformation.SPIRxHandler(sSpiInformation.pRxPacket + SPI_HEADER_SIZE); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void SSIContReadOperation(void) +{ + DEBUGPRINT_F("\tCC3000: SpiContReadOperation\n\r"); + + /* The header was read - continue with the payload read */ + if (!SpiReadDataCont()) + { + /* All the data was read - finalize handling by switching to teh task + * and calling from task Event Handler */ + //DEBUGPRINT_F("SPItrig\n\r"); + SpiTriggerRxProcessing(); + } +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void WriteWlanPin( unsigned char val ) +{ +#if 0 + if (DEBUG_MODE) + { + DEBUGPRINT_F("\tCC3000: WriteWlanPin - "); + DEBUGPRINT_DEC(val); + DEBUGPRINT_F("\n\r"); + delay(1); + } + if (val) + { + digitalWrite(g_vbatPin, HIGH); + } + else + { + digitalWrite(g_vbatPin, LOW); + } +#endif + pyb_cc3000_set_en(val == WLAN_ENABLE); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +long ReadWlanInterruptPin(void) +{ + DEBUGPRINT_F("\tCC3000: ReadWlanInterruptPin - "); + DEBUGPRINT_DEC(digitalRead(g_irqPin)); + DEBUGPRINT_F("\n\r"); + + return pyb_cc3000_get_irq(); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void WlanInterruptEnable() +{ + DEBUGPRINT_F("\tCC3000: WlanInterruptEnable.\n\r"); + // delay(100); + ccspi_int_enabled = 1; + pyb_cc3000_enable_irq(); +} + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ +void WlanInterruptDisable() +{ + DEBUGPRINT_F("\tCC3000: WlanInterruptDisable\n\r"); + ccspi_int_enabled = 0; + pyb_cc3000_disable_irq(); +} + +//***************************************************************************** +// +//! sendDriverPatch +//! +//! @param pointer to the length +//! +//! @return none +//! +//! @brief The function returns a pointer to the driver patch: +//! since there is no patch in the host - it returns 0 +// +//***************************************************************************** +char *sendDriverPatch(unsigned long *Length) { + *Length = 0; + return NULL; +} + +//***************************************************************************** +// +//! sendBootLoaderPatch +//! +//! @param pointer to the length +//! +//! @return none +//! +//! @brief The function returns a pointer to the boot loader patch: +//! since there is no patch in the host - it returns 0 +// +//***************************************************************************** +char *sendBootLoaderPatch(unsigned long *Length) { + *Length = 0; + return NULL; +} + +//***************************************************************************** +// +//! sendWLFWPatch +//! +//! @param pointer to the length +//! +//! @return none +//! +//! @brief The function returns a pointer to the FW patch: +//! since there is no patch in the host - it returns 0 +// +//***************************************************************************** +char *sendWLFWPatch(unsigned long *Length) { + *Length = 0; + return NULL; +} + + +/**************************************************************************/ +/*! + + */ +/**************************************************************************/ + +void SpiIntGPIOHandler(void) +{ + DEBUG_printf("SpiIntGPIOHandler\n"); + + ccspi_is_in_irq = 1; + + 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 */ + CC3000_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; + + CC3000_DEASSERT_CS(); + } + ccspi_is_in_irq = 0; +} + +#if 0 +void SPI_IRQ(void) +{ + ccspi_is_in_irq = 1; + + DEBUGPRINT_F("\tCC3000: Entering SPI_IRQ\n\r"); + + if (sSpiInformation.ulSpiState == eSPI_STATE_POWERUP) + { + /* IRQ line was low ... perform a callback on the HCI Layer */ + sSpiInformation.ulSpiState = eSPI_STATE_INITIALIZED; + } + else if (sSpiInformation.ulSpiState == eSPI_STATE_IDLE) + { + //DEBUGPRINT_F("IDLE\n\r"); + sSpiInformation.ulSpiState = eSPI_STATE_READ_IRQ; + /* IRQ line goes down - start reception */ + + CC3000_ASSERT_CS(); + + // Wait for TX/RX Compete which will come as DMA interrupt + SpiReadHeader(); + sSpiInformation.ulSpiState = eSPI_STATE_READ_EOT; + //DEBUGPRINT_F("SSICont\n\r"); + SSIContReadOperation(); + } + else if (sSpiInformation.ulSpiState == eSPI_STATE_WRITE_IRQ) + { + SpiWriteDataSynchronous(sSpiInformation.pTxPacket, sSpiInformation.usTxPacketLength); + sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + CC3000_DEASSERT_CS(); + } + + DEBUGPRINT_F("\tCC3000: Leaving SPI_IRQ\n\r"); + + ccspi_is_in_irq = 0; + return; +} +#endif + +//***************************************************************************** +// +//! cc3k_int_poll +//! +//! \brief checks if the interrupt pin is low +//! just in case the hardware missed a falling edge +//! function is in ccspi.cpp +// +//***************************************************************************** + +void cc3k_int_poll() +{ + if (pyb_cc3000_get_irq() == 0 && ccspi_is_in_irq == 0 && ccspi_int_enabled != 0) { + SpiIntGPIOHandler(); + } +} |