Go Down

Topic: PROGMEM Example needs "const" (Read 7757 times) previous topic - next topic

glenhawx

Hi,
I am relatively new to Arduino, less than a year.
I am having problems learning how to use PROGMEM. I have an OLED screen and have been playing with the "lorem_ipsum" example but that is my limit with using PROGMEM.

I want to learn more so I found this, http://arduino.cc/en/Reference/PROGMEM, example...
Code: [Select]
/*
 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>
prog_char string_0[] PROGMEM = "String 0";   // "String 0" etc are strings to store - change to suit.
prog_char string_1[] PROGMEM = "String 1";
prog_char string_2[] PROGMEM = "String 2";
prog_char string_3[] PROGMEM = "String 3";
prog_char string_4[] PROGMEM = "String 4";
prog_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 );
  }
}

...but when I try to run the array example I get these errors...
Code: [Select]
ProgmemTest.ino:12:18: error: variable 'string_0' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
ProgmemTest.ino:13:18: error: variable 'string_1' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
ProgmemTest.ino:14:18: error: variable 'string_2' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
ProgmemTest.ino:15:18: error: variable 'string_3' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
ProgmemTest.ino:16:18: error: variable 'string_4' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
ProgmemTest.ino:17:18: error: variable 'string_5' must be const in order to be put into read-only section by means of '__attribute__((progmem))'
ProgmemTest.ino:19:28: error: variable 'string_table' must be const in order to be put into read-only section by means of '__attribute__((progmem))'


I have changed the lines like this...
Code: [Select]
prog_char string_1[] PROGMEM = "String 1";
...to ones like this...
Code: [Select]
prog_char const string_1[] PROGMEM = "String 1";
...and I can eliminate most of the errors but I don't know how to change this line...
Code: [Select]
PROGMEM const char *string_table[] =

I have tried many hours to google a solution and all I can find is:
  • It could be something to do with the version of the IDE I have (1:1.0.5+dfsg2-1)
  • it could be something to do with "prog_char" (dunno how this affects the string_table line)
  • it could be something to do with the gcc compiler on my PC (?)

Ultimately I am lost and I need a working example to tinker with so that I can learn how to use it.
Can anyone help me?
Cheers,
Glen

Arduino IDE running on Linux Mint
Testing with a LeoStick but I also have an Eleven if it could possibly be board related

jboyton

Not much help but a data point: It compiles without complaint for me, using 1.0.5 on OS X.

glenhawx

well that sucks, for me anyway :-(

What board are you using?

glenhawx

#3
Nov 06, 2014, 03:18 am Last Edit: Nov 06, 2014, 03:20 am by glenhawx
I got it to work. I found this page... http://www.nongnu.org/avr-libc/user-manual/pgmspace.html
... and I changed my code to...
Code: [Select]
/*
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>
char const string_0[] PROGMEM = "String 0"; // "String 0" etc are strings to store - change to suit.
char const string_1[] PROGMEM = "String 1";
char const string_2[] PROGMEM = "String 2";
char const string_3[] PROGMEM = "String 3";
char const string_4[] PROGMEM = "String 4";
char const string_5[] PROGMEM = "String 5";
// Then set up a table to refer to your strings.
PGM_P const string_table[] PROGMEM = // 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, (PGM_P)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
    Serial.println( buffer );
    delay( 500 );
  }
}



Using the PGM_P function(?) has it working for me although I'm not sure I understand why (especially the original code worked for Jboyton).
I don't know if this is really "solved" but it is for me.
Thanks for your time,
Glen

KenF

Agh, just compiled it under various versions.  Just about to report my findings but...


Too late.  Glad you got it sorted though.

jboyton

Glad you found a way to make it work. I can't help with the mystery. I have a lowly Uno R3 but I think you can compile with IDE thinking you have any board you want. I couldn't find the one you mentioned in the drop down menu though.

pYro_65

#6
Nov 06, 2014, 07:35 am Last Edit: Nov 06, 2014, 09:31 am by pYro_65
Just to ease the confusion:

IDE 1.5.7 and above have a new compiler which requires PROGMEM data to be const. Every other detail regarding PROGMEM is fine.

Always use the version with the PROGMEM after the declaration ( and before the initialization ), and avoid the prog_xxx_t types ( they add PROGMEM before the id) for maximum compatibility. And add const to your declarations now, so when you upgrade or someone else uses your code, it will work without a hitch.

Code: [Select]
int var PROGMEM = 1234;
char pgmArr[] PROGMEM = "foo";


Forum Mod anyone?
https://arduino.land/Moduino/

nickgammon

Code: [Select]
int pgmArr[] PROGMEM = "foo";

?

Quote
And add const to your declarations now ...
Maybe:

Code: [Select]
const char pgmArr[] PROGMEM = "foo";
Please post technical questions on the forum, not by personal message. Thanks!

More info: http://www.gammon.com.au/electronics

pYro_65

Quote
?
lol, changed one side and not the other. It was more to show where I'm intending PROGMEM to be put.
Forum Mod anyone?
https://arduino.land/Moduino/

glenhawx

Other than adding "const" to the PROGMEM lines all I did was change this...

PROGMEM const char *string_table[] =

to this...

PGM_P const string_table[] PROGMEM =

Did I do ok?

pYro_65

Yeah, that is fine.

For clarity, PGM_P is a macro for a constant char pointer, so your actual declaration is:

Code: [Select]
const char str0[] PROGMEM = "String1";
const char str1[] PROGMEM = "String2";
const char * const string_table[] PROGMEM = { str0, str1 };


There are two const keywords. The second one is for the array, so it can be put in PROGMEM. The first is needed to be compatible with the strings passed which are const if put into PROGMEM.
Forum Mod anyone?
https://arduino.land/Moduino/

Go Up