strings / string literals

Hi,

I have a sketch that includes the below code:

          strcpy(menuList[0],"DropControl v0.1  ");  
          strcpy(menuList[1],"QUICK MODE");
          strcpy(menuList[2],"FULL MODE");
          strcpy(menuList[3],"Drop Info");          
          strcpy(menuList[4],"Set trigger delay");
          strcpy(menuList[5],"Set loop delay");
          strcpy(menuList[6],"Drain");
          strcpy(menuList[7],"Save/Load");
          strcpy(menuList[8],"About");
          numMenuItems = 8;

After the values are copied menuList[] is used by a menu function.

Am I right in thinking that the above text/string literals are copied to RAM on start up and then duplicated when they are copied to menuList{}?

If this is correct, how do I move the text to program memory or eeprom?

strcpy_P would bear some study.
Or use PROGMEM to prevent it being copied the RAM.

Some snippets from a menu system that I use:

#include <avr/pgmspace.h>
.........
........
PROGMEM const char string_0[] = "menu line 1  ";
PROGMEM const char string_1[] = "menu line 2   ";
PROGMEM const char string_2[] = "menu line 3   ";
PROGMEM const char string_3[] = "menu line 4   ";
PROGMEM const char string_4[] =  "               ";
PROGMEM const char string_5[] =  "               ";
PROGMEM const char string_6[] =  "               ";
PROGMEM const char string_7[] =  "               ";
PROGMEM const char string_8[] =  "               ";
PROGMEM const char string_9[] =  "               ";
PROGMEM const char string_10[] =  "               ";
PROGMEM const char string_11[] = "               ";
PROGMEM const char string_12[] = "               ";
PROGMEM const char string_13[] = "               ";
PROGMEM const char string_14[] = "               ";

// Then set up a table to refer to your strings.

PROGMEM const char* const menu_table[] = 	   
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5,
  string_6,
  string_7,
  string_8,
  string_9,
  string_10,
  string_11,
  string_12,
  string_13,
  string_14
};
..............
...........

//Displaying menu lines

  for (int i = marker; i < marker + 4; i++)
  {
    strcpy_P(buffer, (char*)pgm_read_word(&menu_table[i])); // Necessary casts and dereferencing.    
    lcd.setCursor(0, j);
    lcd.print(buffer);
...........
..........

This works using avr-gcc compiler version 4.7.2. If you are using the older version bundled with standard Arduino IDE there will need to be some minor changes with number of brackets and casting to make it compile. But you will be able to google that using the snippets above.

The code above copies the menu strings to flash memory and retrieves them from there rather than the very limited RAM. This leaves RAM for running programs rather than storing text.

Thanks for the replies.

Lemming, your code worked right away. Many thanks

As you are using the print functionality you can avoid using the temporary buffer as the Print library can handle PROGMEM data. It needs a little help, but still worth it if ram is tight.

//in file scope
#define PGMSTR __FlashStringHelper*

//In your code:
lcd.setCursor(0, j);
lcd.print( ( PGMSTR ) pgm_read_word(&menu_table[i]) );

I already have an array ( menuList ) that I use for the menu items so I did not need the buffer:

// Main Menu
PROGMEM const char menu_10[] = "DropControl v0.1  ";
PROGMEM const char menu_11[] = "QUICK MODE ";
PROGMEM const char menu_12[] = "FULL MODE ";
PROGMEM const char menu_13[] = "DROP INFO ";
PROGMEM const char menu_14[] = "SET TRIGGER DELAY ";
PROGMEM const char menu_15[] = "SET LOOP DELAY ";
PROGMEM const char menu_16[] = "DRAIN ";
PROGMEM const char menu_17[] = "LOAD/SAVE ";
PROGMEM const char menu_18[] = "ABOUT ";

PROGMEM const char* const menu_main[] = 	   
{   
  menu_10,
  menu_11,
  menu_12,
  menu_13,
  menu_14,
  menu_15,  
  menu_16,
  menu_17,
  menu_18
};

in the main loop:

          numMenuItems = 8;
          for (int i=0; i<numMenuItems+1; i++)
          {
                 strcpy_P(menuList[i], (char*)pgm_read_word(&menu_main[i]));
          }

Seems to be working well and I have gone from no ram to over 400 bytes free by copying the menus to PROGMEM

I can’t see all your code (because you haven’t posted it) but isn’t this

for (int i=0; i<numMenuItems+1; i++)
          {
                 strcpy_P(menuList[i], (char*)pgm_read_word(&menu_main[i]));
          }

more-or-less doing just what crt0 does?

I've no idea.

You've saved a whole lot of RAM by putting your arrays in flash memory but then waste it all by loading their contents into a similar (and wasteful) sized array stored in RAM thereby negating your memory savings.

Get rid of menuList[] and use the the data direct from the PROGMEM array as shown in my snippets or those by pyro_65.

There are several problems with your original post, that I can see.

The first problem is that your array would have to be sized for the largest of all the strings you want to put in it. That wastes a lot of space.

And the second problem is that you have 9 strings not 8.

lemming: You've saved a whole lot of RAM by putting your arrays in flash memory but then waste it all by loading their contents into a similar (and wasteful) sized array stored in RAM thereby negating your memory savings.

Get rid of menuList[] and use the the data direct from the PROGMEM array as shown in my snippets or those by pyro_65.

I realize this but the menu function I wrote uses the menuList array and would need a major rewrite to remove it. For now my main concern has been addressed; I ran out of memory and with your help I have regained some of it. My initial goal is to get the program finished. Once I have it finished and fully working I can revisit the menu function. I am still very new to the Arduino and C/C++ so I sometimes I have to compromise so I can progress.

michinyon: There are several problems with your original post, that I can see.

The first problem is that your array would have to be sized for the largest of all the strings you want to put in it. That wastes a lot of space.

The wasted space was a trade off. At the time I wrote the menu function I did not know about pointers and I was having trouble with strings. Later I will update the menu function.

michinyon: And the second problem is that you have 9 strings not 8.

This is due to how my menu function works. Element 0 is a static title that does not scroll. Elements 1-8 are the actual menu options which scroll up and down. Therefore, actual menu items = 8. I found it easier to work this way.