diff --git a/CC3000_Host_Driver/evnt_handler.c b/CC3000_Host_Driver/evnt_handler.c index 6142238..dfdcc6d 100644 --- a/CC3000_Host_Driver/evnt_handler.c +++ b/CC3000_Host_Driver/evnt_handler.c @@ -58,6 +58,7 @@ #include "hw_config.h" #include "debug.h" #include "spark_macros.h" +#include //***************************************************************************** // COMMON DEFINES @@ -120,7 +121,7 @@ // GLOBAL VARAIABLES //***************************************************************************** -UINT32 socket_active_status = SOCKET_STATUS_INIT_VAL; +static volatile UINT32 socket_active_status = SOCKET_STATUS_INIT_VAL; uint32_t cc3000__event_timeout_ms = 0; //***************************************************************************** @@ -834,20 +835,20 @@ INT32 hci_unsolicited_event_handler(void) //***************************************************************************** void set_socket_active_status(INT32 Sd, INT32 Status) { - DEBUG("Sd=%d, Status %s",Sd, Status == SOCKET_STATUS_ACTIVE ? "SOCKET_STATUS_ACTIVE" : "SOCKET_STATUS_IACTIVE"); + DEBUG("Sd=%d, Status %s",Sd, Status == SOCKET_STATUS_ACTIVE ? "SOCKET_STATUS_ACTIVE" : "SOCKET_STATUS_INACTIVE"); if(M_IS_VALID_SD(Sd) && M_IS_VALID_STATUS(Status)) { - uint32_t is = __get_PRIMASK(); - __disable_irq(); - socket_active_status &= ~(1 << Sd); /* clean socket's mask */ - socket_active_status |= (Status << Sd); /* set new socket's mask */ - if ((is & 1) == 0) { - __enable_irq(); + for (;;) { + INT32 oldStatus = socket_active_status; + INT32 newStatus = oldStatus; + newStatus &= ~(1 << Sd); /* clean socket's mask */ + newStatus |= (Status << Sd); /* set new socket's mask */ + if (__sync_bool_compare_and_swap(&socket_active_status, oldStatus, newStatus)) + break; } } } - //***************************************************************************** // //! hci_event_unsol_flowcontrol_handler @@ -881,8 +882,8 @@ INT32 hci_event_unsol_flowcontrol_handler(CHAR *pEvent) pReadPayload += FLOW_CONTROL_EVENT_SIZE; } - tSLInformation.usNumberOfFreeBuffers += temp; - tSLInformation.NumberOfReleasedPackets += temp; + __sync_add_and_fetch(&tSLInformation.usNumberOfFreeBuffers, temp); + __sync_add_and_fetch(&tSLInformation.NumberOfReleasedPackets, temp); return(ESUCCESS); } @@ -903,12 +904,7 @@ INT32 get_socket_active_status(INT32 Sd) long rv = SOCKET_STATUS_INACTIVE; if(M_IS_VALID_SD(Sd)) { - uint32_t is = __get_PRIMASK(); - __disable_irq(); rv = (socket_active_status & (1 << Sd)) ? SOCKET_STATUS_INACTIVE : SOCKET_STATUS_ACTIVE; - if ((is & 1) == 0) { - __enable_irq(); - } } return rv; } diff --git a/CC3000_Host_Driver/evnt_handler.h b/CC3000_Host_Driver/evnt_handler.h index b649501..011f18c 100644 --- a/CC3000_Host_Driver/evnt_handler.h +++ b/CC3000_Host_Driver/evnt_handler.h @@ -107,8 +107,6 @@ extern INT32 hci_unsolicited_event_handler(void); #define M_IS_VALID_SD(sd) ((0 <= (sd)) && ((sd) <= 7)) #define M_IS_VALID_STATUS(status) (((status) == SOCKET_STATUS_ACTIVE)||((status) == SOCKET_STATUS_INACTIVE)) -extern UINT32 socket_active_status; - extern void set_socket_active_status(INT32 Sd, INT32 Status); extern INT32 get_socket_active_status(INT32 Sd); diff --git a/CC3000_Host_Driver/socket.c b/CC3000_Host_Driver/socket.c index 7f3e91b..268a31e 100644 --- a/CC3000_Host_Driver/socket.c +++ b/CC3000_Host_Driver/socket.c @@ -119,6 +119,7 @@ INT16 HostFlowControlConsumeBuff(INT16 sd) /* wait in busy loop */ volatile system_tick_t start = GetSystem1MsTick(); + bool stop = false; do { // In case last transmission failed then we will return the last failure @@ -145,10 +146,12 @@ INT16 HostFlowControlConsumeBuff(INT16 sd) return -1; } - } while(0 == tSLInformation.usNumberOfFreeBuffers); - - tSLInformation.usNumberOfFreeBuffers--; - + // Do an atomic decrement if > 0 + UINT16 freeBuffers = tSLInformation.usNumberOfFreeBuffers; + if (0 < freeBuffers) { + stop = __sync_bool_compare_and_swap(&tSLInformation.usNumberOfFreeBuffers, freeBuffers, freeBuffers-1); + } + } while (!stop); return 0; #else @@ -1149,7 +1152,7 @@ INT16 sendto(INT32 sd, const void *buf, INT32 len, INT32 flags, const sockaddr * // //***************************************************************************** -INT16 mdnsAdvertiser(UINT16 mdnsEnabled, CHAR * deviceServiceName, UINT16 deviceServiceNameLength) +INT16 mdnsAdvertiser(UINT16 mdnsEnabled, const CHAR * deviceServiceName, UINT16 deviceServiceNameLength) { INT8 ret; UINT8 *pTxBuffer, *pArgs; diff --git a/CC3000_Host_Driver/socket.h b/CC3000_Host_Driver/socket.h index 75c3684..638b245 100644 --- a/CC3000_Host_Driver/socket.h +++ b/CC3000_Host_Driver/socket.h @@ -640,7 +640,7 @@ extern INT16 sendto(INT32 sd, const void *buf, INT32 len, INT32 flags, //! @brief Set CC3000 in mDNS advertiser mode in order to advertise itself. // //***************************************************************************** -extern INT16 mdnsAdvertiser(UINT16 mdnsEnabled, CHAR * deviceServiceName, UINT16 deviceServiceNameLength); +extern INT16 mdnsAdvertiser(UINT16 mdnsEnabled, const CHAR * deviceServiceName, UINT16 deviceServiceNameLength); //***************************************************************************** diff --git a/CC3000_Host_Driver/wlan.c b/CC3000_Host_Driver/wlan.c index 90e859f..5425168 100644 --- a/CC3000_Host_Driver/wlan.c +++ b/CC3000_Host_Driver/wlan.c @@ -349,8 +349,8 @@ void wlan_stop(void) //***************************************************************************** #ifndef CC3000_TINY_DRIVER -INT32 wlan_connect(UINT32 ulSecType, CHAR *ssid, INT32 ssid_len, - UINT8 *bssid, UINT8 *key, INT32 key_len) +INT32 wlan_connect(UINT32 ulSecType, const CHAR *ssid, INT32 ssid_len, + const UINT8 *bssid, const UINT8 *key, INT32 key_len) { INT32 ret; UINT8 *ptr; diff --git a/CC3000_Host_Driver/wlan.h b/CC3000_Host_Driver/wlan.h index 386a657..485c331 100644 --- a/CC3000_Host_Driver/wlan.h +++ b/CC3000_Host_Driver/wlan.h @@ -189,8 +189,8 @@ extern void wlan_stop(void); // //***************************************************************************** #ifndef CC3000_TINY_DRIVER -extern INT32 wlan_connect(UINT32 ulSecType, CHAR *ssid, INT32 ssid_len, - UINT8 *bssid, UINT8 *key, INT32 key_len); +extern INT32 wlan_connect(UINT32 ulSecType, const CHAR *ssid, INT32 ssid_len, + const UINT8 *bssid, const UINT8 *key, INT32 key_len); #else extern INT32 wlan_connect(CHAR *ssid, INT32 ssid_len); diff --git a/SPARK_Firmware_Driver/inc/cc3000_spi.h b/SPARK_Firmware_Driver/inc/cc3000_spi.h index cd5db62..fb62952 100644 --- a/SPARK_Firmware_Driver/inc/cc3000_spi.h +++ b/SPARK_Firmware_Driver/inc/cc3000_spi.h @@ -71,4 +71,6 @@ extern void SpiResumeSpi(void); extern void SPI_DMA_IntHandler(void); extern void SPI_EXTI_IntHandler(void); +extern void handle_spi_request(); + #endif /* __CC3000_SPI_H */ diff --git a/SPARK_Firmware_Driver/inc/hw_config.h b/SPARK_Firmware_Driver/inc/hw_config.h index d179a5a..dd7c558 100644 --- a/SPARK_Firmware_Driver/inc/hw_config.h +++ b/SPARK_Firmware_Driver/inc/hw_config.h @@ -35,6 +35,13 @@ #include "cc3000_common.h" #include "usb_type.h" +enum SpiBusOwner { + BUS_OWNER_NONE = 0, + BUS_OWNER_CC3000 = 1, + BUS_OWNER_SFLASH = 2 +}; + + /* Exported types ------------------------------------------------------------*/ typedef enum { diff --git a/SPARK_Firmware_Driver/inc/spi_bus.h b/SPARK_Firmware_Driver/inc/spi_bus.h new file mode 100644 index 0000000..41477a5 --- /dev/null +++ b/SPARK_Firmware_Driver/inc/spi_bus.h @@ -0,0 +1,30 @@ +/* + * File: spi_bus.h + * Author: mat + * + * Created on 30 June 2014, 14:25 + */ + +#ifndef SPI_BUS_H +#define SPI_BUS_H + +#ifdef __cplusplus +extern "C" { +#endif + + void reset_bus(); + +int try_acquire_spi_bus(int owner); + +void acquire_spi_bus(int owner); + +void release_spi_bus(int owner); + +int current_bus_owner(); + +#ifdef __cplusplus +} +#endif + +#endif /* SPI_BUS_H */ + diff --git a/SPARK_Firmware_Driver/src/build.mk b/SPARK_Firmware_Driver/src/build.mk index 76f5f7f..cb7966a 100644 --- a/SPARK_Firmware_Driver/src/build.mk +++ b/SPARK_Firmware_Driver/src/build.mk @@ -18,6 +18,7 @@ CSRC += $(TARGET_SPARK_SRC_PATH)/system_stm32f10x.c CSRC += $(TARGET_SPARK_SRC_PATH)/usb_pwr.c CSRC += $(TARGET_SPARK_SRC_PATH)/debug.c CSRC += $(TARGET_SPARK_SRC_PATH)/panic.c +CSRC += $(TARGET_SPARK_SRC_PATH)/spi_bus.c # C++ source files included in this build. CPPSRC += diff --git a/SPARK_Firmware_Driver/src/cc3000_spi.c b/SPARK_Firmware_Driver/src/cc3000_spi.c index 1aa490a..d0f9b05 100644 --- a/SPARK_Firmware_Driver/src/cc3000_spi.c +++ b/SPARK_Firmware_Driver/src/cc3000_spi.c @@ -35,6 +35,7 @@ #include "socket.h" #include "spark_macros.h" #include "debug.h" +#include "spi_bus.h" #define READ_COMMAND {READ, 0 , 0 , 0 , 0} #define READ_OFFSET_TO_LENGTH 3 //cmd dmy dmy lh ll @@ -52,6 +53,7 @@ typedef enum eSPI_STATE_READ_IRQ, eSPI_STATE_READ_PROCEED, eSPI_STATE_READ_READY, + eSPI_STATE_READ_PREP_IRQ } eCC3000States; @@ -117,13 +119,17 @@ static inline eCC3000States State() static inline eCC3000States SetState(eCC3000States ns, eCSActions cs) { - intState save = DISABLE_INT(); eCC3000States os = sSpiInformation.ulSpiState; sSpiInformation.ulSpiState = ns; - if (cs != eNone) + switch (cs) { - cs == eAssert ? ASSERT_CS() : DEASSERT_CS(); + case eAssert: + ASSERT_CS(); + break; + case eDeAssert: + DEASSERT_CS(); + break; } ENABLE_INT(save); return os; @@ -325,6 +331,7 @@ long SpiWrite(unsigned char *ucBuf, unsigned short usLength) if(NotAborted) { NotAborted = Reserve(eSPI_STATE_WRITE_WAIT_IRQ); + WARN("CC3000 SpiWrite acquire bus"); if(NotAborted) { usLength = SpiSetUp(ucBuf, usLength); @@ -396,9 +403,9 @@ void SPI_DMA_IntHandler(void) /* Clear SPI_DMA Interrupt Pending Flags */ DMA_ClearFlag(CC3000_SPI_TX_DMA_TCFLAG | CC3000_SPI_RX_DMA_TCFLAG); - sSpiInformation.ulSpiState = eSPI_STATE_IDLE; SpiPauseSpi(); - DEASSERT_CS(); + SetState(eSPI_STATE_IDLE, eDeAssert); + WARN("CC3000 DmaHandler release read spi bus"); // Call out to the Unsolicited handler // It will handle the event or leave it there for an outstanding opcode // It it handles it the it Will resume the SPI ISR @@ -426,9 +433,8 @@ void SPI_DMA_IntHandler(void) } else { - DEASSERT_CS(); - - sSpiInformation.ulSpiState = eSPI_STATE_IDLE; + SetState(eSPI_STATE_IDLE, eDeAssert); + WARN("CC3000 DmaHandler release write spi bus"); } } break; @@ -440,6 +446,16 @@ void SPI_DMA_IntHandler(void) } } +void handle_spi_request() +{ + if (State() == eSPI_STATE_READ_PREP_IRQ && try_acquire_spi_bus(BUS_OWNER_CC3000)) + { + DEBUG("Handling CC3000 request on main thread"); + SetState(eSPI_STATE_READ_IRQ, eAssert); + SpiIO(eRead, sSpiInformation.pRxPacket, arraySize(spi_readCommand), FALSE); + DEBUG("...done"); + } +} /** * @brief The handler for Interrupt that is generated when CC3000 brings the @@ -458,9 +474,13 @@ void SPI_EXTI_IntHandler(void) sSpiInformation.ulSpiState = eSPI_STATE_INITIALIZED; break; case eSPI_STATE_IDLE: - sSpiInformation.ulSpiState = eSPI_STATE_READ_IRQ; - ASSERT_CS(); - SpiIO(eRead, sSpiInformation.pRxPacket, arraySize(spi_readCommand), FALSE); + if (try_acquire_spi_bus(BUS_OWNER_CC3000)) { + SetState(eSPI_STATE_READ_IRQ, eAssert); + SpiIO(eRead, sSpiInformation.pRxPacket, arraySize(spi_readCommand), FALSE); + } else { + SetState(eSPI_STATE_READ_PREP_IRQ, eNone); + WARN("CC3000 cannot lock bus - scheduling later (owner=%d)", current_bus_owner()); + } break; case eSPI_STATE_WRITE_WAIT_IRQ: sSpiInformation.ulSpiState = eSPI_STATE_WRITE_PROCEED; diff --git a/SPARK_Firmware_Driver/src/hw_config.c b/SPARK_Firmware_Driver/src/hw_config.c index f2cf99c..6315481 100644 --- a/SPARK_Firmware_Driver/src/hw_config.c +++ b/SPARK_Firmware_Driver/src/hw_config.c @@ -28,6 +28,9 @@ #include "usb_lib.h" #include "usb_pwr.h" #include +#include "spi_bus.h" +#include "debug.h" +#include "cc3000_spi.h" /* Private typedef -----------------------------------------------------------*/ @@ -952,8 +955,8 @@ void CC3000_SPI_DMA_Channels(FunctionalState NewState) /* Select CC3000: ChipSelect pin low */ void CC3000_CS_LOW(void) { + acquire_spi_bus(BUS_OWNER_CC3000); CC3000_SPI->CR1 &= ((uint16_t)0xFFBF); - sFLASH_CS_HIGH(); CC3000_SPI->CR1 = CC3000_SPI_CR | ((uint16_t)0x0040); GPIO_ResetBits(CC3000_WIFI_CS_GPIO_PORT, CC3000_WIFI_CS_GPIO_PIN); } @@ -962,6 +965,7 @@ void CC3000_CS_LOW(void) void CC3000_CS_HIGH(void) { GPIO_SetBits(CC3000_WIFI_CS_GPIO_PORT, CC3000_WIFI_CS_GPIO_PIN); + release_spi_bus(BUS_OWNER_CC3000); } /* CC3000 Hardware related callbacks passed to wlan_init */ @@ -1133,8 +1137,8 @@ void sFLASH_SPI_Init(void) /* Select sFLASH: Chip Select pin low */ void sFLASH_CS_LOW(void) { + acquire_spi_bus(BUS_OWNER_SFLASH); sFLASH_SPI->CR1 &= ((uint16_t)0xFFBF); - CC3000_CS_HIGH(); sFLASH_SPI->CR1 = sFLASH_SPI_CR | ((uint16_t)0x0040); GPIO_ResetBits(sFLASH_MEM_CS_GPIO_PORT, sFLASH_MEM_CS_GPIO_PIN); } @@ -1143,6 +1147,8 @@ void sFLASH_CS_LOW(void) void sFLASH_CS_HIGH(void) { GPIO_SetBits(sFLASH_MEM_CS_GPIO_PORT, sFLASH_MEM_CS_GPIO_PIN); + release_spi_bus(BUS_OWNER_SFLASH); + handle_spi_request(); } /******************************************************************************* diff --git a/SPARK_Firmware_Driver/src/spi_bus.c b/SPARK_Firmware_Driver/src/spi_bus.c new file mode 100644 index 0000000..55ccafb --- /dev/null +++ b/SPARK_Firmware_Driver/src/spi_bus.c @@ -0,0 +1,45 @@ +#include +#include +#include "spi_bus.h" +#include "debug.h" +#include "hw_config.h" + +#ifndef SPI_BUS_ARBITER +#define SPI_BUS_ARBITER 1 +#endif + +volatile int spi_bus_lock = 0; + +void reset_bus() { spi_bus_lock = 0; } + +int try_acquire_spi_bus(int owner) { +#if SPI_BUS_ARBITER + __sync_synchronize(); + return spi_bus_lock==owner || __sync_bool_compare_and_swap(&spi_bus_lock, 0, owner); +#else + return 1; +#endif +} + +void acquire_spi_bus(int owner) { +#if SPI_BUS_ARBITER + while (!try_acquire_spi_bus(owner)); +#endif +} + +int try_release_spi_bus(int owner) { +#if SPI_BUS_ARBITER + __sync_synchronize(); + return spi_bus_lock==0 || __sync_bool_compare_and_swap(&spi_bus_lock, owner, 0); +#else + return 1; +#endif +} + +void release_spi_bus(int owner) { +#if SPI_BUS_ARBITER + while (!try_release_spi_bus(owner)); +#endif +} + +int current_bus_owner() { return spi_bus_lock; }