string array must be const in order to be put into read-only section

Hi,

I followed the example from here and whenever I try to compile it gives me this error:

Arduino:1.6.8 (Linux), Kort:"Arduino/Genuino Uno"

/usr/share/arduino/arduino-builder -dump-prefs -logger=machine -hardware "/usr/share/arduino/hardware" -tools "/usr/share/arduino/tools-builder" -tools "/usr/share/arduino/hardware/tools/avr" -built-in-libraries "/usr/share/arduino/libraries" -libraries "/home/linkan/Arduino/libraries" -fqbn=arduino:avr:uno -vid-pid=0X2341_0X0043 -ide-version=10608 -build-path "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp" -warnings=none -prefs=build.warn_data_percentage=75 -verbose "/tmp/arduino_modified_sketch_902022/sketch_apr15c.ino"
/usr/share/arduino/arduino-builder -compile -logger=machine -hardware "/usr/share/arduino/hardware" -tools "/usr/share/arduino/tools-builder" -tools "/usr/share/arduino/hardware/tools/avr" -built-in-libraries "/usr/share/arduino/libraries" -libraries "/home/linkan/Arduino/libraries" -fqbn=arduino:avr:uno -vid-pid=0X2341_0X0043 -ide-version=10608 -build-path "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp" -warnings=none -prefs=build.warn_data_percentage=75 -verbose "/tmp/arduino_modified_sketch_902022/sketch_apr15c.ino"
Board arduino:avr:gert328 doesn't define a 'build.board' preference. Auto-set to: AVR_GERT328
Board arduino:avr:gert168 doesn't define a 'build.board' preference. Auto-set to: AVR_GERT168
Build options changed, rebuilding all
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp/sketch/sketch_apr15c.ino.cpp" -o "/dev/null"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp/sketch/sketch_apr15c.ino.cpp" -o "/dev/null"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp/sketch/sketch_apr15c.ino.cpp" -o "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp/preproc/ctags_target_for_gcc_minus_e.cpp"
"/usr/share/arduino/tools-builder/ctags/5.8-arduino10/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp/preproc/ctags_target_for_gcc_minus_e.cpp"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp/sketch/sketch_apr15c.ino.cpp" -o "/tmp/build91ff1c644f5f1cf1c06da9db071018ab.tmp/sketch/sketch_apr15c.ino.cpp.o"
sketch_apr15c:27: error: variable 'string_table' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
 PROGMEM const char *string_table[] =     // change "string_table" name to suit
                                  ^
exit status 1
variable 'string_table' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

The code is as following:

/*
 PROGMEM string demo
 How to store a table of strings in program memory (flash), 
 and retrieve them.

 Information summarized from:
 http://www.nongnu.org/avr-libc/user-manual/pgmspace.html

 Setting up a table (array) of strings in program memory is slightly complicated, but
 here is a good template to follow. 

 Setting up the strings is a two-step process. First define the strings.

*/

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0";   // "String 0" etc are strings to store - change to suit.
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";


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

PROGMEM const char *string_table[] =     // change "string_table" name to suit
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5 };

char buffer[30];    // make sure this is large enough for the largest string it must hold

void setup()        
{
  Serial.begin(9600);
}


void loop()       
{
  /* Using the string table in program memory requires the use of special functions to retrieve the data.
     The strcpy_P function copies a string from program space to a string in RAM ("buffer"). 
     Make sure your receiving string in RAM  is large enough to hold whatever
     you are retrieving from program space. */


  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 );
  }
}

What am I doing wrong?

What am I doing wrong?

Not dealing with the error message. What is so hard to understand?

The FIRST qualifier must be const, not the second one.

PaulS: Not dealing with the error message. What is so hard to understand?

The FIRST qualifier must be const, not the second one.

If this is what you mean:

const char *string_table[] PROGMEM =     // change "string_table" name to suit
{   
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5 };

That doesn't work either.

This compiles.

const char string_table[][10] PROGMEM =     // change "string_table" name to suit
{   
  "string_0",
  "string_1",
  "string_2",
  "string_3",
  "string_4",
  "string_5" 
};

SurferTim: This compiles.

const char string_table[][10] PROGMEM =     // change "string_table" name to suit
{   
  "string_0",
  "string_1",
  "string_2",
  "string_3",
  "string_4",
  "string_5" 
};

Can I do the same thing without having to define the outer array size?

I don't think so. It needs that dimension to compute the multi-dimensional array size. You might want to play with declaring all those as const character arrays, then use a pointer to the arrays in the string_table array. I haven't tried it.

SurferTim:
I don’t think so. It needs that dimension to compute the multi-dimensional array size. You might want to play with declaring all those as const character arrays, then use a pointer to the arrays in the string_table array. I haven’t tried it.

Actually doing it that way doesn’t work for me. This is the code I am using:

#include <avr/pgmspace.h>

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

const char string_table[][10] PROGMEM =     // change "string_table" name to suit
{   
  "string_0",
  "string_1",
  "string_2",
  "string_3",
  "string_4",
  "string_5"
};

char buf[30];    // make sure this is large enough for the largest string it must hold

void setup()        
{
  Serial.begin(9600);
}


void loop()       
{
  /* Using the string table in program memory requires the use of special functions to retrieve the data.
     The strcpy_P function copies a string from program space to a string in RAM ("buffer"). 
     Make sure your receiving string in RAM  is large enough to hold whatever
     you are retrieving from program space. */

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

When looking in the serial monitor, I see no output at all.

This works. I changed the baud to 115200 because that is what I normally use:

const char string_table[][10] PROGMEM =     // change "string_table" name to suit
{   
  "string_0",
  "string_1",
  "string_2",
  "string_3",
  "string_4",
  "string_5"
};

char buf[30];    // make sure this is large enough for the largest string it must hold

void setup()       
{
  Serial.begin(115200);
}


void loop()       
{

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

SurferTim:
This works. I changed the baud to 115200 because that is what I normally use:

const char string_table[][10] PROGMEM =     // change "string_table" name to suit

{  
 “string_0”,
 “string_1”,
 “string_2”,
 “string_3”,
 “string_4”,
 “string_5”
};

char buf[30];    // make sure this is large enough for the largest string it must hold

void setup()      
{
 Serial.begin(115200);
}

void loop()      
{

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

Thanks it works with small arrays, however I have a very large array and it gives me this error:

Arduino:1.6.8 (Linux), Kort:"Arduino/Genuino Uno"

/usr/share/arduino/arduino-builder -dump-prefs -logger=machine -hardware "/usr/share/arduino/hardware" -tools "/usr/share/arduino/tools-builder" -tools "/usr/share/arduino/hardware/tools/avr" -built-in-libraries "/usr/share/arduino/libraries" -libraries "/home/linkan/Arduino/libraries" -fqbn=arduino:avr:uno -vid-pid=0X2341_0X0043 -ide-version=10608 -build-path "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp" -warnings=none -prefs=build.warn_data_percentage=75 -verbose "/home/linkan/Arduino/playlist/playlist.ino"
/usr/share/arduino/arduino-builder -compile -logger=machine -hardware "/usr/share/arduino/hardware" -tools "/usr/share/arduino/tools-builder" -tools "/usr/share/arduino/hardware/tools/avr" -built-in-libraries "/usr/share/arduino/libraries" -libraries "/home/linkan/Arduino/libraries" -fqbn=arduino:avr:uno -vid-pid=0X2341_0X0043 -ide-version=10608 -build-path "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp" -warnings=none -prefs=build.warn_data_percentage=75 -verbose "/home/linkan/Arduino/playlist/playlist.ino"
Board arduino:avr:gert168 doesn't define a 'build.board' preference. Auto-set to: AVR_GERT168
Board arduino:avr:gert328 doesn't define a 'build.board' preference. Auto-set to: AVR_GERT328
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/sketch/playlist.ino.cpp" -o "/dev/null"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "-I/usr/share/arduino/libraries/LiquidCrystal/src" "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/sketch/playlist.ino.cpp" -o "/dev/null"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "-I/usr/share/arduino/libraries/LiquidCrystal/src" "/usr/share/arduino/libraries/LiquidCrystal/src/LiquidCrystal.cpp" -o "/dev/null"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "-I/usr/share/arduino/libraries/LiquidCrystal/src" "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/sketch/playlist.ino.cpp" -o "/dev/null"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics  -w -x c++ -E -CC -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "-I/usr/share/arduino/libraries/LiquidCrystal/src" "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/sketch/playlist.ino.cpp" -o "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/preproc/ctags_target_for_gcc_minus_e.cpp"
"/usr/share/arduino/tools-builder/ctags/5.8-arduino10/ctags" -u --language-force=c++ -f - --c++-kinds=svpf --fields=KSTtzns --line-directives "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/preproc/ctags_target_for_gcc_minus_e.cpp"
"/usr/share/arduino/hardware/tools/avr/bin/avr-g++" -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10608 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR   "-I/usr/share/arduino/hardware/arduino/avr/cores/arduino" "-I/usr/share/arduino/hardware/arduino/avr/variants/standard" "-I/usr/share/arduino/libraries/LiquidCrystal/src" "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/sketch/playlist.ino.cpp" -o "/tmp/buildcea453dc151950b76555246e62f43ed3.tmp/sketch/playlist.ino.cpp.o"
In file included from /home/linkan/Arduino/playlist/playlist.ino:6:0:
songs.h:125: error: size of variable 'song_data' is too large
 const char song_data[][700] PROGMEM = {
            ^
Using library LiquidCrystal at version 1.0.5 in folder: /usr/share/arduino/libraries/LiquidCrystal 
exit status 1
size of variable 'song_data' is too large

My array (very large) http://pastebin.com/Ap5s6fan

I think the problem is that it uses 700 bytes for every string, but only a few are bigger than 500 bytes. 700*58 > 32kb. How can I store this much data?

That is why I have a Mega 2560 and a Due. You could probably use a SD card. SD modules are cheap, but insure you get one with a logic level converter on it to avoid some unnecessary grief.

SurferTim: That is why I have a Mega 2560 and a Due. You could probably use a SD card. SD modules are cheap, but insure you get one with a logic level converter on it to avoid some unnecessary grief.

Sure, but wouldn't it be possible to just store it as big chunk of memory and have another array with the positions of each substring and just place a nul-terminator inbetween every string? I'm not able to buy the arduono SD card module currently.