Progmem Example , No Joy

:stuck_out_tongue_closed_eyes:
I am trying to figure out how to use PROGMEM.
I tried different short routines of my own and gave p.
Then I copied (cut and paste) the example from the downloaded Arduno Reference (The on line version does not have PROGMEM).
I compiled and uploaded it.
Same results that I had with the code that I tried to write: NADA ....

/*
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.
PGM_P PROGMEM 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 );
}
}

and yes I opened the serial monitor ... sent nice characters to it and asked it nicely for it to respond.

Still it ignored me (probably a female program).

and yes I opened the serial monitor ... sent nice characters to it and asked it nicely for it to respond.

That code will not look at anything you type into the serial monitor.
You can not program anything into program memory at run time unless the code is in the boot loader section.
Do not have code in the loop function that continuously writes to EEPROM or program memory as this will rapidly exceed the permitted number of writes.
Please link the on line tutorial you are trying to follow.

Grumpy_Mike:
That code will not look at anything you type into the serial monitor.

Believe it or not, I know that ... but I was desperate to get its attention.
So I thought it was worth a try.
Sort of like asking it politely to work. That did not work either.

Please link the on line tutorial you are trying to follow.

It is in the DOWNLOAD version of the reference guide.
The online version does not have PROGMEM listed ... but google found it:

It is about halfway down the page listed under "Arrays of strings".

This version works! I took out the DEPRECATED typedef usage and moved the PROGMEM define to the end of each type. I suspect that the PROGMEM was not modifying the right declaration when it was part of the typedef so the table or the data was not being placed in PROGMEM.

See: avr-libc: <avr/pgmspace.h>: Program Space Utilities

/*
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  string_0[] PROGMEM = "String 0"; // "String 0" etc are strings to store - change to suit.
char  string_1[] PROGMEM = "String 1";
char  string_2[] PROGMEM = "String 2";
char  string_3[] PROGMEM = "String 3";
char  string_4[] PROGMEM = "String 4";
char  string_5[] PROGMEM = "String 5";
// Then set up a table to refer to your strings.
const char *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, (char*)pgm_read_word(&(string_table[i]))); // Necessary casts and dereferencing, just copy.
    Serial.println( buffer );
    delay( 500 );
  }
}

johnwasser:
This version works!

Yep, I confirm that.
Thank you :slight_smile: :slight_smile: :slight_smile: :slight_smile:

As far as can tell you changed the line from:

PGM_P PROGMEM string_table[] = // change "string_table" name to suit

to:

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

did I miss anything else ??

OK ... Now I see that you also changed the lines above ..... da.

Can this be done without defining an array of strings ?
Example: a single null terminated string ?

char AlphaSoup[] PROGMEM = "ABCDEFHIJKLMNOPQRSTUVWXYZ";
const char Soup PROGMEM = {AlphaSoup};
.....
strcpy_P(buffer, (char
)pgm_read_word(&(Soup)));


it is a shame that the syntax could not be something a bit simpler like strcpy_P(Soup);

I will answer my own question: yes :slight_smile:

/*	Program: Hello World in four languages */

/* Include function to use flash memory for fixed data storage */
#include <avr/pgmspace.h>
char HelpStr[] PROGMEM = "E=English, F=French, S=Spanish, I=Italian, A=All";
char EnglishGreetingStr[] PROGMEM = "Hello World";
char FrenchGreetingStr[]  PROGMEM = "Bonjour tout le monde";
char SpanishGreetingStr[] PROGMEM = "Hola mundo";
char ItalianGreetingStr[] PROGMEM = "Ciao mondo";

const char *Language[] PROGMEM = // change "string_table" name to suit
{ EnglishGreetingStr,
  FrenchGreetingStr,
  SpanishGreetingStr,
  ItalianGreetingStr };

const char *English PROGMEM = {EnglishGreetingStr};
const char *French PROGMEM = {FrenchGreetingStr};
const char *Spanish PROGMEM = {SpanishGreetingStr};
const char *Italian PROGMEM = {ItalianGreetingStr};
const char *HelpMe PROGMEM = {HelpStr};

/* now we need area in RAM to use the strings */
char OutBuffer[60];

char junk;         // incoming serial byte

void setup() 
{ /* run once */ 
  Serial.begin(9600); // This sets up a serial connection, 9.6 kbts/s.
  /* wait for serial port to connect. Needed for Leonardo only */
  while (!Serial) { ; }
  Serial.println (F("Enter: E, F, S, I or A"));
  Serial.println ("");
}
 
void loop() 
{ /* loop until the end of time */
  if (Serial.available() > 0) 
  {
     /* get incoming byte */
     junk = Serial.read();
     /* Serial.println( junk );  */
     strcpy_P(OutBuffer, (char*)pgm_read_word(&(HelpMe)));
     if (junk == 'E')
       { strcpy_P(OutBuffer, (char*)pgm_read_word(&(English)));}
     if (junk == 'F')
       { strcpy_P(OutBuffer, (char*)pgm_read_word(&(French)));}
     if (junk == 'S')
       { strcpy_P(OutBuffer, (char*)pgm_read_word(&(Spanish)));}
     if (junk == 'I')
       { strcpy_P(OutBuffer, (char*)pgm_read_word(&(Italian)));}
     if (junk == 'A')
       { for (int i = 0; i < 4;  i++)
           { strcpy_P(OutBuffer, (char*)pgm_read_word(&(Language[i])));
             Serial.println( OutBuffer );
           }
       }
     else
       { Serial.println( OutBuffer );
       }
  }
}

lewtwo:
I will answer my own question: yes :slight_smile:

If you are not going to reference the string by number (index in the array) there is no advantage to store the address (pointer) in PROGMEM and fetch it out again. It just uses up PROGMEM: two bytes for the pointer plus instructions to call pgm_read_word().

void loop() 
{ /* loop until the end of time */
  if (Serial.available() > 0) 
  {
    /* get incoming byte */
    junk = Serial.read();
    /* Serial.println( junk );  */
    strcpy_P(OutBuffer, HelpStr);
    if (junk == 'E') { 
      strcpy_P(OutBuffer, EnglishGreetingStr);
    }
    else
    if (junk == 'F') { 
      strcpy_P(OutBuffer, FrenchGreetingStr);
    }
    else
    if (junk == 'S') { 
      strcpy_P(OutBuffer, SpanishGreetingStr);
    }
    else
    if (junk == 'I') { 
      strcpy_P(OutBuffer, ItalianGreetingStr);
    }
    Serial.println( OutBuffer );
  }
}

And if you only use each string for only one Serial.println() you can save code by using the F() macro:

    if (junk == 'E') { 
      Serial.println(F("Hello World"));
    }

The advantage is in learning how to actually get it to work and then try to understand exactly what is happening.

00000099 <EnglishGreetingStr>:
  99:	48 65 6c 6c 6f 20 57 6f 72 6c 64 00                 Hello World.

000000a5 <FrenchGreetingStr>:
  a5:	42 6f 6e 6a 6f 75 72 20 74 6f 75 74 20 6c 65 20     Bonjour tout le 
  b5:	6d 6f 6e 64 65 00                                   monde.

000000bb <SpanishGreetingStr>:
  bb:	48 6f 6c 61 20 6d 75 6e 64 6f 00                    Hola mundo.

000000c6 <ItalianGreetingStr>:
  c6:	43 69 61 6f 20 6d 6f 6e 64 6f 00                    Ciao mondo.

000000d1 <Language>:
  d1:	99 00 a5 00 bb 00 c6 00                             ........

000000d9 <English>:
  d9:	99 00                                               ..

000000db <French>:
  db:	a5 00                                               ..

000000dd <Spanish>:
  dd:	bb 00                                               ..

000000df <Italian>:
  df:	c6 00                                               ..

Dean has some good tutorials on avr-gcc behavior:

Ray

that site is not responding at this time :drooling_face: