Too many static vars?

Hi Folks,

I'm recognizing while my program grew, that all of a sudden a static var in a function isn't static anymore. In total I use about 20 vars static distributed in several functions. From my observations I could assume that ther maybe too many vars static but I'm really not sure.

Does anybody have a clue whether this assumption is reasonable or other ideas why static vars may be modified for any other reasons?

Thanks in advance

Tuxuser

http://arduino.cc/forum/index.php/topic,97455.0.html

Section 6

Tuxuser:
ideas why static vars may be modified for any other reasons?

Memory corruption, possibly caused by running out of RAM (but could also be caused by bugs in your code).

Arduinos have very little RAM, so there is a practical limit to how many variables you can have. There is no specific limit to the number you can have though, whether static or not.

Post your code. Without seeing it, we can only guess at the cause of the problem.

Okay, my fault not posting the code :frowning: take my appologies. However I'm unable to post, since the code (1300 somewhat lines) exeeds the forum limit obviosly by far. I have to find another solution... :frowning:

However, I recognized, that other and additionaly introduced vars work nicely...

Tuxuser

Tuxuser:
I have to find another solution... :frowning:

If it's too big to include in a post, your next option is to attach it to a post. Your last option is to post it on a public file-sharing site and post a link to it.

I highly appreciate your willingness to assist! Attached is the code.

Hava a look at the "int RTC (int command)" function. There are two static vars, yearRTC and yearRtc. One returns the correct value (see comments) the other one not because it is actually cleared after returning from the function. I don't have a clue.

Thanks to all of you

Tuxuser

Unfortunately, I can't download that file - looks like a problem with the forum server.

Seems like some more things are against me :wink: if even the download isn't working...

Let's see whether at least the function having the trouble is small enough:

