I have an Adafruit cc3000 wi-fi shield that hangs frequently. The attached graph shows how many times "loop()" executed before it got hung up one day. Sometimes it makes 50 or so loops, sometimes 10, sometimes several hundred...(ignore the "weight" and "lb" - it's really counting loops). But it always eventually gets stuck, often at the code immediately following 4a and 8. Less often, the connection fails (at the if(client.connected) test).
Increasing the watchdog timer to 4 minutes (from the current 1 minute) doesn't help.
Is this normal behavior for a wi-fi connection? Can I tweak something to get more reliable behavior?
// Libraries
#include <Adafruit_CC3000.h>
#include <SPI.h>
#include <LiquidTWI2.h> // for LCD only
#include <Wire.h> // LCD only
#include <avr/wdt.h> // for watchdog timer
// Define CC3000 chip pins
#define ADAFRUIT_CC3000_IRQ 3
#define ADAFRUIT_CC3000_VBAT 5
#define ADAFRUIT_CC3000_CS 10
// Create CC3000 instance
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
SPI_CLOCK_DIV2); // you can change this clock speed
// WLAN parameters
#define WLAN_SSID "blahblahblah"
#define WLAN_PASS "more blah"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY WLAN_SEC_WPA2
// Xively parameters
#define WEBSITE "api.xively.com"
#define API_key "yet more blah"
#define feedID "and even more"
uint32_t ip = 0xD834E978; //xively ip in hex
int i=0;
int iMstrt; // for displaying available memory
unsigned long ulTstrt; // for timing loop
volatile int counter; // for watchdog timer
volatile int countmax = 8; // Timer expires after about 1 min
// if 8 sec interval is selected below
// 8 x 8 = 64 sec
String data;
// Connect via i2c, default address #0 (A0-A2 not jumpered)
LiquidTWI2 lcd(0);
void setup(void)
{
data.reserve(100); // data.length() = 90 (max, if three-digit weight)
// Initialize
Serial.begin(115200);
Serial.println(F("\nInit..."));
if (!cc3000.begin())
{
Serial.println(F("Fail begin()-Chk wires"));
while(1);
}
// set the LCD type
lcd.setMCPType(LTI_TYPE_MCP23008); // used with small I2C backpack
// set up the LCD's number of rows and columns:
lcd.begin(8, 2);
iMstrt = freeRam(); // memory at start
}
void loop(void)
{
//***************************************************************
/* print testing info */
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(i+=1); //number of loop
Serial.println();
Serial.println(i);
//***************************************************************
/* Get data, prepare JSON for Xively */
//int weight = analogRead(A0);
int weight = i; // print number of loops for testing purposes
int length = 0;
data = "";
data = data + "\n" + "{\"version\":\"1.0.0\",\"datastreams\" : [ {\"id\" : \"SouthPostWeight\",\"current_value\" : \"" + String(weight) + "\"}]}";
length = data.length();
lcd.setCursor(0, 1);
lcd.print(weight);
lcd.print(" ");
lcd.print(length);
lcd.setCursor(4,0);
lcd.print("send");
Serial.print(F("send... data length "));
Serial.println(length);
watchdogEnable();
ulTstrt=millis();
//***************************************************************
/* Connect to WiFi Access Point...AP */
// Hasn't hung on this in tests, but looks like it could hang.
// Only returns false if cc3000 reports it is not initialized.
// Takes approx 13 seconds...so can't use normal watchdog timer
Serial.print("*1* ");
cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY);
//***************************************************************
/* Wait for DHCP to complete */
// takes approx 100 ms
// 50% of hangs are here with watchdog at 8 seconds
// Adding the global 64 sec watchdog eliminated most hangs here
Serial.print("*2* ");
while (!cc3000.checkDHCP())
{
delay(200);
}
//***************************************************************
/* connect to XIVELY */
// Normally takes approx 75 ms
// the following code and the code after *4a* and *8* hang most often.
Serial.print("*3* ");
Adafruit_CC3000_Client client = cc3000.connectTCP(ip, 80);
//***************************************************************
/* Send data to XIVELY */
// Normally takes about 9 seconds, total
if (client.connected()) {
Serial.print("*4a* "); // often hangs after printing *4a*
client.println("PUT /v2/feeds/" + String(feedID) + ".json HTTP/1.0"); // approx 1.4 s
Serial.print("*4b* ");
client.println("Host: api.xively.com"); // approx 0.9 sec max
Serial.print("*5* ");
client.println("X-ApiKey: " + String(API_key)); // approx 2.3 sec max
Serial.print("*6* ");
client.println("Content-Length: " + String(length)); // approx 0.8 sec max
client.print("Connection: close"); // approx 0.7 sec max
client.println(); // approx 0.1 sec max
Serial.print("*7* ");
client.print(data); //occasional hangs here approx 3.8 sec max
client.println(); // approx 0.1 sec max
} else {
lcd.setCursor(4,0);
lcd.print("fail");
Serial.println(F("Conn faild"));
delay(10000);
i=i/2; // for testing only...divide by two to show connection failure in Xively graph
return; // go to beginning of loop()
}
//***************************************************************
/* Read response.*/
// Average time to execute = 500 ms
// Max time (other than hang) = 1200 ms
// Doing this read is apparently necessary
// (if commented out, data does not show on Xively).
// Often hangs here
Serial.print("*8* ");
while (client.connected()) {
while (client.available()) {
char c = client.read();
Serial.print(c);
}
}
//***************************************************************
/* disconnect from XIVELY 1 ms and AP 2 ms */
// has never hung on these two
Serial.print("*9* ");
client.close();
cc3000.disconnect();
wdt_disable();
Serial.print("done... ");
printTime();
//***************************************************************
lcd.setCursor(4,0);
lcd.print(" ");
lcd.setCursor(4,0);
lcd.print(iMstrt-freeRam()); // this has stayed constant at 141 throughout all tests
// Wait
//delay(600000UL); // ten minutes=600,000
delay(20000); // integer limit is about 32,000, unsigned int 65,535
}
void printTime()
{
Serial.print((millis()-ulTstrt)/1000);
Serial.println(" s");
}
int freeRam()
{
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
void watchdogEnable()
{
counter=0;
cli(); // disable interrupts
MCUSR = 0; // reset status register flags
// Put timer in interrupt-only mode:
WDTCSR |= 0b00011000; // Set WDCE (5th from left) and WDE (4th from left) to enter config mode,
// using bitwise OR assignment (leaves other bits unchanged).
WDTCSR = 0b01000000 | 0b100001; // set WDIE (interrupt enable...7th from left, on left side of bar)
// clr WDE (reset enable...4th from left)
// and set delay interval (right side of bar) to 8 seconds,
// using bitwise OR operator.
sei(); // re-enable interrupts
// delay interval patterns:
// 16 ms: 0b000000
// 500 ms: 0b000101
// 1 second: 0b000110
// 2 seconds: 0b000111
// 4 seconds: 0b100000
// 8 seconds: 0b100001
}
ISR(WDT_vect) // watchdog timer interrupt service routine
{
counter+=1;
if (counter < countmax)
{
wdt_reset(); // start timer again (in interrupt-only mode)
}
else // then change timer to reset-only mode with short (16 ms) fuse
{
MCUSR = 0; // reset flags
// Put timer in reset-only mode:
WDTCSR |= 0b00011000; // Enter config mode.
WDTCSR = 0b00001000 | 0b000000; // clr WDIE (interrupt enable...7th from left)
// set WDE (reset enable...4th from left), and set delay interval
// reset system in 16 ms...
// unless wdt_disable() in loop() is reached first
}
}