Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 21 of 21

Thread: CC3000 with adafruit library, non-blocking?

  1. #1
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894

    CC3000 with adafruit library, non-blocking?

    Hi all,

    I'm having some issues with the CC3000. When I send a http request and immediately after that use a different SPI device, the CC3000 interrupt that occurs later interferes with my other device drivers and my application locks up (this is how I interpret the errors I get).

    I can work around that by simply finishing all CC3000 operations before starting anything else, but that's not what I want. I'd like to send a request, do something else, and check the request result later.

    Is there a way to use the adafruit library in a non-blocking way or are there library alternatives?

    Regards

    Christoph

    Edit: Also, if there are any other modules comparable to the CC3000 (example code/library available, SPI or I2C interface) you recommend, I'll try those.
    Last edited by christoph; 07-05-2014 at 10:42 PM.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    I'm working on a permanent solution. It's not easy.

    http://forum.pjrc.com/threads/25582-...-program/page2

  3. #3
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894
    Wouldn't that require writing a new SPI part for the library? The adafruit library seems to use the SPI in an ISR, when it shouldn't. Making the SPI unavailable would not change a lot. Or am I totally misinterpreting your point?

    Regards

    Christoph

  4. #4
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    I've written several lengthy explanations about SPI transactions on the Arduino Developers Mailing List.

    At the risk of being terse, rather than duplicate that work, I'm going to refer you to that already-written material. It's very long read, with a number of not-so-well-informed comments, but also a lot of good input and testing from Matthijs and Cristian.

    https://groups.google.com/a/arduino....I/6deNjw3Y9m4J

    My general feeling is this issue has already been discussed far too much. A lot of very good work has already been done. Recently Cristian gave some guidance on what he'll accept into Arduino, so this message is more-or-less the final word.

    https://groups.google.com/a/arduino....I/Hm7UFtWxm2UJ

    Today I'm working on a fix for the pin 33 troubles, and also support for activating the chip lock bit. I still have a pretty good list of desired features for 1.20... many of which may get pushed out to 1.21. My intention is to work on the SPI transaction stuff after the pin 33 issue is fixed, since it really is important.

    I'm still participating on these forum discussions, but on the matter of SPI transactions, it's been discussed and planned very throughly. Cristian has outlined when Arduino will accept, so the best use of my time now is actually working on the code.

  5. #5
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894
    Paul, this was not meant to be about SPI transactions as such. Maybe my question was not phrased well enough to make that clear. I'll try to re-write it. Let's take this snippet from the WebClient example:

    Code:
    Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
    if (www.connected()) {
      www.fastrprint(F("GET "));
      www.fastrprint(WEBPAGE);
      www.fastrprint(F(" HTTP/1.1\r\n"));
      www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
      www.fastrprint(F("\r\n"));
      www.println();
    } else {
      Serial.println(F("Connection failed"));    
      return;
    }
    
    Serial.println(F("-------------------------------------"));
      
    /* Read data until either the connection is closed, or the idle timeout is reached. */ 
    unsigned long lastRead = millis();
    while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
      while (www.available()) {
        char c = www.read();
        Serial.print(c);
        lastRead = millis();
      }
    }
    www.close();
    The code sends a http request and waits for a response. That takes about one or two seconds. All SPI transactions are blocking and may stay so. I would like to do the following instead:

    Code:
    Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
    if (www.connected()) {
      www.fastrprint(F("GET "));
      www.fastrprint(WEBPAGE);
      www.fastrprint(F(" HTTP/1.1\r\n"));
      www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
      www.fastrprint(F("\r\n"));
      www.println();
    } else {
      Serial.println(F("Connection failed"));    
      return;
    }
    
    -----> Use the SPI for something else here <-----
      
    /* Read data until either the connection is closed, or the idle timeout is reached. */ 
    unsigned long lastRead = millis();
    while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
      while (www.available()) {
        char c = www.read();
        Serial.print(c);
        lastRead = millis();
      }
    }
    www.close();
    The problem is that the CC3000 driver uses the SPI in an ISR that would mess with any code that uses the SPI in between. My question was about alternative APIs that use the SPI as it is (blocking), but don't try to use the SPI at a random point in time when I don't have any control over what is happening. I hav found this in the meatime: https://code.google.com/p/cc3000-non-blocking-lib/ but I don't know and didn't find any information about how to use it. It seems to do just what I want: Move SPI transfers from the ISR into the main loop.

    Does anyone have any experience with that non-blocking driver?

    Regards

    Christoph

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    Quote Originally Posted by christoph View Post
    The problem is that the CC3000 driver uses the SPI in an ISR that would mess with any code that uses the SPI in between.
    This is exactly the problem SPI transactions are meant to solve. This, and differing SPI settings, which is also an issue with CC3000.

  7. #7
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894
    Differing SPI settings are ok, I found a workaround for those. Regarding the rest: I...I just don't get it. The bottom line seems to be that the current driver needs me to block for however long it wants, so I guess I need to adapt to that.

    Nonetheless, having a better API for the SPI is surely a huge benefit and effort, and I'm looking forward to that.

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    Christoph, if you're still watching this thread, I'm testing CC3000 together with other SPI devices.

    I see code fragments in reply #5, but not a complete program. I'm going to try to fill in the gaps...

    If you'll post a complete program that shows the problem you were seeing, I'll test with your code (rather than stuff I make up for the rest). That would give the best odds I'll truly solve the exact problem you encountered.

  9. #9
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    I'm building a test which will write a file to a SD card with random data. Then it'll run this example and repetitively read the file and compare against the known data, while it waits for the web server to respond.

    Hopefully that's a good test? If you had some other SPI device in mind to use while using the CC3000 in non-blocking mode, please let me know?

  10. #10
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894
    Hi Paul,

    thanks for helping. Your suggestion sounds just like what I'd like to do. One other device I have in mind is an OLED display (ssd1351), but that should not make a difference. johnnyfp is using a modified version of the Energia library which I'm planning to test, but not before the weekend as I'm currently on vacation.

    I'll also try to write a minimum working example when I'm back.

    Regards

    Christoph

  11. #11
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    I'm happy to report the SPI transactions are working great.

    I modified the CC3000 example to repetitively read a 3000 byte file from the SD card while waiting for the CC3000. Without SPI transactions, it crashes on Teensy 2.0 within just a few iterations. On Teensy 3.1, it and can't ever access the card, because CC3000 doesn't save/restore SPI settings for non-AVR chips. With SPI transactions, it works perfectly.

    Here's the code that waits for the CC3000 incoming data, while calling read_sd_card(). I'll attach the full code to this message.

    Code:
            /* Read data until either the connection is closed, or the idle timeout is reached. */
            unsigned long lastRead = millis();
            while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
    
                    // while waiting for the Wifi to return data, read the SD card
                    read_sd_card();
    
                    while (www.available()) {
                            char c = www.read();
                            Serial.print(c);
                            lastRead = millis();
                    }
            }
            www.close();
    At startup, 3000 bytes of random data are written to a file and kept in memory. The read_sd_card() function reads the file and checks 3000 bytes are the same as originally written. The full code is attached below. (you must edit to add your SSID and Wifi password if secure)

    Here are the libraries, patched for SPI transactions.

    https://github.com/PaulStoffregen/SPI
    https://github.com/PaulStoffregen/Adafruit_CC3000
    https://github.com/PaulStoffregen/SD

    Earlier in this thread, I probably didn't communicate the time scale of SPI transactions well. A SPI transaction is NOT the entire 1+ seconds needed for the CC3000 to fetch a web page. It's only a very brief time, while a library uses the SPI port. Usually each SPI transaction corresponds to a single assert of a chip select. Ethernet uses transactions as the socket level, so several small transfers are done per transaction, but the time is still very small.

    In this case, the SD library is doing transactions that involve single sector reads or writes, or small transfers to check the card status. The CC3000 interrupt is only masked for very short times, but long enough that it can't interfere with proper operation of the SD card, or (hopefully) any other SPI-based library that's using SPI.beginTransaction() and SPI.endTransaction().
    Attached Files Attached Files

  12. #12
    Senior Member Constantin's Avatar
    Join Date
    Nov 2012
    Location
    In the yard with a 17' Dia. Ferris Wheel
    Posts
    1,408
    Hi Paul,

    Just wanted to reiterate my appreciation for your work, both here as well as with the Arduiono collective!

  13. #13
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    Quote Originally Posted by PaulStoffregen View Post
    I'm happy to report the SPI transactions are working great.
    Outstanding work! The importance of this cannot be overstated!

  14. #14
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    Cristian Maglie just agreed on the Arduino Developers Mail List that it's time to send this as a pull request for Arduino (which I'll do tomorrow). I'm also going to put together a 1.20-rc2 Teensyduino installer.

    Here's a photo the hardware I used for the test in #11.

    Click image for larger version. 

