It seems that if I do not have a line of debug in my code, I can become stuck in hci_event_handler. I believe I have found the culprit to be a race condition in which tSLInformation.usRxEventOpcode is set too late - after the IRQ arrives. Unfortunately the SPI data receive handler performs a key check on this variable, (evnt_handler.c:639) which will scrap the received data if it hasn't been set. This happens if the interrupt happens before we get into the SimpleLinkWaitEvent call, (evnt_handler.c:816)
/* The following shows a race condition due to setting tSLInformation.usRxEventOpcode too late. (Only code of note shown.) CC3000 Host Driver: 1.11.1 */ /* Call to wlan_start */ wlan.c:256 wlan_start() /* Stuff ... */ wlan.c:306 hci_command_send(HCI_CMND_READ_BUFFER_SIZE, tSLInformation.pucTxCommandBuffer, 0); wlan.c:307 SimpleLinkWaitEvent(HCI_CMND_READ_BUFFER_SIZE, 0); /* If an interrupt should happen before this point, it will result in the host driver getting stuck in a loop */ evnt_handler.c:816 tSLInformation.usRxEventOpcode = usOpcode; /* The following is called after IRQ pin drops, SPI data read in */ wlan.c:219 void SpiReceiveHandler(void *pvBuffer) wlan.c:224 hci_unsolicited_event_handler(); evnt_handler.c:673 if (hci_unsol_event_handler((char *)pucReceivedData) == 1) evnt_handler.c:639 if ((event_type != tSLInformation.usRxEventOpcode) && (event_type != HCI_EVNT_PATCHES_REQ)) { return(1); } /* Now considering what happens if this returns 1... */ evnt_handler.c:673 if (hci_unsol_event_handler((char *)pucReceivedData) == 1) { /* This ultimately causes this command to be lost... */ tSLInformation.usEventOrDataReceived = 0; res = 1; SpiResumeSpi(); } /* Once the IRQ finishes we continue processing */ evnt_handler.c:816 hci_event_handler(pRetParams, 0, 0); /* Since we set this to zero, we loop on this forever... */ while (1) { evnt_handler.c:241 if (tSLInformation.usEventOrDataReceived != 0)
Thoughts and suggested fixes?
From searching this forum I think there is a good chance the following posts are describing this problem.
http://e2e.ti.com/support/low_power_rf/f/851/t/305178.aspx
http://e2e.ti.com/support/low_power_rf/f/851/t/295158.aspx
http://e2e.ti.com/support/low_power_rf/f/851/t/292783.aspx
http://e2e.ti.com/support/low_power_rf/f/851/t/303733.aspx
EDIT for some clarification: My host is running a RTOS (ChibiOS) so rather than handling the interrupt in an ISR it is passed onto a thread. This problem can manifest itself in in the following way:
CC3000 Control Thread | IRQ Processing Thread |
Send SPI Command | |
Receive Reply | |
Unexpected opcode - delete data | |
Set expected reply opcode |
My solution to this problem was to insert a wait in the IRQ processing thread, before the call to the registered processing callback is triggered. This wait will permit the control thread to execute a bit further, hopefully setting usRxEventOpcode: