Clearing and Optimizing the SRAM

I am having SRAM issues. I have code that crashes over time. At first, it would randomly crash after 6-10 hours. I realize the SRAM is used up. How can this be? SRAM stands for static random access memory. Well if its static, then how is it changing and filling up with respect to time... this will be considered dynamic then? Anyways, I made my strings smaller in size, used the F macro and included the "avr/pgmspace.h" in my list of libraries .Why does it fill up over time? It did improve the crash time to about 24 hours instead. How does a program run and clear a stack out of the SRAM and send it elsewhere? And if I transfer it to my flash or eeprom then wont that fill up over time eventually as well making the program crash? Thanks.

Well if its static, then how is it changing and filling up with respect to time

It's static only in the sense that the SIZE is static.

Why does it fill up over time?

Who knows? Only YOU can see your code.

How does a program run and clear a stack out of the SRAM and send it elsewhere?

The stack is cleared when a called function ends. You can't "clear a stack out of SRAM and send it elsewhere" anywhere except in your dreams.

And if I transfer it to my flash or eeprom then wont that fill up over time eventually as well making the program crash?

Since you can't, no.

SRAM contains global variables, the stack and heap-allocated objects. You cannot grow the
first of these, but the stack and the heap can grow - so your code must be doing so.

PaulS, In one of your posts in the thread clearing SRAM stack? you said

Eventually, you run out of stack space, because nothing ever returns and pops anything off the stack.

How do you do this? What function or command, or code does this? I feel my SendData is what's causing the issue since I have so much stuff going on there. What do I need to do in that function to "pop something off the stack"?

by the way, where is the auto format? I used the # command... is that it? My apologies for the atrocious indentation. I am used to straight ladders for my logic.

#include "Wire.h"
#include "DS1307RTC.h"
#include "DHT.h"
#include "PID_v1.h"
#include "SPI.h"
#include "Time.h"
#include "TimeAlarms.h"
#include "WiFi.h"
//#include "avr/wdt.h"
#include "WString.h"
#include "avr/pgmspace.h"

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
#define SensorPin 2      
#define Offset 0            
#define DHTPIN 2
#define DHTTYPE DHT11
#define RELAY_ON 1
#define RELAY_OFF 0
#define Relay1  9  
#define Relay2  8
#define Relay3  6
#define Relay4  5
#define Relay5  4  
#define Relay6  3
#define Relay7  38
#define Relay8  39  

char server[] = "bb.com";  
char ssid[] = "bb";     //SSID Home Network Name
char pass[] = "bb";  //Key or Network Password
int status = WL_IDLE_STATUS;               
int a[7]={0,1,2,3,4,5};
int flag = 0;
double Setpoint, Input, Output;
double Kp=1, Ki=0.5, Kd=0.25;  //PID Tuning Parameters
unsigned long int avgValue;
WiFiClient client;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); //PID Tuning Parameters

DHT dht(DHTPIN, DHTTYPE);
AlarmID_t firstAlarm;
AlarmID_t secondAlarm;
AlarmID_t third;
AlarmID_t fourth;
AlarmID_t fifth;

void setup() {
 
     //wdt_enable(WDTO_8S);
     //wdt_reset();
     dht.begin();
     Wire.begin();
     //myPID.SetSampleTime(30000);
     digitalWrite(Relay1, RELAY_ON);
     digitalWrite(Relay2, RELAY_ON);
     digitalWrite(Relay3, RELAY_ON);
     digitalWrite(Relay4, RELAY_ON);  
     digitalWrite(Relay5, RELAY_ON);
     digitalWrite(Relay6, RELAY_ON);
     digitalWrite(Relay7, RELAY_ON);
     digitalWrite(Relay8, RELAY_ON);
     
     pinMode(Relay1, OUTPUT);   
     pinMode(Relay2, OUTPUT);  
     pinMode(Relay3, OUTPUT);  
     pinMode(Relay4, OUTPUT);    
     pinMode(Relay5, OUTPUT);   
     pinMode(Relay6, OUTPUT);  
     pinMode(Relay7, OUTPUT); 
     pinMode(Relay8, OUTPUT); 
      
     Serial.begin(9600); 

     setSyncProvider(RTC.get);
     
     firstAlarm = Alarm.alarmRepeat(23,28,00, MorningAlarm1); //2 ALARM MAX 
     secondAlarm =  Alarm.alarmRepeat(23,28,10, NightAlarm1);   //2 ALARM MAX
     third= Alarm.alarmRepeat(23,28,00, MorningAlarm2); //2 ALARM MAX
     fourth = Alarm.alarmRepeat(23,28,10, NightAlarm2);   //2 ALARM MAX
     fifth = Alarm.timerRepeat(30, SendData);   

     
     Input = analogRead(2);
     myPID.SetMode(AUTOMATIC);     
     Setpoint = 7.0;
  
     while ( status != WL_CONNECTED) { 
     status = WiFi.begin(ssid, pass);     
     }
     } //End of Void Setup

void loop() {     
           // wdt_reset();
           //Alarm1();
            Alarm.delay(0);           
            } //End of Loop   
            
                void SendData(){            
                if (client.connect(server, 80)) {
               // wdt_reset();
                tmElements_t tm;
                
                int SoilMoisture = analogRead(a[0]);            
            
                int sensorReading = analogRead(a[1]);
            
                int sensorReading2 = analogRead(a[2]);  
                        
                int sensorReading3 = analogRead(a[3]);     
                   
                int buf[10];               
                for(int i=0;i<10;i++)       
                { 
                buf[i]=analogRead(SensorPin);
                }
                for(int i=0;i<9;i++)        
                {
                for(int j=i+1;j<10;j++)
                {
                if(buf[i]>buf[j])
                {
                int temp=buf[i];
                buf[i]=buf[j];
                buf[j]=temp;
                }
                }
                }
                avgValue=0;
                for(int i=2;i<8;i++)                      
                avgValue+=buf[i];
                float phValue=(float)avgValue*5.0/1024/6; 
                phValue=3.5*phValue+Offset;                      
            
                int sensorReading5 = analogRead(a[5]);
                float voltage5 = sensorReading5 * 5.0;
                voltage5 /= 1024; 

                float h = dht.readHumidity();
                float t = dht.readTemperature();  
                client.print(F("GET http://bb?"));
                client.print(F("&1="));
                client.print(SoilMoisture);
                client.print(F("&2="));
                client.print(t);
                client.print(F("&3="));
                client.print(h);
                client.print(F("&4="));
                client.print(sensorReading3);
                client.print(F("&5="));
                client.print(phValue);
                client.print(F("&6="));
                client.print(voltage5);
                client.print(F("&7="));  
                if (RTC.read(tm)) {
                client.print(tmYearToCalendar(tm.Year));
                if (tm.Month<10)
                client.print(F("0"));
                client.print(tm.Month);
                if (tm.Day<10)
                client.print(F("0"));
                client.print(tm.Day);     
                print2digits(tm.Hour);
                print2digits(tm.Minute);
                print2digits(tm.Second);               
                }        
                client.print(F("&8="));
                showAlarmTime(firstAlarm);
                client.print(F("&9="));
                showAlarmTime(secondAlarm);               
                client.print(F("&10="));
                showAlarmTime(third);
                client.print(F("&11="));
                showAlarmTime(fourth);
                client.print(F("&12="));
                showAlarmTime(fifth);
                client.print(F("&13="));
                client.println(Setpoint);
                client.println(" HTTP/1.1");
                client.println("Host: bb.com ");
                client.println();
                } 
                }           
                void MorningAlarm1()
                {
                digitalWrite(Relay1, RELAY_OFF);//This Alarm Turns the relay off. This can be lights or anything. See MorningAlarm1 to adjust Time
                }
                
                void NightAlarm1()
                {
                digitalWrite(Relay1, RELAY_ON);//This Alarm Turns the relay on. This can be lights or anything. See NightAlarm1 to adjust Time
                }
                
                void MorningAlarm2()
                {
                digitalWrite(Relay2, RELAY_OFF);//This Alarm Turns the relay off. This can be lights or anything. See MorningAlarm2 to adjust Time
                }
                
                void NightAlarm2()
                {
                digitalWrite(Relay2, RELAY_ON);//This Alarm Turns the relay on. This can be lights or anything. See NightAlarm2 to adjust Time
                }                
                //  void Pid()
                //   {
                //  Input = analogRead(2);                 
                //  myPID.SetTunings(Kp, Ki, Kd);   
                //  myPID.Compute();        
                //  }  

                void showAlarmTime(AlarmID_t id)
                {
                time_t alarmTime = Alarm.read(id); 
                if( alarmTime <= SECS_PER_DAY)  
            
                // client.print(id, DEC);  
                digitalClockDisplay(alarmTime);
                }
                void digitalClockDisplay(time_t t)
                {
                client.print(hour(t)); 
                if (minute(t)<10)
                client.print(F("0"));
                client.print(minute(t));                
                if (second(t)<10)
                client.print(F("0"));
                client.print(second(t));              
                }
                void print2digits(int number) {
                if (number >= 0 && number < 10) {
                client.write('0');
                }
                client.print(number);
                }
               // void Alarm1()
               // {

                 // if ((hour ==9 )&&( minute==1  ))digitalWrite(Relay1, RELAY_ON);
                //}
