Problem with reading back from PROGMEM, HELP?

I want to store a lot of strings for displaying it on an LCD, so first I do this:

prog_char string_0[] PROGMEM = "1-Tempo";
prog_char string_1[] PROGMEM = "2-Lider gordo";
prog_char string_2[] PROGMEM = "3-Envolvente";
prog_char string_3[] PROGMEM = "3b-Forma de env";
... etc etc
prog_char string_34[] PROGMEM = "C#";
prog_char string_35[] PROGMEM = "C";
prog_char string_36[] PROGMEM = "B";
prog_char string_37[] PROGMEM = "A#";
prog_char string_38[] PROGMEM = "A";

PROGMEM const char *menuOption[] = {string_0,string_1,string_2,string_3,... etc etc ,string_38};
char buffer[16];

then when I want to display one of the strings on the LCD:

strcpy_P(buffer, (char*)pgm_read_word(&(menuOption[21])));

and that seems to work fine.

but when I want to return one of those strings back from a function I get a strange behavior

String getNoteName(int pitch){
  int oct = ((pitch-33)/12)+1; //33=A1
  int noteNumb = pitch-((12*(oct+2))-3);
  noteNumb=noteNumb+38; //Index 38 is A, 37 is A#, 36 is B and so on...
  String noteName;
  strcpy_P(buffer, (char*)pgm_read_word(&(menuOption[noteNumb])));  //    <--- THIS LINE IS TROUBLE!
  noteName = String(buffer);
  return noteName;

What that function does is you give it the note number and it returns the note name, for example “A4”. The problem is that the line I point there is, somehow, changing the value for menuIndex when I do this:

  strcpy_P(buffer, (char*)pgm_read_word(&(menuOption[menuIndex])));

also when I print buffer to Serial it prints this:

? ?? ?? ?? ?? ?? ?X ? ?ü ?C ?? ?? ?? ?? ?? ??acB6·?ا9hV®º«U?<·ÌWc½míýu>ör1?

Any idea??? Very weird, I am not writing on the memory, always reading… or that is what I intend…
Could it be that I am getting low on memory? my sketch is 19.300 bytes according to the bottom of the compiler

now, I “commented” some of the definition lines of PROGMEM at the beginning to check if it was memory problem and also I added this on the trouble line:

  printLog("menuIndex",menuIndex); // <--- ADDED THIS
  strcpy_P(buffer, (char*)pgm_read_word(&(menuOption[noteNumb])));  //    <--- THIS LINE IS TROUBLE
  printLog("menuIndex",menuIndex); // <--- ADDED THIS

Its giving me trash on the Serial Monitor, and the programm crashes (on Arduino), it doesn’t responds anymore.


I dont think your saving anything by putting such short strings as note names in progmem, also you should not be using the string class, if you search you will find many threads explaining why not. try one of the alternatives and if you still have a problem, ask again.

Duane B

I used the example for Strings documented here:
The problem seems to be giving it a variable instead of a constant where it is “i” here:

strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i])));

I really don’t know why it does that, here it is used like that and it is suposed to work fine:

  for (int i = 0; i < 6; i++)
    strcpy_P(buffer, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy. 
    Serial.println( buffer );
    delay( 500 );

Anyway… I resolved it by putting a number instead of “i”

Its this string you should not use -

  String noteName; // this is the string class
  strcpy_P(buffer, (char*)pgm_read_word(&(menuOption[noteNumb])));  //    <--- THIS LINE IS TROUBLE!
  noteName = String(buffer); // and here your initialising one, then copying it and discarding it

Basically the String class is fine on larger systems that have ‘garbage collection’ Arduino does not and you should not use the String class it will allocate all of your memory in minutes specially the way you are using it.

If you have a look at the code I posted today for my laptimer build along, I am using program memory and a single static buffer that I use to copy progmem strings into whenever I need them. My way is not the best I am sure, but using a static buffer is your best bet in Arduino land.

// example from rcarduino Lap Timer build along -
char * getRamString(PGM_P pString)
  static char pBuffer[DISPLAY_ROW_BUFFER_LENGTH];
  return strcpy_P(pBuffer,pString);

And another function I use for formatting the time -
This is ugly, but I know the max length and format of the string, its a fixed format
You should use a similarly fixed format and fixed buffer size, then you can reuse your
buffer. If you need different buffers for different data its not a disaster as long as they are small and there are too many of them.

// turn a lap_time_t into a time string formatted as - m:ss:dd
// bPrecision turns 100's on or off
char* CLapTimes::formatTime(lap_time_t time,unsigned char bPrecision)
  char *pResult = NULL;
  lap_time_t nSeconds = time/100;
  lap_time_t nMinutes = nSeconds/60;
  lap_time_t nHundredths = 0;
  if(nMinutes <= 9)
      nHundredths = time - (nSeconds*100);

    nSeconds -= (nMinutes * 60);   
    m_pTimeStringBuffer[7] = 0;
    m_pTimeStringBuffer[6] = (nHundredths%10)+'0';
    m_pTimeStringBuffer[5] = (nHundredths/10)+'0';
    m_pTimeStringBuffer[4] = '.';
    m_pTimeStringBuffer[3] = (nSeconds%10)+'0';
    m_pTimeStringBuffer[2] = (nSeconds/10)+'0';
    m_pTimeStringBuffer[1] = ':';
    m_pTimeStringBuffer[0] = nMinutes + '0';    
    pResult = m_pTimeStringBuffer;
  return pResult;
char CLapTimes::m_pTimeStringBuffer[9];/*m:ss:dd - dd represents hundredths of a second */

Duane B