Running out of memory.

Here's the problem. I've got a large bunch of strings in PROGMEM. No problem. They're called at random, and output to 1602 display. Each string is less than 16 characters long, but after about ~4 iterations, my SRAM is full and it resets.

What I need is an equivalent of print(F that works with variable strings. Any ideas?

void loop() {
  // read the input pin:
  boolean buttonState = digitalRead(pushButton); // read the pushbutton
  if (!buttonState) { // if it's low
    rand1 = random (0, 53); // generate some random numbers
    rand2 = random (0, 53);
    rand3 = random (0, 53);
    lcd.clear (); // set up the display
    lcd.setCursor (0, 0);
    lcd.print(F("Thou")); // print(F "thou"
    lcd.setCursor (0, 1);
    strcpy_P(buffer, (char*)pgm_read_word(&(lineOne_table[rand1]))); //Get and reconstruct 1st string from PROGMEM
    lcd.print(buffer); // print it
    delay (2000); // wait a bit
    lcd.clear (); // do it again
    lcd.setCursor (0, 0);
    strcpy_P(buffer, (char*)pgm_read_word(&(lineTwo_table[rand2])));//Get and reconstruct 2nd string from PROGMEM
    lcd.print(buffer);
    lcd.setCursor (0, 1);
    strcpy_P(buffer, (char*)pgm_read_word(&(lineThree_table[rand3])));//Get and reconstruct 3rd string from PROGMEM
    lcd.print(buffer);


  }
}

Please post your code

I'd love to, but apparently it exceeds the maximum size allowed, hence I only posted the loop. Hang on, I'll cut it into bits.

What evidence do you have its RAM running out? Could it be insufficient before even starting? google
arduino memoryfree

#include <avr/pgmspace.h>
#include <LiquidCrystal.h>
// load words into program memory
const char lineOne_0[] PROGMEM = "test 1";
const char lineOne_1[] PROGMEM = "test 1";
const char lineOne_2[] PROGMEM = "test 1";
const char lineOne_3[] PROGMEM = "test 1";
const char lineOne_4[] PROGMEM = "test 1";
const char lineOne_5[] PROGMEM = "test 1";
const char lineOne_6[] PROGMEM = "test 1";
const char lineOne_7[] PROGMEM = "test 1";
const char lineOne_8[] PROGMEM = "test 1";
const char lineOne_9[] PROGMEM = "test 1";
const char lineOne_10[] PROGMEM = "test 1";
const char lineOne_11[] PROGMEM = "test 1";
const char lineOne_12[] PROGMEM = "test 1";
const char lineOne_13[] PROGMEM = "test 1";
const char lineOne_14[] PROGMEM = "test 1";
const char lineOne_15[] PROGMEM = "test 1";
const char lineOne_16[] PROGMEM = "test 1";
const char lineOne_17[] PROGMEM = "test 1";
const char lineOne_18[] PROGMEM = "test 1";
const char lineOne_19[] PROGMEM = "test 1";
const char lineOne_20[] PROGMEM = "test 1";
const char lineOne_21[] PROGMEM = "test 1";
const char lineOne_22[] PROGMEM = "test 1";
const char lineOne_23[] PROGMEM = "test 1";
const char lineOne_24[] PROGMEM = "test 1";
const char lineOne_25[] PROGMEM = "test 1";
const char lineOne_26[] PROGMEM = "test 1";
const char lineOne_27[] PROGMEM = "test 1";
const char lineOne_28[] PROGMEM = "test 1";
const char lineOne_29[] PROGMEM = "test 1";
const char lineOne_30[] PROGMEM = "test 1";
const char lineOne_31[] PROGMEM = "test 1";
const char lineOne_32[] PROGMEM = "test 1";
const char lineOne_33[] PROGMEM = "test 1";
const char lineOne_34[] PROGMEM = "test 1";
const char lineOne_35[] PROGMEM = "test 1";
const char lineOne_36[] PROGMEM = "test 1";
const char lineOne_37[] PROGMEM = "test 1";
const char lineOne_38[] PROGMEM = "test 1";
const char lineOne_39[] PROGMEM = "test 1";
const char lineOne_40[] PROGMEM = "test 1";
const char lineOne_41[] PROGMEM = "test 1";
const char lineOne_42[] PROGMEM = "test 1";
const char lineOne_43[] PROGMEM = "test 1";
const char lineOne_44[] PROGMEM = "test 1";
const char lineOne_45[] PROGMEM = "test 1";
const char lineOne_46[] PROGMEM = "test 1";
const char lineOne_47[] PROGMEM = "test 1";
const char lineOne_48[] PROGMEM = "test 1";
const char lineOne_49[] PROGMEM = "test 1";
const char lineOne_50[] PROGMEM = "test 1";
const char lineOne_51[] PROGMEM = "test 1";
const char lineOne_52[] PROGMEM = "test 1";
const char lineOne_53[] PROGMEM = "test 1";

Doz71:
I'd love to, but apparently it exceeds the maximum size allowed, hence I only posted the loop. Hang on, I'll cut it into bits.

OK, so attach it.

That's a good plan.

Please find attached :slight_smile:

sketch_jan10a.ino (10.4 KB)

Why is it necessary to repeat the same string 53 times, times 3? WHy can't you do something like;

char testOne[]   = "test one";
char testTwo[]   = "test two";
char testthree[] = "test three";

Perhaps you can give more details on what the output of the program should be with some given set of inputs, as I just don't see the reason for all the duplicated strings.

It generates a random phrase.

Those are just test words. In the end sketch they will not be repeated.

There are a choice of 54 different words for each "line".

Doz71:
It generates a random phrase.

Can you explain what's the difference between these "random" phrases, please:

const char lineOne_0[] PROGMEM = "test 1";
const char lineOne_1[] PROGMEM = "test 1";
const char lineOne_2[] PROGMEM = "test 1";
const char lineOne_3[] PROGMEM = "test 1";
const char lineOne_4[] PROGMEM = "test 1";
const char lineOne_5[] PROGMEM = "test 1";
const char lineOne_6[] PROGMEM = "test 1";
const char lineOne_7[] PROGMEM = "test 1";
const char lineOne_8[] PROGMEM = "test 1";
const char lineOne_9[] PROGMEM = "test 1";
const char lineOne_10[] PROGMEM = "test 1";
const char lineOne_11[] PROGMEM = "test 1";
const char lineOne_12[] PROGMEM = "test 1";
const char lineOne_13[] PROGMEM = "test 1";
const char lineOne_14[] PROGMEM = "test 1";
const char lineOne_15[] PROGMEM = "test 1";
const char lineOne_16[] PROGMEM = "test 1";
const char lineOne_17[] PROGMEM = "test 1";
const char lineOne_18[] PROGMEM = "test 1";
const char lineOne_19[] PROGMEM = "test 1";
const char lineOne_20[] PROGMEM = "test 1";
const char lineOne_21[] PROGMEM = "test 1";
const char lineOne_22[] PROGMEM = "test 1";
const char lineOne_23[] PROGMEM = "test 1";
const char lineOne_24[] PROGMEM = "test 1";
const char lineOne_25[] PROGMEM = "test 1";
const char lineOne_26[] PROGMEM = "test 1";
const char lineOne_27[] PROGMEM = "test 1";
const char lineOne_28[] PROGMEM = "test 1";
const char lineOne_29[] PROGMEM = "test 1";
const char lineOne_30[] PROGMEM = "test 1";
const char lineOne_31[] PROGMEM = "test 1";
const char lineOne_32[] PROGMEM = "test 1";
const char lineOne_33[] PROGMEM = "test 1";
const char lineOne_34[] PROGMEM = "test 1";
const char lineOne_35[] PROGMEM = "test 1";
const char lineOne_36[] PROGMEM = "test 1";
const char lineOne_37[] PROGMEM = "test 1";
const char lineOne_38[] PROGMEM = "test 1";
const char lineOne_39[] PROGMEM = "test 1";
const char lineOne_40[] PROGMEM = "test 1";
const char lineOne_41[] PROGMEM = "test 1";
const char lineOne_42[] PROGMEM = "test 1";
const char lineOne_43[] PROGMEM = "test 1";
const char lineOne_44[] PROGMEM = "test 1";
const char lineOne_45[] PROGMEM = "test 1";
const char lineOne_46[] PROGMEM = "test 1";
const char lineOne_47[] PROGMEM = "test 1";
const char lineOne_48[] PROGMEM = "test 1";
const char lineOne_49[] PROGMEM = "test 1";
const char lineOne_50[] PROGMEM = "test 1";
const char lineOne_51[] PROGMEM = "test 1";
const char lineOne_52[] PROGMEM = "test 1";
const char lineOne_53[] PROGMEM = "test 1";

If I select one of these randomly and print it on a LCD, I can see no difference, actually.

This can give you an idea of how to start working with PROGMEM, but you'll have to work out the random selection yourself.

#include <avr/pgmspace.h>

char* const  wordsLine1[53] PROGMEM =  {"day" ,  "night",  "noon",  "midnight" ,  "" ,};
char* const  wordsLine2[53] PROGMEM =  {"see",  "feels",  "smell",  "touch",  "",};
char* const  wordsLine3[53] PROGMEM =  {"bright",  "dull",  "smooth",  "rough", "",};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  char *ptr;

  ptr = (char*)pgm_read_word(&wordsLine1[3]);
  Serial.print(ptr);
  Serial.print(" ");
  ptr = (char*)pgm_read_word(&wordsLine2[1]);
  Serial.print(ptr);
  Serial.print(" ");
  ptr = (char*)pgm_read_word(&wordsLine3[2]);

  Serial.println(ptr);
 
}