Name:	cc3k_sd_test.jpg 
Views:	262 
Size:	104.0 KB 
ID:	2447

    I'm really glad these strange SPI problems are finally going to be solved, not just on Teensy, but eventually for all Arduino compatible boards. Nobody deserves to put so much work into a project and ultimately have it turn out flaky because of the platform.

  15. #15
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894
    Quote Originally Posted by PaulStoffregen View Post
    Nobody deserves to put so much work into a project and ultimately have it turn out flaky because of the platform.
    And that, Paul, makes PJRC awesome.

  16. #16
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    894
    Paul, there's a small error in your cc3000_sd.ino

    Lines 59 and 60 use hard-coded pin numbers, but the pins have been defined before. These defines should be used here, so
    Code:
    // lines 59...60:
    pinMode(4, INPUT_PULLUP);  // SD Card
    pinMode(10, INPUT_PULLUP); // CC3000
    should be
    Code:
    pinMode(SD_CHIP_SELECT, INPUT_PULLUP);  // SD Card
    pinMode(ADAFRUIT_CC3000_CS, INPUT_PULLUP); // CC3000
    instead.

    You probably didn't notice this as resetting a pin to input mode in setup() usually doesn't have any real effect when the hardware came from reset before.

    After correctly setting the pin numbers, the output of your sketch doesn't show any errors on my hardware, which also includes an adafruit ssd1351 (carrying the SD card) and other stuff. There are lots of "SD ok :-)" messages and a message block from the CC3000 in regular intervals.

    I'll now try (!) to port my existing project to 1.20 RC2 and see if interleaved display, SD and CC3000 works for me. Might take some time, though...

    Regards

    Christoph

  17. #17
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    22,293
    Opps, yeah, I just quickly added those lines without using the proper names.

  18. #18
    Hi folks,

    Just tried out a CC3000 with the Adafruit lib for Teensy last night. Mine has the 1.26 firmware Buildtest got me as far as trying to connect to my wifi network last night, but couldn't do it. Messed around with things- the second (stock, commented) below wouldn't work, the second came back with a connect, but checkConnected would always return 0 afterwards

    if(cc3000.connectSecure(WLAN_SSID, WLAN_PASS,3))
    // if (cc3000.connectToAP(WLAN_SSID, WLAN_PASS, 3,1))

    On a lark, tried it with an Arduino uno tonight and Adafruit's library. Everything works fine. Any ideas? Stuff I could try? Thanks for any and all. I will probably go back and double check my connections, but it was definitely talking to the cc3000 to have gotten that far.

  19. #19
    Junior Member
    Join Date
    Sep 2014
    Posts
    1
    Impressive work Paul.
    I just found this thread after 3 days of trying to figure out why my CC3000 Shield with SD card is not working properly. I'm working in a project where I have a server listening to clients and once a client connects needs to send a large file from the SD card. My setup uses an Arduino DUE, does your code works with the DUE you think ?

  20. #20
    Senior Member
    Join Date
    Jan 2015
    Location
    SF Bay Area
    Posts
    255
    I browsed through adafruit cc3000 library code.
    I see the library uses pin interrupt, yet the code blocks waiting for interrupt to complete. :0

  21. #21
    Quote Originally Posted by PaulStoffregen View Post
    hi Paul ,

    first of all thanks sooo much for your work , im having the SD.h corrupted file problem in a very critical project at my work and i wasn't able to understand why till i read your threads
    i use Ethernet 2 shield for both Ethernet and SD read write , also i user external interrupts a lot
    my application is an interrupt based production counter that saves the count to SD file and sends it to a server by Ethernet , i have some questions please

    1- i downloaded your SD library will it work with the ethernet 2 library with no problem or should be more adjustments to the ethernet 2 lib code
    2- will the external interrupt cause problems too or is it just the 2 spi devices
    3- does loosing electricity while writing a file causes a corrupt file too
    4- i just knew about Teensy is it 100% compatible with arduino code and libraries and does it support UTFT library

    thanks in advance ,

    thats my code
    Code:
    #include <Ethernet2.h>
    #include <EthernetClient.h>
    #include <SPI.h>
    #include <SD.h>
    #include <TimerOne.h>
    #include <avr/wdt.h>
    //************************************************************************************
    //************************************************************************************
    // GLOBAL VARIABLES
    const int chipSelect = 4;// SD
    
    File dataFile;//FILE ENTITY
    File dataFile2;//FILE ENTITY
    
    volatile unsigned long int total;//Counter accumelator
    char b, R, N, X, Y, Z, x, p; // k //status flag to stop count while stop , connection trials count ,
    //status send & reset send, reet debouncer , count debouncer , repeat send status
    int port=5045;
    byte mac[] = {0x90, 0xA2, 0xDA, 0x10, 0x76, 0x7C};
    byte ip[] = {10, 10, 10, 45}; // unit for machine 21 counting ip =41
    byte server[] = {10, 10, 10, 250}; // server ip
    EthernetClient client;
    //************************************************************************************
    //************************************************************************************
    void setup() {
      char w, c;
       wdt_disable();  
    
       p=0;
    
      pinMode (2, INPUT); // status
      pinMode (8, OUTPUT); // reset out
      pinMode (9, INPUT); // reset in
      pinMode (3, INPUT); // count
      pinMode(10, OUTPUT);//CS for SD
      pinMode (7, OUTPUT); //Simulator o/p
      
      //----------------------------------------------------------------
      c = 0;
      while (c < 20)
      { 
        if (SD.begin(chipSelect))
        {
          c = 120;
       }
        else
        {
          delay(5);
          c++;
        }
      }
      //-------------------------------------------------
      Ethernet.begin(mac, ip);
      c = 0;
      while (c < 20)
      {
        c++;
        client.connect(server, port);
        if (client.connected()) 
        {
          c = 120;
        }
        else
        {
        client.stop();
        delay(5);
        }
      }
         //-------------------------------------------------
      w = 0;
      dataFile2 = SD.open("total.txt");
      if (dataFile2)
      {
        w = 1;
        getit();
      }
      else {
        dataFile2 = SD.open("total1.txt");
      }
      if (dataFile2)
      {
        if (w == 0) {
          getit();
        }
      }
     
      //-------------------------------------------------
      Timer1.initialize(2000000L); // set a timer 2 seconds
      Timer1.attachInterrupt( Repeats ); // attach the service routine here
      Status1();
    }
    //************************************************************************************
    //************************************************************************************
    void loop() {
      char f, a;
       attachInterrupt (digitalPinToInterrupt (3), Counting, RISING);  // attach interrupt handler
    //----------------------------------------------------------------
      f = digitalRead(2);
      if (f != X)
      {
        Status1();
        X = f;
      }
    //----------------------------------------------------------------
    //----------------------------------------------------------------
      a = digitalRead(9);
      if (a != Z)
      {
        Z = a;
        if (digitalRead(9) == 1)
        {
          delay(5);
          if (digitalRead(9) == 1)
          {
            reset1();
          }
        }
      }
      //----------------------------------------------------------------
      if (R == 1)
      { // those are the functions which where in the Timer ISR R is a flag of time
        sendether();
        p++;
        if (p>=28){
        p=0;
        }
        writetotal();
        R = 0;
      }
    }
    //************************************************************************************
    //************************************************************************************
    void Counting()
    { 
      
      static unsigned long last_interrupt_time = 0;
     unsigned long interrupt_time = millis();
     // If interrupts come faster than 200ms, assume it's a bounce and ignore
     if (interrupt_time - last_interrupt_time > 150) 
     {
       if (digitalRead(2) == 1)
      {
        total++;
      }
     }
     last_interrupt_time = interrupt_time;
    }
      
    
    //************************************************************************************
    //************************************************************************************
    void reset1()
    {
      
      b = 2;
      digitalWrite(8 , HIGH);
      delay(1000);
      digitalWrite(8 , LOW);
      delay(500);
    
      sendether();
      total = 0;
      writetotal();
     
    }
    //************************************************************************************
    //************************************************************************************
    void Status1()
    {
      b = 1;
      if (digitalRead(2) == 1)
      {
        sendether();
      }
      else
      {
        sendether();
      }
    }
    //************************************************************************************
    //************************************************************************************
    void Repeats()
    {
      R = 1;
     // k++;
    }
    //************************************************************************************
    //************************************************************************************
    void sendether()
    {
      char c;
     c = 0;
      while (c < 5)
      {
        c++;
        client.connect(server, port);
        if (client.connected()) 
        {
          c = 10;
        }
        else
        {
        client.stop();
        
        }
      }
     
      // if coming from reset
      if (b == 2)
      {
        client.println(total);
        client.println(F("shift"));
        client.println(total);
        client.println(total);
        client.println(total);
        b = 0;
      }
      // if coming from repeat
      if (b == 0)
      {
        client.println(total);
        x++;
        if (x == 5)
        {
          if (digitalRead(2) == 1) {
            client.println(F("run"));
          }
          else if (digitalRead(2) == 0) {
            client.println(F("stop"));
          }
          x = 0;
        }
      }
      // if coming from status
      else if (b == 1)
      {
        if (digitalRead(2) == 1)
        { 
          client.println(F("run"));
          client.println(F("run"));
          b = 0;
        }
        else if (digitalRead(2) == 0)
        { 
          client.println(F("stop"));
          client.println(F("stop"));
          b = 0;
         }
      }
    }
    //************************************************************************************
    //************************************************************************************
    void writetotal()
    {
      char dataString2[25];
      sprintf(dataString2, "%u", total);
      SD.remove("total.txt");
      dataFile2 = SD.open("total.txt", FILE_WRITE);
      if (dataFile2)
      {
        dataFile2.println(dataString2);
        dataFile2.close();
      }
      SD.remove("total1.txt");
      dataFile2 = SD.open("total1.txt", FILE_WRITE);
      
      if (dataFile2)
      {
        dataFile2.println(dataString2);
        dataFile2.close();
      }
    }
    //************************************************************************************
    //************************************************************************************
    void getit()
    {
      char dataString1[25];
      char q = 0;
      while (dataFile2.available())
      {
        dataString1[q++] = dataFile2.read();
        dataString1[q] = '\0';
      }
       // close the file:
      dataFile2.close();
    }
    //************************************************************************************
    //************************************************************************************

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •