6
\$\begingroup\$

I'm using the WiFi shield on an Arduino Uno but I do not think the shield is fully disconnecting. I have a loop that checks a sensor for input. If the sensor hits the threshold, it connects with te WiFi shield to download some data, sleeps for a few seconds, then enters the loop again.

The function that I have to connect to the network, in it's simplest form, performs a WiFi.begin(), client.connect(), send message, client.stop() and WiFi.disconnect().

However, as I enter the main loop (after what I believe to be disconnecting form the network) the LINK light on the shield remains on. Furthermore if I loop through the loop after quite some time the Uno eventually halts. This is suggestive of a memory leak.

With the green light on am I REALLY disconnected from the network despite me running client.stop() and WiFi.disconnect()? Has anyone else seen memory leak issues with the WiFi Shield?

I am also using the SD card and I've heard that there used to be memory leaks with that, but if I am not using strings to interface with the SD card I should be good, right? I am referring to this link about the SD card memory leak: https://stackoverflow.com/questions/11690647/arduino-memory-leaks-sd-card-strings I am executing a close() each time I reference the SD card...

EDIT: Attaching code.... (I believe this was the last working version. I've since removed the WiFi portions as I could never make it work, but you should get the gist of what I was trying to do....

#include <SD.h>
#include <WiFi.h>
#include <Time.h>

//#include <MemoryFree.h>

/* This sample code demonstrates the normal use of a TinyGPS object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
*/
//system wide params
boolean DEBUG = true;        // flag to print out data or not
unsigned long timeBuf = 0;   // time marker for motion, number is in milliseconds that have passed sine system boot
char GPSString[100];
boolean weMoved = false;     // boolean to indicate that we moved.  We may or may not gather data depending on that...
boolean timeLapse = false;   // boolean to inicate that we sat in one common place for an extended period of time.





void setup()
{
int total;
int average;

      // this is the pin the GPS unit is plugged into.
      // Need to set it up for voltage output
      pinMode(8, OUTPUT);
      // but we have it turned off to start
      digitalWrite(8, LOW);



  //set accelerometer pins as inut pins
  pinMode(A0, INPUT);
  pinMode(A1, INPUT);
  pinMode(A2, INPUT);
  pinMode(A3, INPUT);

  Serial.begin(57600);

  initializeSD();


}

void loop()
{
    // Check if we MOVE or time lapses and we need another data query.  
    {
    Serial.println("monitoring");
    int xreadings[8];
    int yreadings[8];
    int zreadings[8];
    initReadings(xreadings, yreadings, zreadings);

    int index = 0;
    while(1) {

      // turn on GPS unit if we sit for a while a minute before data gathering
      if((millis() - timeBuf > 299900)) digitalWrite(8, HIGH);

       // break if we have elapsed the time
       if((millis() - timeBuf) > 300000) 
       {
         timeLapse = true;
         break;
       }

       // time ok, so get new readings and check for movement threshold.  Break if we move
       if(index >= 8) index = 0;       
       xreadings[index] = analogRead(1);
       yreadings[index] = analogRead(2);
       zreadings[index] = analogRead(3);

       if(moved(xreadings, yreadings, zreadings))
       {
         digitalWrite(8, HIGH);
         weMoved = true;
         break; 
       }
    }
  }

     // get WiFi Positioning....
     checkWiFiPosition();

     delay(6000);

     // get GPS string and then send off to location server
     processGPS();
     sendGPS();
     delay(5000);


   {
     float temperature = getLocalTemp();
     Serial.print("Temp is ");
     Serial.println(temperature);
   }

    delay(1000);


    writeToSD();

    // now turn off GPS unit as we are about to go back into our loop
    digitalWrite(8, LOW);

    // and update timeLapse to be the current time
    timeBuf = millis();

}

// function to load up accelerometer array
void initReadings(int* xr, int* yr, int* zr){
   for (int thisReading = 0; thisReading < 8; thisReading++)
   {
     xr[thisReading] = analogRead(1);   
     delay(1);
     yr[thisReading] = analogRead(2);
     delay(1);
     zr[thisReading] = analogRead(3);    
   } 
}


// function to check if the accelerometer has detected movement
boolean moved(int* xr, int* yr, int* zr){
  int delta = 0;

  for (int i = 0; i < 7; i++)
  {
     // add x deltas
     if (xr[i] >= xr[i+1]) delta = delta + (xr[i] - xr[i+1]);
     else delta = delta + (xr[i+1] - xr[i]);

     // add y deltas
     if (yr[i] >= yr[i+1]) delta = delta + (yr[i] - yr[i+1]);
     else delta = delta + (yr[i+1] - yr[i]);

     // add z deltas
     if (zr[i] >= zr[i+1]) delta = delta + (zr[i] - zr[i+1]);
     else delta = delta + (zr[i+1] - zr[i]);

  }  
     if (delta > 100) return true;
     else return false;
}


float getLocalTemp(){

 int reading = analogRead(A0);
 return (reading - 500) / 10;

}


// function that write the GPS, baraometer and other data information to the SD card
static void writeToSD()
{

  String logEntry;
  logEntry += GPSString;

  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(logEntry);
    dataFile.close();
    Serial.println("Closed");
    // print to the serial port too:
  }  
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }   

}