void loop() {

}

Thanks econjack, I'll give this a try. I initally got the PROGMEM code from the example given.

Thanks Nick, and thanks for the clear explanation on your website. I can now start to understand what's going on, rather than poking and hoping (there's a BASIC gag in there for you).

You initial approach was better than econjacks...

The difference (using the same data) is 64 bytes of ram usage.

const char wl1_a[] PROGMEM = "day";
const char wl1_b[] PROGMEM = "night";
const char wl1_c[] PROGMEM = "noon";
const char wl1_d[] PROGMEM = "midnight";
const char wl1_e[] PROGMEM = "";
const char wl2_a[] PROGMEM = "see";
const char wl2_b[] PROGMEM = "feels";
const char wl2_c[] PROGMEM = "smell";
const char wl2_d[] PROGMEM = "touch";
const char wl3_a[] PROGMEM = "bright";
const char wl3_b[] PROGMEM = "dull";
const char wl3_c[] PROGMEM = "smooth";
const char wl3_d[] PROGMEM = "rough";
const char* const wordsLine1[53] PROGMEM =  {wl1_a ,  wl1_b,  wl1_c, wl1_d, wl1_e, };
const char* const wordsLine2[53] PROGMEM =  {wl2_a ,  wl2_b,  wl2_c, wl2_d, wl1_e, };
const char* const wordsLine3[53] PROGMEM =  {wl3_a ,  wl3_b,  wl3_c, wl3_d, wl1_e, };

void setup() {
  Serial.begin(115200);
  char *ptr = (char*)pgm_read_word(&wordsLine1[3]);
  printPM(ptr);
  Serial.write(' ');
  ptr = (char*)pgm_read_word(&wordsLine2[1]);
  printPM(ptr);
  Serial.write(' ');
  ptr = (char*)pgm_read_word(&wordsLine3[2]);
  printPM(ptr);
  Serial.println();
}

void printPM(char* ptr) {
  byte cval;
  while (cval=pgm_read_byte_near(ptr++)) {
    Serial.write(cval);
  }
}

void loop() {}

@Whandall: I don't understand your comment. I just compiled with 1.6.5 and my program is 2234 bytes and yours is 2254. Also, when I try to run yours, I get no output. I'm not sure what the problem is, as I just compiled it. If yours run, what IDE are you using?

I had to change the print function to make it print (edited the post, sorry).

I'm talking about the ram usage. Your strings reside in RAM, not in PROGMEM.
Your code only places the array of pointers (to RAM strings) into PROGMEM
(and creates a bunch of warnings).

My ide is 1.6.5

Doz71:
Thanks Nick, and thanks for the clear explanation on your website. I can now start to understand what's going on, rather than poking and hoping (there's a BASIC gag in there for you).

Peeking and poking, eh?

Doz71:
What I need is an equivalent of print(F that works with variable strings. Any ideas?

lcd.print(reinterpret_cast<const __FlashStringHelper *>(pgm_read_word(...)))

Feel free to create a macro for it. :slight_smile:

Doz71:
What I need is an equivalent of print(F that works with variable strings. Any ideas?

PROGMEM isn't variable, so I don't understand your question. Variables go into RAM.