Go Down

Topic: freeRam() causes freeze (Read 3289 times) previous topic - next topic

Thomas499

I started a similar thread in Networking but I just figured out this has nothing to do with the network side of my code, rather than calling on freeRam() in conjunction with the network code.

using the example WiFi Web Server LED Blink I want someone to add this little code to it, and see if the free ram doesn't cause the arduino to crash in 7 minutes after the server code is called.

up top above setup add
Quote
unsigned long previousMillis=0;
int interval=30000;
unsigned long PrintCount=0;
unsigned long LoopCount=0;
next add this to loop()
Quote
void loop()
{
  ListenForController();
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval) // print this every 2 seconds
  { previousMillis = currentMillis;   
    Serial.print(PrintCount);
    Serial.print(F("   "));
    Serial.print(LoopCount);
    Serial.print(F("   "));
    Serial.print(millis());
    Serial.print(F("   "));
    Serial.print(freeRam());
    Serial.print(F("   "));
    Serial.println(F("slave arduino // freezes"));
    PrintCount++;
  }
  LoopCount++;
}

void ListenForController()
{
then at the bottom add this

Quote
int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval); 
}
The results are if you never connect to the internet page, it will never freeze. However, if you connect to the internet page (if you only connect once) then it will freeze in 7 minutes after the connection due to some kind of cross code contamination witchery.


Thomas499

Heres the full code, with changes already made.

Code: [Select]
/*
  WiFi Web Server LED Blink

 A simple web server that lets you blink an LED via the web.
 This sketch will print the IP address of your WiFi Shield (once connected)
 to the Serial monitor. From there, you can open that address in a web browser
 to turn on and off the LED on pin 9.

 If the IP address of your shield is yourAddress:
 http://yourAddress/H turns the LED on
 http://yourAddress/L turns it off

 This example is written for a network using WPA encryption. For
 WEP or WPA, change the Wifi.begin() call accordingly.

 Circuit:
 * WiFi shield attached
 * LED attached to pin 9

 created 25 Nov 2012
 by Tom Igoe
 */
#include <SPI.h>
#include <WiFi.h>

char ssid[] = "";      //  your network SSID (name)
char pass[] = "";   // your network password
int keyIndex = 0;                 // your network key Index number (needed only for WEP)
unsigned long previousMillis=0;
int interval=30000;
unsigned long PrintCount=0;
unsigned long LoopCount=0;
int status = WL_IDLE_STATUS;
WiFiServer server(80);

void setup() {
  Serial.begin(9600);      // initialize serial communication
  pinMode(9, OUTPUT);      // set the LED pin mode

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    while (true);       // don't continue
  }

  String fv = WiFi.firmwareVersion();
  if ( fv != "1.1.0" )
    Serial.println("Please upgrade the firmware");

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to Network named: ");
    Serial.println(ssid);                   // print the network name (SSID);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection:
    delay(10000);
  }
  server.begin();                           // start the web server on port 80
  printWifiStatus();                        // you're connected now, so print out the status
}


void loop()
{
  ListenForController();
  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis >= interval) // print this every 2 seconds
  { previousMillis = currentMillis;   
    Serial.print(PrintCount);
    Serial.print(F("   "));
    Serial.print(LoopCount);
    Serial.print(F("   "));
    Serial.print(millis());
    Serial.print(F("   "));
    Serial.print(freeRam());
    Serial.print(F("   "));
    Serial.println(F("slave arduino // freezes"));
    PrintCount++;
  }
  LoopCount++;
}

void ListenForController()
{
  WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("new client");           // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println();

            // the content of the HTTP response follows the header:
            client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on<br>");
            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off<br>");

            // The HTTP response ends with another blank line:
            client.println();
            // break out of the while loop:
            break;
          }
          else {      // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        }
        else if (c != '\r') {    // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(9, HIGH);               // GET /H turns the LED on
        }
        if (currentLine.endsWith("GET /L")) {
          digitalWrite(9, LOW);                // GET /L turns the LED off
        }
      }
    }
    // close the connection:
    client.stop();
    Serial.println("client disonnected");
  }
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
  // print where to go in a browser:
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}
  int freeRam() {
  extern int __heap_start,*__brkval;
  int v;
  return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int) __brkval); 
}

PaulS

Code: [Select]
    Serial.println("WiFi shield not present");
    Serial.println("Please upgrade the firmware");
    Serial.print("Attempting to connect to Network named: ");

A waste of perfectly serviceable SRAM.

If you are concerned about running out of SRAM, and you must be or you wouldn't be using freeRam(), quit pissing it away.

Code: [Select]
    String currentLine = "";                // make a String to hold incoming data from the client
That whooshing noise you hear is your memory being trashed.
The art of getting good answers lies in asking good questions.

Thomas499

Quote
A waste of perfectly serviceable SRAM.
In my orignal experiment I used the F macro as much as possible. However, once I simplifed the problem to calling on freeRam() in conjuction of using server code, I wanted to simplify the problem and use the experiment that came pre-loaded in the library for all newbs to learn from. I made minimal changes to the example, to show that it does freeze if you call on FreeRam.

This is the serial printout. see how after 6 minutes once server code is called, the program completely freezes.   
Code: [Select]
To see this page in action, open a browser to http://192.168.0.157
new client
GET /H HTTP/1.1
Host: 192.168.0.157
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
DNT: 1
Referer: http://192.168.0.157/
Connection: keep-alive

client disonnected
0   23866   30000   1211   slave arduino // freezes
1   98416   60000   1211   slave arduino // freezes
2   172939   90000   1211   slave arduino // freezes
3   247452   120000   1211   slave arduino // freezes
4   322003   150000   1211   slave arduino // freezes
5   396545   180000   1211   slave arduino // freezes
6   471072   210000   1211   slave arduino // freezes
7   545602   240000   1211   slave arduino // freezes
8   620094   270000   1211   slave arduino // freezes
9   694595   300000   1211   slave arduino // freezes
In the debugging efforts, i used two separate arduino unos, and one mega, and used the 1.0.6 and 1.5.8 arduino IDE. No matter what i did, if froze every time once I ran the server code by using the web site it gave me. I can't find any logical reason to why this may be happening. 

Delta_G

In your ListenForController method you are using the String class and the + operator to add characters to it.  This has the effect of causing the String to re-allocate for it's backing char array every time you get a new character.  That can cause memory fragmentation and cause you to run out of SRAM fast and has been known for some time to freeze Arduino programs.

The String class is great on PCs with lots of RAM.  On micros it works OK in small programs, but stuff like this it is notorious for locking up. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Thomas499

Quote
That can cause memory fragmentation and cause you to run out of SRAM fast and has been known for some time to freeze Arduino programs.
Two things to consider though, It would have to call on the same ListenForController() method listed on the example for the fragmentation to build up to the point it could crash the arduino though. If it did call on ListenForController() it would print "new client" again in the serial monitor. It only calls it once, though, so what else could cause the fragmentation?

The second is, how else can you effectively use a server based controller code without using the (if strings ends with GET/"something")
Quote
// Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          digitalWrite(9, HIGH);               // GET /H turns the LED on
        }

Delta_G

It only needs to call it once to crash.  It's in a while(client.connected()) loop.  So as long as the client is connected it keeps getting characters and adding them to that String, further fragmenting memory each time. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

PaulS

Quote
The second is, how else can you effectively use a server based controller code without using the (if strings ends with GET/"something")
Each time a client makes a request, it includes carriage returns and line feeds. When a set arrives, check the collected data. If it STARTS with "GET ", the stored data is the complete GET request.

Unless you plan on hosting a huge amount of data, like Ebay, the GET requests that a client makes should be relatively short. Allocate a char array of a reasonable size, and store the data in the array, adding a NULL terminator after every character addition.

https://forum.arduino.cc/index.php?topic=288234.0
Robin2's tutorial refers to serial data, but the process of collecting client data is EXACTLY the same.
The art of getting good answers lies in asking good questions.

Thomas499

but it printed "client disonnected" in the serial monitor. that means for the client to connect again it would have to go back through and that would print "new client" again. And if the client were still connected, it wouldn't be able to print the information it does in the main loop that happens every 30 seconds until the crash happens correct?

I still need the server side abilities, if strings are a bad idea, how else can I control the arduino using it as a server?

I even tried to limit the amount of possible fragmentation  by doing this
Quote
else if (c != '\r')
{   
   if (currentLine.length()<80) 
  { 
     currentLine += c;      // add it to the end of the currentLine
  }
}
even that didn't work. if there is 1211 of freeRam available as the serial monitor says, I don't see how the string (max size of 80) can be the reason the program crashes. Wouldn't it just write over the previous space it occupied?

Delta_G

#9
Nov 03, 2015, 08:57 pm Last Edit: Nov 03, 2015, 08:58 pm by Delta_G
So what if the client was disconnected when it froze?

The scenario looks like this:

client connects, memory gets all fragmented so that the heap starts getting close to the stack, but they don't crash into one another just yet.  Client disconnects and that function returns, but now the memory is all messed up and you don't have much room for anything else on the stack.  Some other function gets called and pushes its stuff onto the stack and the stack crashes into the heap and the program freezes. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Thomas499

#10
Nov 03, 2015, 09:08 pm Last Edit: Nov 03, 2015, 09:11 pm by Thomas499
Quote
Some other function gets called and pushes its stuff onto the stack and the stack crashes into the heap and the program freezes. 
but it runs over 600,000 more cycles after the client disconnects before it freezes. If you look at the code, which i simplified greatly for debugging, there is nothing in there that should cause any sort of unusual SRAM consumption, that isn't called every loop is there? Therefor something else is fragmenting the program correct? what else in the code could cause that sort of witchery?

Lets say i used Robins char example, can you do (if char ends with) like you can with strings?

========edit======
the mega has a lot more scram than the uno correct? Therefor, shouldn't it take the mega twice as long to crash? for some reason it doesn't.

Delta_G

#11
Nov 03, 2015, 09:14 pm Last Edit: Nov 03, 2015, 09:14 pm by Delta_G
Code: [Select]

char ssid[] = "";      //  your network SSID (name)
char pass[] = "";   // your network password


Just to be sure, you took your ssid and password out before you posted and these really have something in them in your program right?

You're not trying to add to those arrays later in code are you?
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Delta_G

Lets say i used Robins char example, can you do (if char ends with) like you can with strings?

There is no wichery in computer code.  They do exactly as they're told.

Since String is just a class that's hiding a char array from you, you can rest assured that there is nothing you can do with String that they aren't doing behind the scenes with a char array.

To see if a char array ends with a particular letter, use strlen to get the length of the string and check the last letter is equal to something.
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Thomas499

#13
Nov 03, 2015, 09:32 pm Last Edit: Nov 03, 2015, 09:37 pm by Thomas499
Quote
Just to be sure, you took your ssid and password out before you posted and these really have something in them in your program right?
correct, i didn't want to post my network password for the world to see. i don't know what information you have to have to bypass a routers firewall, but I like to play it safe.

By the way.... now that I think about it, if you give a person the numbers 1-100 and tell them to figure out how many times they can make 100 the answer is 49, 1+99, 2+98, ect. then you only have one 50 left over.


The point that is bugging me greatly is that even if I include
Quote
else if (c != '\r')
{   
   if (currentLine.length()<80)
  {
     currentLine += c;      // add it to the end of the currentLine
  }
}
which makes the max string length 80, and we use our logic that says fragmentation can only happen 80 times at most, assuming the first string is 1char, then something is put on top of that, then the string is erased, then a second string is 2 chars something is put on top of that, then the string is erased, and it keeps happening, then most fragmentation that can happen is 80*40 which is 320, but the freeRam says I have 1211 freeRam to work with.... What else could be causing the fragmentation? It can't be the string in this case by itself because of the 80 cap.... correct?

Quote
Since String is just a class that's hiding a char array from you, you can rest assured that there is nothing you can do with String that they aren't doing behind the scenes with a char array.

To see if a char array ends with a particular letter, use strlen to get the length of the string and check the last letter is equal to something.
yes, but lets say the ends with is 3 letters, which you really need, otherwise that information it pulls from the
Quote
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
is going to rock your world as it could use pretty much any letter in that info, the only way to safely code it to work it to have something that is 3 or more chars, in the server case, it uses GET/ as the safety. can you easily do that with cars without writing code that checks one at a time and if that char is match it checks the next char?

Delta_G

If you want the last three letters, use strlen to figure out how long the string is and point a char pointer at the third to last character and compare with strcmp.

There really is absolutely nothing that you can do with String that you can't do with char arrays.  You have to know that's true because the String class is, under the hood, using char arrays and standard c-string functions. 
|| | ||| | || | ||  ~Woodstock

Please do not PM with technical questions or comments.  Keep Arduino stuff out on the boards where it belongs.

Go Up