This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Using CC3100 simplelink driver in non interrupt environment?

Other Parts Discussed in Thread: CC3100, MSP430F5253, CC3100BOOST

I'm looking at running the simplelink driver in a non-interrupt based environment. Specifically, it will run in a bootloader, which does not use any interrupts. It looks to me like I could simply poll the cc3100 Host Interrupt line at the beginning of _SlNonOsMainLoopTask() and call _SlDrvRxIrqHandler() when the interrupt line is asserted. Is there any downside to doing it this way, or can someone suggest a better way?

  • I should add that we're only planning on using the file system API in the bootloader, as well as statring and stopping the device. So there shouldn't be any asynchronous messages coming from the CC3100 as far as I can tell.
  • Hi,

    I'm not sure what you mean by "using the file system API in the bootloader, as well as statring and stopping the device".

    Can you elaborate a little more?

    It seem you are still having the Host interrupt line so why not using it in non-OS mode as is demonstrated on some of the SDK examples?

    Shlomi

  • Hi Shlomi,

    We're creating a custom bootloader on the MSP430F5253, and one of its jobs is to update our application image. We've chosen to store the application image in the serial flash that is connected to the CC3100. So the bootloader needs the Simplelink drivers to read the application image file. As I understand it, whenever the CC3100 wants to send data to the host, it asserts the host interrupt line. The servicing of the interrupt on the host spawns the correct handling function, and a subsequent call to _SlNonOsMainLoopTask() will execute the handling function.

    In our bootloader, we don't want to handle any interrupts, so that we can have a single vector table that is owned by the application. So my question is how to best poll the host interrupt line to detect when the CC3100 has something to send to the host. My idea was to modify _SlNonOsMainLoopTask() to poll the host interrupt line, and if it's asserted, call _SlDrvRxIrqHandler(), which will spawn the handling function. Then the rest of _SlNonOsMainLoopTask() will execute the spawned function. So my question is will this work as long as all I'm using the CC3100 for is to start/stop it, and use the file system APIs?
  • I understand what you mean now.

    Please note that if you end up modifying the host driver, we cannot guarantee corner cases that might pop up since the driver has been tested as is.

    In any case, please note that you would not be able to have nested interrupt handling in case the polling is not fast enough. For example, even if you just power on the devie and it is configured in AP mode - you get 2 consecutive host interrupts, the INITCOMPLETE and the IPAAQUIRED events. You need to make sure you can handle it.

    The IRQ handler in the current implementation is bounded to HWI in order to spend as least time as possible.

    Again, what you suggest has not been tested but it sounds as if it could work.

    Shlomi

  • Thanks for the followup. I've implemented what I suggested, and I'm seeing something strange. I've attached 2 logic analyzer captures. What we're doing is opening a file to program into MSP flash memory. We're reading 512 bytes at a time from the file (since that's the MSP sector size), and writing the buffer to flash. Everything works file for the first 8 blocks. In the 9th block, we seem to get an extra host interrupt in the middle of the file read, but when the simplelink driver attempts to read, the semaphores appear to be in the wrong state and the driver gets stuck. What's strange is that if I insert a 100ms delay between the writing of the buffer to MSP flash and the next file read, everything works fine.

    Here are the definitions of the signals in the logic analyzer traces:

    WMISO, WMOSI, WCLK, WCX# are the MSP<->CC3100 SPI signals

    WINT is the CC3100's HOST_INTR signal

    TP73 is a GPIO that frames the call to sl_FsRead() during the read of the 8th 512 byte chunk

    TP74 frames the call to sl_FsRead() during the read of the 9th 512 byte chunk

    TP75 frames the call to sl_SyncObjClear() in _SlDrvMsgReadCmdCtx()

    The 1st logic analyzer trace shows the entire capture from sl_Start() to when the driver hangs during the read of the 9th 512 byte chunk. The 2nd trace is just a magnification of what happens during the 8th and 9th file read.

    Any idea why the CC3100 seems to assert the HOST_INTR during the 9th read from the file and why adding a 100ms delay seems to make it go away?

  • Hi,

    Most likely it is an Async event but this is exactly what I mentioned with changing the driver.

    Looking a little deeper into your suggestion, there are some things that are not very clear.

    • are you using a non-OS or OS flavor?
    • if it is a non-OS, it means you only have a single task context, let's call it the driver context. Am I right?
    • If you have only a driver context, it means you always wait on the semaphore CmdSyncObj when sending a command. With the regular implementation in a non-OS, this semaphore is signaled in the interrupt context (not spawned actually) and this in turn enables the driver context to proceed. In your case, you suggest waiting on this semaphore and releasing it in the same context. I'm not sure how this works.

    Shlomi

  • Hi Shlomi,

    First, to answer your questions:

    1) We are using non-OS flavor

    2) Yes, we have a single task context

    3) The reason I think it should work is while waiting on CmdSyncObj, we wait forever, right? So it shouldn't matter if the signal is signaled in interrupt context or polled context, right? So that's why I chose to add polling on the HOST_INTR pin in _SlNonOsMainLoopTask().

    What I discovered today is that indeed an Async event is being sent - SL_OPCODE_DEVICE_DEVICEASYNCDUMMY. The reason the driver locked up in this case can be seen by following the logic in _SlDrvMsgReadCmdCtx(). The async event is sent in the middle of the call to _SlDrvMsgRead(). When that happens in interrupt context, _SlDrvRxIrqHandler() will run, and at that point, g_pCB->IsCmdRespWaited will still be TRUE, and thus CmdSyncObj will be set. In the non-interrupt context, the call to sl_SyncObjClear() in _SlDrvMsgReadCmdCtx() occurs after g_pCB->IsCmdRespWaited is set to FALSE. This results in sl_SyncObjClear() polling the HOST_INTR pin, which is set, and _SlDrvRxIrqHandler() will now instead call sl_Spawn((_SlSpawnEntryFunc_t)_SlDrvMsgReadSpawnCtx, NULL, 0). The problem is that _SlDrvMsgReadSpawnCtx() tries to unlock g_pCB->GlobalLockObj, which is still locked, and this results in the driver being stuck.

    I found that if I modify _SlDrvMsgReadCmdCtx() to poll HOST_INTR after the call to _SlDrvMsgRead(), everything works fine. Obviously this fixes this one issue only. But I'm curious why the CC3100 doesn't send the SL_OPCODE_DEVICE_DEVICEASYNCDUMMY event if I wait 100ms between file reads. Are there other cases where the CC3100 will send async events if all I'm using is the file system API?

  • Hi,

    In the current host driver non-OS implementation, this scenario would not happen as the global lock would be unlocked at the end of _SlDrvMsgReadCmdCtx() since IsCmdRespWaited would become FALSE. Then, the spawned task would be able to run as the global lock is free.

    Regarding the DUMMY event, this is sent to indicate flow control information in its header. This flow control inform the host with free pools and when the device is ready to receive data. I do not have the exact procedure but it includes time window in which commands are received from host. If you change this window from host by simple delay, you end up with not receiving the event.

    Shlomi

  • Hi,

    Did the above post answer your query? please verify the answer.

    Shlomi

  • Hi,

    I am closing the thread, if issue still exist please open a new thread and add a link to this one for reference.

    Shlomi

  • I would also very much like to use the CC3100, polling the HOST_INTR pin.

    Ed Ferrari, did you manage to make it work? If so, would you please share what you did to make it work?

  • Hi Bart,

    Sure. What version of the host driver are you using? The implementation differs slightly between 1.0.0.10 and 1.0.1.6.

    -Ed
  • I just started using the CC3100 recently.

    I'm using SDK 1.2.0 with a new CC3100boost, so, I assume that will be 1.0.1.6.

    But, if you don't mind I would like to know what you did to make it work for both cases. I can only learn more (I hope) :-) .

    I tried polling in a 1ms timer isr. That worked more or less, but is far from ideal.

  • Hi Bart,

    I was mixing up SDK versions with NWP versions. I really meant SDK 1.1.0 versus 1.2.0. Our implementation for SDK 1.1.0 has a lot of mileage under its belt, so we're pretty confident it's good. The SDK 1.2.0 implementation has had limited testing, so it may have issues.

    Keep in mind that in our product, we're only using the CC3100's file system in our bootloader (non interrupt environment), so our implementation won't work if you're expecting asynchronous events from trying to connect to a WLAN for example.

    Good luck, and let me know if you have any questions.

    Here is what we did for SDK 1.1.0:

    driver.c:
    ---------
    Added the following after line 1214:
    
    #ifdef BOOTLOADER
                checkIncomingMsg(); //see if msg sent while reading
    #endif
    
    
    nonos.c
    -------
    Added the following after line 147:
    
        // bootloader will run without interrupts, so we need to check the CC3100_INT
        // pin here and spawn a task if asserted
    #ifdef BOOTLOADER
        if(RxIrqCnt == (g_pCB)->RxDoneCnt)
        {
            checkIncomingMsg();
        }
    #endif
    
    
    and the code for checkIncomingMsg() is as follows:
    
    #ifdef BOOTLOADER
    /*============================================================================*/
    void
    checkIncomingMsg( void )
    {
        if ( GPIO_INT_ACTIVE( CC3100_INT ) )
        {
            GPIO_INT_CLEAR( CC3100_INT );
            _SlDrvRxIrqHandler( NULL );
        }
    }
    #endif

    ------------------------------------------------------------------------------------------------------

    And here is what we did for SDK 1.2.0:

    driver.c:
    ---------
    Added the following after line 1320:
    
    #ifdef BOOTLOADER
                checkIncomingMsg(); //see if msg sent while reading
    #endif
    
    
    nonos.c
    -------
    Placed the following #ifndef around line 109:
    #ifndef BOOTLOADER
            if (FALSE == g_pCB->IsCmdRespWaited)
    #endif
    
    Added the following after line 169:
    
        // bootloader will run without interrupts, so we need to check the CC3100_INT
        // pin here and spawn a task if asserted
    #ifdef BOOTLOADER
        if(RxIrqCnt == (g_pCB)->RxDoneCnt)
        {
            checkIncomingMsg();
        }
    #endif
    
    
    and the code for checkIncomingMsg() is as follows:
    
    #ifdef BOOTLOADER
    /*============================================================================*/
    void
    checkIncomingMsg( void )
    {
        if ( GPIO_INT_ACTIVE( CC3100_INT ) )
        {
            GPIO_INT_CLEAR( CC3100_INT );
            _SlDrvRxIrqHandler( NULL );
        }
    }
    #endif

  • Thanks a lot for the inspiration Ed.
    It was a good starting point for me. I dug a little deeper into the code and made some more adjustments.
    Preliminary testing shows that I got at least wlan and socket communication working now, using a polling method.