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.

CC3000 Driver & Missed Interrupt Problem

Hi all,

I've painstakingly traced a stall in the CC3000 driver code to a call to nvmem_read() which happens during wlan_smart_config_process(). This call attempts to read the AES key from NVMEM on the CC3000, and is split into two parts - SimpleLinkWaitEvent() immediately followed by SimpleLinkWaitData(). I've managed to figure out that in between these calls, there is a delay between SpiPauseSpi() and SpiResumeSpi() that is causing an interrupt to be missed, meaning that the driver waits forever for data (the second step of nvmem_read()).

Here is a logic trace showing the problem. Note that line 6 shows the state of interrupt processing - enabled is HIGH, paused/disabled is LOW.

As you can see, IRQ goes low while interrupt handling is disabled. It resumes shortly, but by that point it is too late.

My question is - am I implementing resume and pause correctly? I'm simply disabling and enabling interrupts on the IRQ pin. If this is correct, it seems like I've hit some kind of race condition or even a bug in the library.

Thanks!

Vishal 

  • I just realized that the odd thing about this is that IRQ goes low even though CS is disabled...what could that mean?

  • Just wanted to post an updated logic analyzer screenshot. The only change is in the IRQ Enabled? line, which should correctly display the interrupt state now. The window of time in which the interrupts are disabled is more obvious, but the real question is why the CC3000 interrupts at all when it isn't enabled.

  • The problem is the way I was pausing and resuming interrupts. Perhaps because I'm using the Arduino environment and not working as close to the metal as I would be with CCS or IAR, there is enough of a delay between pausing and resuming that I miss the IRQ low signal. What I did to avoid this is to swap out the regular interrupt handler with a dummy interrupt handler that simply sets a flag when an interrupt happens. Then, when interrupt handling is resumed, I swap them back and if the IRQ flag was set, pretend as if an interrupt just took place. This took care of things long enough for Smart Config to go through. 

    I still think it's a bug in the library if a race condition like this manifests due to a slight difference in timing, but I'm no expert.

  • I had the same problem with the LPC1837 processor. And this means unnecessary debug time. This should be publicly known in some kind of errata sheet. I solved it the same as you.

  • Hi Vishal,

    VIshal Talwar said:

     there is enough of a delay between pausing and resuming that I miss the IRQ low signal. 

    What do you mean by a delay between pausing and resuming?

    In this period (from pausing to resuming) there should not be any interrupts.

    I think the issue is that you didn't really disabled the interrupt, otherwise how could it be (according to your scope capture) that interrupt arrived after pausing the SPI? (while IRQ Enabled? was low)

    Yael

     

  • Hi Yael,

    Sorry for the long delay replying, but I was on vacation for a while and am getting warmed up again. What I mean is basically what you yourself described in this thread:

    http://e2e.ti.com/support/low_power_rf/f/851/p/260521/923417.aspx

    "If the IRQ is low but you didn't receive any ISR, you can ask for the IRQ state (maybe you missed the ISR between the CS assertion and the interupt enable)."

    I think what happened is interrupts were disabled when IRQ went low, and then when they were re-enabled I had already missed the IRQ pulse. Does this make any sense? It seems to be a case you guard against in some parts of the code.

    Thanks,

    Vishal

  • Also, I see what you are saying that an IRQ should not arrive between SPI pause and resume...but how would the CC3000 know this? Also, it looks like someone else said they had the same issue and solved it the same way just before your reply.

  • HI,

    CC3000 should not be aware if you are masking interrupts or not but until the host wont lower the CS and raise it again, CC3000 should not raise the interrupt.

    The race described could happen, but could be avoid with rechecking the interrupt status.

    Yael

     

  • Hi Yael,

    That's what I would have thought as well (about the CC3000 not raising IRQ when CS0 is HIGH) but I received information stating otherwise from the LSR forum:

    http://www.lsr.com/ProductsForum/tabid/164/forumid/8/postid/2980/scope/posts/Default.aspx#2980

    -Vishal

  • Hi Vishal,

    I don't see any conflicting information from LSR.

    LSR answer mentioned that once the IRQ is low, host should lower the CS (ENABLE).

    Host can’t directly control the IRQ line but can do that indirectly by controlling the CS line.

    If your host is masking the interrupts and an interrupt arrived, it will lower the CS only when the masking will be stop. 

    Why does your ENABLE line doesn't go low once the IRQ go low? If the answer is that you missed the interrupt, the solution could be checking this line again (IRQ line will stay low until you will response with the ENABLE line...).

    If the line is still low, low the ENABLE line and read the data.


    I think I understand you confusion from the information from LSR - this should relates to read or write operation:

    If host wants to write information, it will low the CS and wait for IRQ to be low.

    If CC3000 want to write, it will low IRQ and wait for CS to be low.

    Yael

  • Thanks for the detailed response, Yael. I think you are confirming a few things:

    1. That IRQ can fire at any time when the CC3000 wants to respond

    2. That because of 1), I could miss the interrupt if my timing is off

    3. That a missed interrupt isn't guarded against by the current version of the driver

    Where you placed the red circle is exactly where I miss the interrupt, as IRQ Enabled (line 6) isn't high at the time. So you are suggesting a way around missing the interrupt by checking again, but I think my solution of never really disabling interrupts but simply flagging that an interrupt happened and acting on it when IRQ is "enabled" (echoed by  earlier in the thread) works fine as well.

    For the record, the ported and patched version of the driver seems to be working without issue on the Teensy MCU so far.

    Thanks,

    Vishal

  • Good morning
    I have the same problem with porting codewarrior compiler on MKL25Z128VLK4, how can I fix.
    The problem is due to reading nvmem_get_mac_address (); that remains in hci_event_handler.
    I am attaching spi.c

    Please if anyone can tell me where can I put the changes in spi.c.

    Thank you very much

  • Hi Vishal,

    I seem to be facing the similar problem you are facing. When I send back to back packets to CC3000 I'm getting stuck in the infinite while loop.

    1. Did your Interrupt managing workaround solve the problem completely? Are you able to send/receive packets correctly?

    2. Did you make the SPI changes in latest SP and host driver versions as well?

    Appreciate any help..

    Vivek

  • Hi Vivek,

    Yes, the interrupt-deferring solution continues to work for me with the latest drivers. Is it not working for you on the latest version? I noticed they added a bit of code to purportedly deal with a missed interrupt, as I mentioned in this thread:

    http://e2e.ti.com/support/low_power_rf/f/851/p/293532/1024023.aspx#1024023

    However, I simply do not understand the order of operations in that section of code. In any case I have not modified SpiWrite in the newer version of the driver, only the interrupt handling bit.

    Vishal

  • Vishal Talwar said:
    pretend as if an interrupt just took place

    Hi Vishal,

    I'm still working on CC3000 module with no hope in sight. When you say you "Pretend as if an interrupt took place", what does that mean?

    If you see that the IRQ flag is set once the Interrupts are resumed, do you force the micro to take IRQ interrupt?

    Help is appreciated.

    Thanks,

    Vivek

  • Hi Vivek,

    Sorry to hear that. I meant that I manually call the interrupt handler when interrupts are resumed if an interrupt was detected while disabled. I found a different approach used in the Adafruit library:

    https://github.com/adafruit/Adafruit_CC3000_Library/blob/master/ccspi.cpp#L742

    Clearly, missed interrupts are a major source of problems with this library.

    -Vishal

  • Hi everyone
    I don't really know exactly what happen, as I am actually a newcomer.
    I had been struggling with the module: cannot recv nor recvfrom at all, either with TCP nor UDP.

    I had been monitoring my IRQ with an LED (Because apparently it's okay to do so)

    Having the problem, I modified the SPI.cpp (don't know the exact name)
    as such:

    void SpiResumeSpi(void) {
    SPIInterruptsEnabled = 1;
    if(Read_CC3000_IRQ_Pin()==0)
    {
    CC3000InterruptHandler();
    }
    }

    It sort of works. At least I can now do a read from TCP.

    I haven't tested much of it.

    And I'm sorry if this is a thread resurrection, remembering the date of last post. I'm just excited.

    I hope someone can confirm this as well.

    Thanks.

  • I've also had the problem of not recv not working. The only fix I've found so far is to decrease the spi clock rate. With a clock greater than about 1 MHz the problem occurs.