int RTC (int command) {
  static int dummy2 = 0;
  static int dummy3 = 0;
  static int dummy4 = 0;
  static int  secondRTC = 0;
  static int  minuteRTC = 0;  
  static int  hourRTC = 0;
  static int  weekdayRTC = 0;
  static int  dayRTC = 0;
  static int  monthRTC = 0;
  static int  yearRTC = 0;    // This var is not static after compilation
  static int yearRtc = 0;
  static int  calenderDayRTC = 0;  
  static boolean       dstRTC = 0;
  
  unsigned long  ntpTime = 0;
  unsigned int  returnValue = 0;
  boolean leapYear = 0;
  long daysSince1970 = 0;
  long yearCntr = 0;

#ifdef DEBUG_Time
  Serial.println ("[RTC Routine]");
#endif
   

  // NTP sync the RTC either on startup (weekday = 0) or at 4 in the morning for one hour ever 5 minutes if longer than 23 hrs unsync
  // 23 hrs to avoid a time lag of an hour per day.
  if (weekdayRTC == 0 || (hourRTC == 4 && (minuteRTC % 5) == 0 && secondRTC == 0 && TimerCare (getHoursNoSync) >= 23)) {                             
#ifdef DEBUG
    Serial.println ("  Set RTC");
#endif

    // Sync with NTP
    ntpTime = getNtpTime ();
    
   
    // Convert NTP seconds in real time and date
    if (ntpTime != 0) {
      // Calculate year
      daysSince1970 = ntpTime / 86400L;
      yearCntr = 1970;
      while (daysSince1970 >= 0) {
        yearCntr++;
        if (yearCntr % 4 == 0) {
          // leap year
          daysSince1970 -= 366;
        }
        else {
          daysSince1970 -= 365;
        }
      }
      yearRTC = yearCntr - 1;  // Not static - Compiler BUG?
      yearRtc = yearCntr - 1;

      // Calculate day number within year
      if ((yearRTC - 1) % 4 == 0) {
        calenderDayRTC = daysSince1970 + 366;
      }
      else {
        calenderDayRTC = daysSince1970 + 365;
      }
      //Calculate time (hh:mm:ss)
      hourRTC = ((ntpTime % 86400L) / 3600) + correctZone + (int) dstRTC;
      minuteRTC = (ntpTime % 3600) / 60;
      secondRTC = (ntpTime % 60);
      
      // Calculate weekday (Mon to Sun, 1 to 7)
      weekdayRTC = ((int)(ntpTime / 86400L)) % 7 + correctDay;    // Need to correct by the weekday as of 2013-01-01
      if (weekdayRTC > 7) {                                // Correction needed due to correctDay setting above
        weekdayRTC -= 7;
      }
      
      // Reset the hours without NTP synchronisation
      TimerCare (resetNoSyncTime);
      
      // Now while NTP sync is done set status OK
      operationState = stateOK;
      
      // Initially set the shutters
      if (hourRTC * 60 + minuteRTC > getNextDrive (getOpen) && hourRTC * 60 + minuteRTC < getNextDrive (getClose)) {
        shutterDrive (shutterSequenceUp, 0);
#ifdef DEBUG
        sprintf (debugText, "[RTC]\n  Auto Drive UP init at: %02i:%02i\n", RTC (getHour), RTC (getMinute));
        Serial.println (debugText);
#endif        
      }
      else {
        shutterDrive (shutterSequenceDown, 0);
#ifdef DEBUG
        sprintf (debugText, "[RTC]\n  Auto Drive DOWN init at: %02i:%02i\n", RTC (getHour), RTC (getMinute));
        Serial.println (debugText);
#endif        
      }

      
#ifdef DEBUG
      Serial.println ("  RTC synced");
      Serial.print ("  NTP: ");
      Serial.println (ntpTime);
      sprintf (debugText, "  RTC: %02i:%02i:%02i\n", hourRTC, minuteRTC, secondRTC);
      Serial.print (debugText);
      sprintf (debugText, "  Date: %4.0i-%02i-%02i Weekday: %i\n", yearRTC, monthRTC, dayRTC, weekdayRTC);
      Serial.print (debugText);
#endif      
    }
  }
  
  // Maintain the RTC time every expired second
  if (yearRTC % 4 == 0) {
    leapYear = 1;
  }
  else {
    leapYear = 0;
  }
  
  // Update all values of the RTC
  if (command == maintainRTC) {

    // Maintain RTC
    if (++secondRTC > 59) {
      secondRTC = 0;
      
      // Calculate day and month every minute (ensures quick availability after 1st sync)
      if (calenderDayRTC <= 31) {                          // Jan with 31 days
        monthRTC = 1;
        dayRTC = calenderDayRTC;
      }
      else if (calenderDayRTC <= 59 + (int) leapYear) {    // Feb with 28 +1 days
        monthRTC = 2;
        dayRTC = calenderDayRTC - 31 - (int) leapYear;
      }
      else if (calenderDayRTC <= 90 + (int) leapYear) {    // Mar with 31 days
        monthRTC = 3;
        dayRTC = calenderDayRTC - 59 - (int) leapYear;
      }
      else if (calenderDayRTC <= 120 + (int) leapYear) {   // Apr with 30 days
        monthRTC = 4;
        dayRTC = calenderDayRTC - 90 - (int) leapYear;
      }
      else if (calenderDayRTC <= 151 + (int) leapYear) {  // May with 31 days
        monthRTC = 5;
        dayRTC = calenderDayRTC - 120 - (int) leapYear;
      }
      else if (calenderDayRTC <= 181 + (int) leapYear) {  // Jun with 30 days
        monthRTC = 6;
        dayRTC = calenderDayRTC - 151 - (int) leapYear;
      }
      else if (calenderDayRTC <= 212 + (int) leapYear) {  // Jul with 31 days
        monthRTC = 7;
        dayRTC = calenderDayRTC - 181 - (int) leapYear;
      }
      else if (calenderDayRTC <= 243 + (int) leapYear) {  // Aug with 31 days
        monthRTC = 8;
        dayRTC = calenderDayRTC - 212 - (int) leapYear;
      }
      else if (calenderDayRTC <= 273 + (int) leapYear) {  // Sep with 30 days
        monthRTC = 9;
        dayRTC = calenderDayRTC - 243 - (int) leapYear;
      }
      else if (calenderDayRTC <= 304 + (int) leapYear) {  // Oct with 31 days
        monthRTC = 10;
        dayRTC = calenderDayRTC - 273 - (int) leapYear;
      }
      else if (calenderDayRTC <= 334 + (int) leapYear) {  // Nov with 30 days
        monthRTC = 11;
        dayRTC = calenderDayRTC - 304 - (int) leapYear;
      }
      else if (calenderDayRTC <= 365 + (int) leapYear) {  // Dec with 31 days
        monthRTC = 12;
        dayRTC = calenderDayRTC - 334 - (int) leapYear;
      }

     if (++minuteRTC > 59) {
        minuteRTC = 0;
        if (++hourRTC > 23) {
          hourRTC = 0;
          if ((!leapYear && (++calenderDayRTC > 365)) ||
              (leapYear && (calenderDayRTC > 366)))     {
            calenderDayRTC = 1;
            yearRTC++;  // Not static - Compiler BUG?
            yearRtc++;
          }
        }
      }
    }

    
#ifdef DEBUG_TIME
  sprintf (debugText, "  RTC: %02i:%02i:%02i\n", hourRTC, minuteRTC, secondRTC);
  Serial.print (debugText);
#endif
    
  }
  
#ifndef NODST
  dstRTC = 0;
  if (monthRTC >= 4 && monthRTC <= 9) {
    dstRTC = 1;
  }
  else if (monthRTC == 3 && dayRTC >= 25) {
    if  (weekdayRTC == 7 && hourRTC >= 3) {
      dstRTC = 1;
    }
    else if (dayRTC - weekdayRTC >= 25) {
      dstRTC = 1;
    }
  }
  
  else if (monthRTC == 10 && weekdayRTC >= 25) {
    if  (weekdayRTC == 7 && hourRTC >= 3) {
      dstRTC = 0;
    }
    else if (dayRTC - weekdayRTC >= 25) {
      dstRTC = 0;
    }
    else {
      dstRTC = 1;
    }
  }

#ifdef DEBUG_TIME
  if (dstRTC) {
    Serial.println ("  DST");
  }
  else {
    Serial.println ("  No DST");
  }
#endif


#endif
  
  
  switch (command) {
    case getSecond:
      returnValue = secondRTC;
    break;
    
    case getMinute:
      returnValue = minuteRTC;
    break;
    
    case getHour:
      returnValue = hourRTC;
    break;
    
    case getDay:
      returnValue = dayRTC;
    break;

    case getWeekday:
      returnValue = weekdayRTC;
    break;
    
    case getMonth:
      returnValue = monthRTC;
   break;
    
    case getYear:
      returnValue = yearRTC;  // Not static - Compiler BUG?
//      returnValue = yearRtc;
    break;
    
    case getCalenderDay:
      returnValue = calenderDayRTC;
    break;

    case getDst:
      returnValue = (int) dstRTC;
    break;
  }
  return returnValue;
}
        sprintf (debugText, "[RTC]\n  Auto Drive UP init at: %02i:%02i\n", RTC (getHour), RTC (getMinute));
        Serial.println (debugText);

You can save a bunch of memory by doing multiple Serial.print()s.

#ifdef DEBUG_Time
Serial.println (F("[RTC Routine]"));
#endif
will save SRAM, too.

What are the symptoms that make you believe it's "not static"?

Both vars used (consequently same treatment in all lines) are returning different values to main. During all my experiements, I also inserted some code sending the values via serial.print and it sends at the start of the next function call a 0 (zero). Funny though, I as well observed a shift from one var to another when experimenting with the code. Before the yearRTC was affected I had another var affected. By that time I thought it might be some prob with too many statics within one function and moved the code to another function. After that the moved var was fine but now yearRTC got corrupted.

How much free memory does your sketch have when it is running?

Surely another part of my newbie limitations: I see that the sketch size is 24.886 bytes out of 258.048 but where do I find the used RAM?

Looks like 4652 bytes RAM left...

If you search for "Arduino free memory" you should find a well-used piece of code (probably in the playground) that works out how much memory is free.

My guess is that you have a pointer an array index somewhere else in the program that is going wildly out of range. However, it's worth checking the amount of free memory, because that's an easy thing to do. This is the code I use:

// Find out how much free memory we have
unsigned int getFreeMemory()
{
  uint8_t* temp = (uint8_t*)malloc(16);    // assumes there are no free holes so this is allocated at the end
  unsigned int rslt = (uint8_t*)SP - temp;
  free(temp);
  return rslt;
}

It is fast, but if you are using the String class or anything else that uses dynamic memory, then it isn't reliable. There are other ways of getting free memory, based on calling malloc in a loop, that work in those cases.

dc42:
There are other ways of getting free memory, based on calling malloc in a loop, that work in those cases.

The approaches based on calling malloc() in a loop will tell you the largest contiguous piece of free memory in the heap but would surely not tell you how much space is available for the stack. In cases where the sketch makes little/no use of dynamic memory, the remaining stack space is far more important so the code you posted is what is needed.

@dc42 after wondering above I found that piece of code. That's where the "4652 bytes" left cam from. However, thanks for confirming me.

You're making a good point that somewhere in the program somthing might get out of range. I'm going to check on that as far as possible. Hypotheses is that it may be related to the Ethercard library from Jeelabs for ENC28J60. I already recognized that this lib, means the buffer used inside is subject to cause strange things...

I'll keep you posted!