boolean processGPS()
{
     char buf[100];
     int iter = 0;
     int d = 0;
     char thisChar; 
     unsigned long startTime = millis();

     Serial.println("GPS");
     while((millis() - startTime) < 2000){
     if (Serial.available()) {
       #if ARDUINO >= 100 //For Arduino v1.0+
       {
         thisChar = Serial.read();
         if(thisChar == '$') iter = 0;
         buf[iter] = thisChar;
         buf[iter+1] = '\0';
         iter++;
       }  
       #else //For Arduino v0023 or earlier
         thisChar = Serial.read();
       #endif
     }
       if(thisChar == '*'){

        if(buf[1] == 'G' && buf[2] == 'P' && buf[3] == 'G' && buf[4] == 'G' && buf[5] == 'A'){
           int commaCount = 0;

           // cycle through all characters contained in the string, noting commas
             for(int i = 0; i < iter; i++){

                if(buf[i] == ','){
                 commaCount++; 
              }
           } // for loop      
         // Only return true if we reach the 9th comma on the GPGGA line.  This indicates we
         //    gathered all necessary data fields from the GPGGA line we need: fields 2 - 8
         if(commaCount >= 9){     
             for(int i = 0; i < iter; i++)
             {
                GPSString[i] = buf[i];
             }    
             GPSString[iter] = '\0';
             return true;
         }
         iter = 0;
       } // If we found GPGGA in the string      
       else{
           iter = 0;
       }
       d=0;
     }
   }   
     return false;
}





//###################################################################################
void sendGPS(){
  int status = WL_IDLE_STATUS; // the Wifi radio's status

  WiFiClient client;  

  char* ssids[]={"linksys"};
  char* passwds[]={"xxxx"};
   for (int i = 0; i < 1; i++){
     Serial.print("Attempting to connect to: ");
     Serial.print(ssids[i]);
     status = WiFi.begin(ssids[i],passwds[i]);
     if ( status != WL_CONNECTED) { 
      WiFi.disconnect();
      Serial.println("No connection");
      continue;
    } else {

      break;
    }
  }

  byte server[] = { 1,2,3,4 }; // Test server
  if (client.connect(server, 8080)) {
  Serial.println("Connected to Lo ");
  byte wifimac[6];                    
  WiFi.macAddress(wifimac);
  char c1[17]="";
  byte b1;  
  for(int y=5, x=0; y>=0, x<=16; y--, ++x) {
       b1=((byte)(wifimac[y]>>4));
       c1[x]=(char)(b1>9 ? b1+0x37 : b1+0x30);
       b1=((byte)(wifimac[y]&0xF));
       c1[++x]=(char)(b1>9 ? b1+0x37 : b1+0x30);
       if(x<16) {
         c1[++x]=':';
       }
  }
  String wifim = "";
  for(int z=0; z<17;z++)
  {
    wifim += c1[z];
  } 

  client.println("POST /MACServer/LocateMe?id="+wifim+"&latlong="+GPSString);

  }
  Serial.println("disconnected");
  client.stop(); 
  WiFi.disconnect();
}


void checkWiFiPosition(){
  int status = WL_IDLE_STATUS; // the Wifi radio's status

  WiFiClient client; 

  char* ssids[]={"linksys"};
  char* passwds[]={"xxxxxx"};
   for (int i = 0; i < 1; i++){
     Serial.print("Attempting to connect to: ");
     Serial.print(ssids[i]);
     status = WiFi.begin(ssids[i],passwds[i]);
     if ( status != WL_CONNECTED) { 
      WiFi.disconnect();
      Serial.println("No connection");
      continue;
    } else {
      break;
    }
  }

  byte server[] = { 1,2,3,4 }; // Test server
  if (client.connect(server, 8080)) {
  Serial.println("Connected to Lo ");
  byte wifimac[6];                    
  WiFi.macAddress(wifimac);
  char c1[17]="";
  byte b1;  
  for(int y=5, x=0; y>=0, x<=16; y--, ++x) {
       b1=((byte)(wifimac[y]>>4));
       c1[x]=(char)(b1>9 ? b1+0x37 : b1+0x30);
       b1=((byte)(wifimac[y]&0xF));
       c1[++x]=(char)(b1>9 ? b1+0x37 : b1+0x30);
       if(x<16) {
         c1[++x]=':';
       }
  }
  String wifim = "";
  for(int z=0; z<17;z++)
  {
    wifim += c1[z];
    //Serial.print(c1[z]);
  } 


  //Serial.println("WIFI shield MAC " + wifim);
  //Serial.print("RSSI: ");
  //Serial.println(WiFi.RSSI());

  byte bssid[6];
  WiFi.BSSID(bssid);
  char c[17]="";
  byte b;
  for(int y=5, x=0; y>=0, x<=16; y--, ++x) {
       b=((byte)(bssid[y]>>4));
       c[x]=(char)(b>9 ? b+0x37 : b+0x30);
       b=((byte)(bssid[y]&0xF));
       c[++x]=(char)(b>9 ? b+0x37 : b+0x30);
       if(x<16) {
         c[++x]=':';
       }
  }
  String mac = ""; 
   for(int z=0; z<17;z++)
  {
    mac += c[z];
    Serial.print(c[z]);
  }

  client.println("POST /MACServer/LocateMe?id="+wifim+"&m=" + mac);
  boolean startRead=false;


  Serial.println("Rd");
  while (client.connected()) {

      char c = client.read();

      if(c=='<')
        startRead=true;

      if(startRead==true)
          Serial.print(c);
      if(c=='>') startRead=false;
    }


  client.stop(); 
  WiFi.disconnect();
  }
  delay(1000);  

}



