crash with String() concatenation

Basically, this an Uno with a nice LCD, and the program crashes when lots of String concatenation occurs in a single line. If you concat it piece-meal, then it's fine. Check Option 1 and Option 2 in the code - 1 crashes, 2 works fine.

The hardware is listed here:

http://forums.adafruit.com/viewtopic.php?f=25&t=27606

Within that thread, there were suggestions that the culprit may be the String lib in the 1.0 IDE.

Thoughts, suggestions? Thanks!

#include "Wire.h"
#include "LiquidCrystal.h"
#include "RTClib.h"
#include "SD.h"

// Address the correct LCD
LiquidCrystal lcd(0);
// RTC type
RTC_DS1307 RTC;
// Select the pin for SD card
const int chipSelect = 10;

// Init variables
char spinn = ' ';
int prevmin = 61;
String line0 = "";
String line1 = "";
String line2 = "";
String line3 = "";

void setup() {
  // Fire up comm libraries
  Wire.begin();
  RTC.begin();

  // Set the clock
  /*
  if (! RTC.isrunning()) {
    RTC.adjust(DateTime(__DATE__, __TIME__));
  }
  */

  // Fire up LCD
  lcd.begin(20, 4);

  // Set output pin for SD  
  pinMode(10, OUTPUT);
}

int spewLCD() {
  // Dump all line strings to LCD
  lcd.setCursor(0, 0);
  lcd.print(String(line0));
  lcd.setCursor(0, 1);
  lcd.print(String(line1));
  lcd.setCursor(0, 2);
  lcd.print(String(line2));
  lcd.setCursor(0, 3);
  lcd.print(String(line3));
}

String spinner() {
  // animate a spinning character
  switch (spinn) {
    case '|':
      spinn = '/';
      break;
    case '/':
      spinn = '-';
      break;
    case '-':
      spinn = ' ';
      break;
    case ' ':
      spinn = '|';
      break;
  }
  return String(spinn);
}

String padto4(int num) {
  // left-pad 4-digit integer with 0
  // return String
  if (num < 10) {
    return "000" + String(num);
  }  else if (num < 100) {
    return "00" + String(num);
  } else if (num < 1000) {
    return "0" + String(num);
  } else {
    return String(num);
  }
}

String padto2(int num) {
  // left-pad 2-digit integer with 0
  // return String
  if (num < 10) {
    return "0" + String(num);
  } else {
    return String(num);
  }
}

void loop() {
  // get now time
  DateTime now = RTC.now();

  // current minute
  int min = now.minute();
  
  String yr = padto4(now.year());
  String mt = padto2(now.month());
  String d = padto2(now.day());
  String hr = padto2(now.hour());
  String mn = padto2(now.minute());
  String s = padto2(now.second());

  // prepare display lines
  line0 = "Pri=+12 Sec=+15    C";
  line1 = "Out=+17 In=+15 H=75%";
  line2 = "RPM=2125        AUTO";

///////// OPTION 1 /////////////
//  line3 = yr + "/" + mt + "/" + d + " " + hr + ":" + mn + ":" + s + spinner();
////////////////////////////////

///////// OPTION 2 /////////////
  line3 = yr + "/";
  line3 = line3 + mt + "/";
  line3 = line3 + d + " ";
  line3 = line3 + hr + ":";
  line3 = line3 + mn + ":";
  line3 = line3 + s + spinner();
////////////////////////////////

  spewLCD();

/*
  if (prevmin != min) {
    // if a new minute just started
    File logF = SD.open("log.txt", FILE_WRITE);
    if (logF) {
      logF.println(min);
      logF.close();
    } else {
      lcd.setCursor(0, 0);
      lcd.print("cannot open log.txt");
    }
    // and now the new minute has become old, we wait for the next minute
    prevmin = min;
  }
*/

//  delay(100);
}

Suggestion then.

I suggest you rethink using String Objects on a device with only 2k of ram.

String spinner() {
  // animate a spinning character
  switch (spinn) {
    case '|':
      spinn = '/';
      break;
    case '/':
      spinn = '-';
      break;
    case '-':
      spinn = ' ';
      break;
    case ' ':
      spinn = '|';
      break;
  }
  return String(spinn);
}

Why are you wrapping a single itty-bitty char in a humongous String object?

String padto4(int num) {
  // left-pad 4-digit integer with 0
  // return String
  if (num < 10) {
    return "000" + String(num);
  }  else if (num < 100) {
    return "00" + String(num);
  } else if (num < 1000) {
    return "0" + String(num);
  } else {
    return String(num);
  }
}

More uselessness.

What is the end goal of getting everything into a single string? sprintf() could be used with a lot less overhead, IF it was needed. Almost certainly is isn't.

I am always warning anything to stay clear of String class due to limited memory. Here is an old-school sprint way tutorial:

BTW, your spinning character method was pretty cool, my 2 cents. I would consider using an array and a pointer but your way is more clear with few symbols.

Why are you wrapping a single itty-bitty char in a humongous String object?

Because I'm a newbie, that's why.

I did quite a bit of programming, back in the day, on small devices with restricted memory, but I lost my chops after spending a lot of time with systems with 4GB of RAM. I guess I need to change the way I'm thinking again.

BTW, the documentation on http://arduino.cc/ really hides the fact that you could use the built-in C library. I can see how this helps non-programmers, but at some point it turns around and bites you in the a**. I wasn't even aware that I could use sprintf() and stuff like that.

I eliminated all the String references and all is well now. No more crashes.

Just to be clear, Arduino uses g++ compiler so pretty much all ANSI c and c++. Arduino team wants to hide this fact from newbies that are turned away by programming in c but use sketch in arduino language.

I eliminated all the String references and all is well now. No more crashes.

Excellent. Thanks for letting us know.

Down on the lower right of the (simple and incomplete) Reference page on the Arduino site you can find link to AVR Libc. Go there and find more detail.

I have a growing bookmarks section in my browser just for organizing all the links I've copied. And still I have to net-dig at times.

Florin_Andrei:

Why are you wrapping a single itty-bitty char in a humongous String object?

Because I'm a newbie, that's why.
...

I eliminated all the String references and all is well now. No more crashes.

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

Paragraph 8.

Now we just have to get people to read it.

Then help the ones that read but don't understand.
The hard ones to help are the ones that don't understand but think they do.