int a[7]={0,1,2,3,4,5};

A 7 element array initialized with 6 values, where a{i] = i. How is this useful?

void loop() {     
           // wdt_reset();
           //Alarm1();
            Alarm.delay(0);           
            } //End of Loop   
            
                void SendData(){            
                if (client.connect(server, 80)) {
               // wdt_reset();
                tmElements_t tm;

When you
learn to use
Tools + Auto Format,
I'll make another
attempt to
read your
code.

#include "Wire.h"
#include "DS1307RTC.h"
#include "DHT.h"
#include "PID_v1.h"
#include "SPI.h"
#include "Time.h"
#include "TimeAlarms.h"
#include "WiFi.h"
//#include "avr/wdt.h"
#include "WString.h"
#include "avr/pgmspace.h"

#define F(string_literal) (reinterpret_cast<const __FlashStringHelper *>(PSTR(string_literal)))
#define SensorPin 2      
#define Offset 0            
#define DHTPIN 2
#define DHTTYPE DHT11
#define RELAY_ON 1
#define RELAY_OFF 0
#define Relay1  9  
#define Relay2  8
#define Relay3  6
#define Relay4  5
#define Relay5  4  
#define Relay6  3
#define Relay7  38
#define Relay8  39  

char server[] = "bb.com";  //IPAddress server(); 
char ssid[] = "bb";     //SSID Home Network Name
char pass[] = "bb";  //Key or Network Password
int status = WL_IDLE_STATUS;               
int a[7]={
  0,1,2,3,4,5};
int flag = 0;
double Setpoint, Input, Output;
double Kp=1, Ki=0.5, Kd=0.25;  //PID Tuning Parameters
unsigned long int avgValue;
WiFiClient client;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); //PID Tuning Parameters

DHT dht(DHTPIN, DHTTYPE);
AlarmID_t firstAlarm;
AlarmID_t secondAlarm;
AlarmID_t third;
AlarmID_t fourth;
AlarmID_t fifth;

void setup() {

  //wdt_enable(WDTO_8S);
  //wdt_reset();
  dht.begin();
  Wire.begin();
  //myPID.SetSampleTime(30000);
  digitalWrite(Relay1, RELAY_ON);
  digitalWrite(Relay2, RELAY_ON);
  digitalWrite(Relay3, RELAY_ON);
  digitalWrite(Relay4, RELAY_ON);  
  digitalWrite(Relay5, RELAY_ON);
  digitalWrite(Relay6, RELAY_ON);
  digitalWrite(Relay7, RELAY_ON);
  digitalWrite(Relay8, RELAY_ON);

  pinMode(Relay1, OUTPUT);   
  pinMode(Relay2, OUTPUT);  
  pinMode(Relay3, OUTPUT);  
  pinMode(Relay4, OUTPUT);    
  pinMode(Relay5, OUTPUT);   
  pinMode(Relay6, OUTPUT);  
  pinMode(Relay7, OUTPUT); 
  pinMode(Relay8, OUTPUT); 

  Serial.begin(9600); 

  setSyncProvider(RTC.get);

  firstAlarm = Alarm.alarmRepeat(23,28,00, MorningAlarm1); //2 ALARM MAX 
  secondAlarm =  Alarm.alarmRepeat(23,28,10, NightAlarm1);   //2 ALARM MAX
  third= Alarm.alarmRepeat(23,28,00, MorningAlarm2); //2 ALARM MAX
  fourth = Alarm.alarmRepeat(23,28,10, NightAlarm2);   //2 ALARM MAX
  fifth = Alarm.timerRepeat(30, SendData);   


  Input = analogRead(2);
  myPID.SetMode(AUTOMATIC);     
  Setpoint = 7.0;

  while ( status != WL_CONNECTED) { 
    status = WiFi.begin(ssid, pass);     
  }
} //End of Void Setup

void loop() {     
  // wdt_reset();
  //Alarm1();
  Alarm.delay(0);           
} //End of Loop   

void SendData(){            
  if (client.connect(server, 80)) {
    // wdt_reset();
    tmElements_t tm;

    int SoilMoisture = analogRead(a[0]);            

    int sensorReading = analogRead(a[1]);

    int sensorReading2 = analogRead(a[2]);  

    int sensorReading3 = analogRead(a[3]);     

    int buf[10];               
    for(int i=0;i<10;i++)       
    { 
      buf[i]=analogRead(SensorPin);
    }
    for(int i=0;i<9;i++)        
    {
      for(int j=i+1;j<10;j++)
      {
        if(buf[i]>buf[j])
        {
          int temp=buf[i];
          buf[i]=buf[j];
          buf[j]=temp;
        }
      }
    }
    avgValue=0;
    for(int i=2;i<8;i++)                      
      avgValue+=buf[i];
    float phValue=(float)avgValue*5.0/1024/6; 
    phValue=3.5*phValue+Offset;                      

    int sensorReading5 = analogRead(a[5]);
    float voltage5 = sensorReading5 * 5.0;
    voltage5 /= 1024; 

    float h = dht.readHumidity();
    float t = dht.readTemperature();  
    client.print(F("GET http://bb?"));
    client.print(F("&1="));
    client.print(SoilMoisture);
    client.print(F("&2="));
    client.print(t);
    client.print(F("&3="));
    client.print(h);
    client.print(F("&4="));
    client.print(sensorReading3);
    client.print(F("&5="));
    client.print(phValue);
    client.print(F("&6="));
    client.print(voltage5);
    client.print(F("&7="));  
    if (RTC.read(tm)) {
      client.print(tmYearToCalendar(tm.Year));
      if (tm.Month<10)
        client.print(F("0"));
      client.print(tm.Month);
      if (tm.Day<10)
        client.print(F("0"));
      client.print(tm.Day);     
      print2digits(tm.Hour);
      print2digits(tm.Minute);
      print2digits(tm.Second);               
    }        
    client.print(F("&8="));
    showAlarmTime(firstAlarm);
    client.print(F("&9="));
    showAlarmTime(secondAlarm);               
    client.print(F("&10="));
    showAlarmTime(third);
    client.print(F("&11="));
    showAlarmTime(fourth);
    client.print(F("&12="));
    showAlarmTime(fifth);
    client.print(F("&13="));
    client.println(Setpoint);
    client.println(" HTTP/1.1");
    client.println("Host: bb.com ");
    client.println();
  } 
}           
void MorningAlarm1()
{
  digitalWrite(Relay1, RELAY_OFF);//This Alarm Turns the relay off. This can be lights or anything. See MorningAlarm1 to adjust Time
}

void NightAlarm1()
{
  digitalWrite(Relay1, RELAY_ON);//This Alarm Turns the relay on. This can be lights or anything. See NightAlarm1 to adjust Time
}

void MorningAlarm2()
{
  digitalWrite(Relay2, RELAY_OFF);//This Alarm Turns the relay off. This can be lights or anything. See MorningAlarm2 to adjust Time
}

void NightAlarm2()
{
  digitalWrite(Relay2, RELAY_ON);//This Alarm Turns the relay on. This can be lights or anything. See NightAlarm2 to adjust Time
}                
//  void Pid()
//   {
//  Input = analogRead(2);                 
//  myPID.SetTunings(Kp, Ki, Kd);   
//  myPID.Compute();        
//  }  

void showAlarmTime(AlarmID_t id)
{
  time_t alarmTime = Alarm.read(id); 
  if( alarmTime <= SECS_PER_DAY)  

    // client.print(id, DEC);  
    digitalClockDisplay(alarmTime);
}
void digitalClockDisplay(time_t t)
{
  client.print(hour(t)); 
  if (minute(t)<10)
    client.print(F("0"));
  client.print(minute(t));                
  if (second(t)<10)
    client.print(F("0"));
  client.print(second(t));              
}
void print2digits(int number) {
  if (number >= 0 && number < 10) {
    client.write('0');
  }
  client.print(number);
}
// void Alarm1()
// {

// if ((hour ==9 )&&( minute==1  ))digitalWrite(Relay1, RELAY_ON);
//}

Well if its static, then how is it changing and filling up with respect to time

Sorry you do not understand what you are saying.

There are two sorts of RAM, static RAM and dynamic RAM, the two type referrer only to the fact that you have to keep refreshing, that is writing, dynamic RAM every few micro seconds or so otherwise you loose the contents. Hardware is built into these chips to help this process.
With static RAM you write the contents once and those contents are fixed as long as the power is on.
The big advantage of dynamic RAM is that it takes much less silicon to make it so you can have vastly more memory for a given chip size.

It has nothing at all to do with what the contents are and how those contents move or anything you mentioned in the first post.

Sorry you do not understand what you are saying.

I agree. Thank you.

So in my code then, the SRAM isn't being "filled up"? What is causing the random crashing then? How do I fix it? Thanks

Running out of ram can happen, it is known as a memory leak. It happens when you allocate and deallocate memory in an aysemitric way. Using strings is a well known way to get into trouble but it can also be caused by other things.
It could be that there is too much memory being used and you only notice after a time when you stary to overwrite things.
Memory leakes can be one of the hardest things to find in software debugging.

analogRead() is for analog pins. You are reading pins 0, 1, 2, 3, and 5. Fix that up first (analog pins are referred to a A0, A1, A2, A3, A4, and A5... not the same as a[0], etc.

analogRead() is for analog pins. You are reading pins 0, 1, 2, 3, and 5. Fix that up first (analog pins are referred to a A0, A1, A2, A3, A4, and A5... not the same as a[0], etc.

There is nothing wrong with the way OP is using pin numbers in the analogRead() function. Converting the value (14 on a 328-based Arduino) in A0 into an analog pin number involves subtracting 14 from the number, to get 0. Might as well save the trouble, and supply 0 in the first place.

A0 is defined so that that pin can be used as a digital pin, and have the same name on all Arduinos.

arios85:
I am having SRAM issues. I have code that crashes over time. At first, it would randomly crash after 6-10 hours. I realize the SRAM is used up. How can this be? SRAM stands for static random access memory. Well if its static, then how is it changing and filling up with respect to time... this will be considered dynamic then? Anyways, I made my strings smaller in size, used the F macro and included the "avr/pgmspace.h" in my list of libraries .Why does it fill up over time? It did improve the crash time to about 24 hours instead. How does a program run and clear a stack out of the SRAM and send it elsewhere? And if I transfer it to my flash or eeprom then wont that fill up over time eventually as well making the program crash? Thanks.

Try implementing the common freeRAM() function in your application and using it over time to observe available memory. Your description suggests that your free RAM will decline over time until you eventually get a crash. Here is my implementation of this common function.

int freeRam() {
  //If __brkval is zero nothing has been allocated on the heap - so use heap start
  //If __brkval is non zero it indicates the top of the heap
  extern int __heap_start, *__brkval;

  //Calculate the free RAM between the top of the heap and top of the stack
  //This new variable is on the top of the stack
  int l_total = 0;
  if (__brkval == 0)
	l_total = (int) &l_total - (int) &__heap_start;
  else
	l_total = (int) &l_total - (int) __brkval;
  //
  l_total -= sizeof(l_total); //Because free RAM starts after this local variable
  return l_total;
}

If indeed you can see your free RAM declining then you need to find out why. The use of String global variables that are subject to regular changes may be a contributor. Likewise the creation of memory objects that are not closed properly to release their memory may be a problem.

Cheers

Catweazle NZ

So in my code then, the SRAM isn't being "filled up"?

Yes it is.
Looking at your code you have a lot of libraries any one of those could have a memory leak in them.
It does not have to be a leak even, it could be that your free memory is becoming fragmented. Suppose you have two string variables the first of 6 chars call it A and the second of eight call that B. To start off they sit next to each other in the memory. Now you change the value in A to a 7 chars string. It won't fit in the old memory space so new space is allocated after variable B. This leaves a hole where A used to be. It is free memory but it is isolated.
The compile will use this space if it can, but the free memory can become fragmented, full of little free space too small to use. There is a process of gathering all this free space into one area by shuffling the variables you do have about to consolidate all the small free spaces into one large free space. This is called garbage collection, some languages have this built in but the C language does not.

Follow the advice given by CatweazleNZ and also try and give yourself as much free SRAM as possible by moving all your literal strings into program memory using the F function.
http://playground.arduino.cc/Learning/Memory#.UwlwdF6prdU

Also this link from one of our members has some good advice.

To put some closure to this thread, this is what I did to solve try and solve the issue.

Thinking I had a leak somewhere either in my code or in the called libraries, I downloaded a brand new version of Arduino, the 1.05 I think its called (I've been using 1.03 previously). I obtained new libraries for the Time, Time Alarms, and RTC and ran my code. I still got crashing. I put that free memory scan in my loop and saw no decrease in RAM over a certain time (the value in my serial monitor didn't decrease).

Finally, I added

client.flush();
client.stop();

to the end of my code and it works like a charm. Going on day 6 with no crashes yet. Flush and stop your connection ALWAYS when wanting to do instances as this one talked about in this thread. Thank you all for your help in trying to figure out what was going on with my code.

1 Like