//function that initializes the SD card
void initializeSD()
{
  analogWrite(8, 170);
  delay(5000);
  analogWrite(8, 0);
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  //pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(4)) {
    // don't do anything more:
    return;
  }
  if(DEBUG) {Serial.println("card initialized.");}
}
\$\endgroup\$
9
  • 2
    \$\begingroup\$ I don't really see how there could be memory leaks, as there is no malloc() on the AVR (or at least there shouldn't be). Everything should be statically allocated. \$\endgroup\$ Commented Dec 7, 2012 at 4:30
  • 1
    \$\begingroup\$ @FakeName malloc() has been implemented on the Arduino in a few different ways. Some libraries for peripherals / shields implement their own private version as well - though that should be considered privateLocalAlloc() or something. \$\endgroup\$ Commented Dec 7, 2012 at 5:18
  • \$\begingroup\$ Ok, so I agree this might not be a memory leak, but shouldn't the light go off!? \$\endgroup\$
    – ngramsky
    Commented Dec 7, 2012 at 5:20
  • 2
    \$\begingroup\$ @AnindoGhosh - malloc() with 2 KB SRAM? That's a horrible idea. \$\endgroup\$ Commented Dec 7, 2012 at 5:44
  • \$\begingroup\$ @FakeName I know, right? \$\endgroup\$ Commented Dec 7, 2012 at 6:09

3 Answers 3

6
+25
\$\begingroup\$

You can use analog switches like CD4066 or MOSFET in series to power the shield. This can power off the shield completely. If using analog switch, make sure to check the current handling capability of the switch.

Hope this helps.

\$\endgroup\$
2
  • \$\begingroup\$ The way shields work I am not sure how you could put a mossfet in the path of the shield. \$\endgroup\$
    – Kortuk
    Commented Dec 17, 2012 at 19:48
  • \$\begingroup\$ @Kortuk By inserting a MOSFET on the shield or base board. It would need custom work as per custom requirements. \$\endgroup\$ Commented Dec 19, 2012 at 6:22
3
\$\begingroup\$

First, why are you trying to ensure that the WiFi sheild is disconnected? Are you concerned about quiescent power, or are you simply trying to resolve the issue you describe as a possible memory leak.

Second, while it's probably not the issue - your writeToSD() method doesn't follow the advice in the SO question you referenced - you need to have dataFile.close() at the very end of your function, regardless of whether you are able to successfully open a file descriptor.

Third, I don't see the support framework for accessing the GPS in your source. I don't know if it's root cause, but it certainly jumps out as something that's unlikely to lead to reliable code. Specifically:

  • No pin obviously declared as an input pin for the GPS (I see Pin 8 referenced for output, but it appears to be more of a power control pin than serial output).
  • No header file: #include "TinyGPS.h"

Does the GPS code work?

\$\endgroup\$
1
  • \$\begingroup\$ I wanted the WiFi shield to disconnect as I will be moving in and out of many WiFi access points. This would be running on a campus where I can connect the shield with many different access points. Thus when I am away I would want to be disconnected as I will have to re-connect at a later time, possibly to another AP. Hmmm, thought the SD code was robust, I'll revist that. RE the GPS - Yes it works and yes I am not using any support libraries. As the Arduino only has 2K SRAM Icannot load TinyGPS.h. Connecting the GPS unit to the serial allows me to collect data as text with no issue. \$\endgroup\$
    – ngramsky
    Commented Dec 17, 2012 at 14:41
2
\$\begingroup\$

Be careful turning off power (using a transistor) while there are still voltages on other (signal) pins. Many chips don't like having voltages on their pins without power being supplied, therefore set pinMode for related pins to INPUT. Your library may get confused though.

It is better to figure out if the chips have an enable pin. You'll have to check the datasheets for that.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.