PROGMEM do nothing ?

Hello,

I make a program with huge array. But, array is stored in the program memory using PROGMEM.

like this,

const String Pn[] PROGMEM = {"1 Piano", "2 Piano", "3 Piano", "4 Piano", "5 Piano", "6 Piano", "7 Piano", "8 Piano", "9 Piano", "10 Piano", "11 Piano", "12 Piano", "13 Piano", "14 Piano", "15 Piano", "16 Piano", "17 Piano", "18 Piano", "19 Piano", "20 Piano", "21 Piano", "22 Piano", "23 Piano", "24 Piano", "25 Piano", "26 Piano", "27 Piano", "28 Piano", "29 Piano", "30 Piano", "31 Piano", "32 Piano", "33 Piano", "34 Piano", "35 Piano", "36 Piano", "37 Piano", "38 Piano", "39 Piano", "40 Piano", "41 Piano", "42 Piano", "43 Piano", "44 Piano", "45 Piano", "46 Piano", "47 Piano", "48 Piano", "49 Piano", "50 Piano", "51 Piano", "52 Piano", "53 Piano", "54 Piano", "55 Piano", "56 Piano", "57 Piano", "58 Piano", "59 Piano", "60 Piano", "61 Piano", "62 Piano", "63 Piano", "64 Piano", "65 Piano", "66 Piano", "67 Piano", "68 Piano", "69 Piano", "70 Piano", "71 Piano", "72 Piano", "73 Piano", "74 Piano", "75 Piano", "76 Piano", "77 Piano", "78 Piano", "79 Piano", "80 Piano", "81 Piano", "82 Piano", "83 Piano", "84 Piano", "85 Piano", "86 Piano", "87 Piano", "88 Piano", "89 Piano", "90 Piano", "91 Piano", "92 Piano", "93 Piano", "94 Piano", "95 Piano", "96 Piano", "97 Piano", "98 Piano", "99 Piano", "100 Piano", "101 Piano", "102 Piano", "103 Piano", "104 Piano", "105 Piano", "106 Piano", "107 Piano", "108 Piano", "109 Piano", "110 Piano", "111 Piano", "112 Piano", "113 Piano", "114 Piano", "115 Piano", "116 Piano", "117 Piano", "118 Piano", "119 Piano", "120 Piano", "121 Piano", "122 Piano", "123 Piano", "124 Piano", "125 Piano", "126 Piano", "127 Piano"};

When I uploading the code compiler gives me this,

Sketch uses 12,194 bytes (37%) of program storage space. Maximum is 32,256 bytes.
Global variables use 2,498 bytes (121%) of dynamic memory, leaving -450 bytes for local variables. Maximum is 2,048 bytes.

That means PROGMEM do nothing. :o :o
How can I store my array in program memory?

Thank in advance

String will always be in RAM. A character array can be in flash memory (PROGMEM)

You have to do "extra" to get arrays of things to put the things themselves into PROGMEM. Your current setup puts the pointers to the strings PROGMEM, but not the strings themselves. (I think. I'm not quite sure how it works with C++ String Objects vs regular C strings.) See Dean Camera's Tutorial

I tried to compile this sample program.It uses string array.
I found it from [http://playground.arduino.cc/Main/PROGMEM]

/*
 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 it rises this error,

exit status 1
'prog_char' does not name a type

What is the problem?

prog_char no longer exists. Change it to char.

If you did a simple Google you would have quickly found that prog_char is deprecated. Just use char and the PROMEM keyword.

Then it may work. But remember, like westfw said, you put TWO different things in PROGMEM. string_x is a pointer to a string in PROGMEM. But you put that pointer into a array of pointer again in PROGMEM (string_table). So know you need to use _P handlers twice to access it!

yes..I changed prog_char to char...actually it must be const char.

However Now I have another problem of this line.

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

error is,

variable 'string_table' must be const in order to be put into read-only section by means of '__attribute__((progmem))'

I used google. But, it has complicated answers.

const char *const string_table... I think.

Yep, const char *string_table only tells the compiler it’s a array to const chars. But you want a constant array to constant chars :wink:

septillion: Yep, const char *string_table[] only tells the compiler it's a array to const chars. But you want a constant array to constant chars ;)

I have assign constant char array to const char *string_table[]

const char *string_table[]   = 
{
  string_0,
  string_1,
  string_2,
  string_3,
  string_4,
  string_5
};

string_0,string_1,string_2,string_3,string_4, string_5 are constant array.

westfw:
const char *const string_table…
I think.

It’s Correct.
Now,program is working properly.
But, What is the meaning of that?can you explain?

Did you miss reply #8? ;)

const => we have something that's constant char => of type char * => it's a pointer to that const => and that [u]pointer itself[/u] is constant string_table => and we call it string table [] => and it's an array

This worked last summer and prolly does now.
The major RAM use is in the speed test variables,
// these globals are for a speed test, up to 200 chars
unsigned long testMicros[ 200 ], elapsed; // 804 bytes
char inBuf[ 200 ]; // + 200
byte stateBuf[ 200 ], retBuf[ 200 ], testIdx; // + 401 = 1405 bytes of 1630 bytes as globals

The name of an array is a pointer to the array.

// Dictionary_Match_1_Speed_Test by GoForSmoke @ Arduino Forum
// Free for use, June 6th, 2016
// This sketch uses Arduino source generated by Dictionary_Table_Maker_1.
// Use the Table Maker to change keywords, paste the monitor output into
// the sketch that will use the match() function with your new words. 

#include <avr/io.h>
#include <avr/pgmspace.h>

// these variables are here to ward off the WinXP bug! They will get optimized out.
int a, b, c, d, e, f;
char g;
char h;
char i;

const uint8_t keys = 16;

const char key000[] PROGMEM  = "memccpy";
const byte branch000[] PROGMEM  = { 255,255,255,4,1,255,255 };
const char key001[] PROGMEM  = "memchr";
const byte branch001[] PROGMEM  = { 255,255,255,4,2,255 };
const char key002[] PROGMEM  = "memcmp";
const byte branch002[] PROGMEM  = { 255,255,255,4,3,255 };
const char key003[] PROGMEM  = "memcpy";
const byte branch003[] PROGMEM  = { 255,255,255,4,255,255 };
const char key004[] PROGMEM  = "memmem";
const byte branch004[] PROGMEM  = { 255,255,255,6,5,255 };
const char key005[] PROGMEM  = "memmove";
const byte branch005[] PROGMEM  = { 255,255,255,6,255,255,255 };
const char key006[] PROGMEM  = "memrchr";
const byte branch006[] PROGMEM  = { 255,255,255,7,255,255,255 };
const char key007[] PROGMEM  = "memset";
const byte branch007[] PROGMEM  = { 255,255,255,255,255,255 };
const char key008[] PROGMEM  = "strcat";
const byte branch008[] PROGMEM  = { 255,255,255,12,9,255 };
const char key009[] PROGMEM  = "strchr";
const byte branch009[] PROGMEM  = { 255,255,255,12,10,255 };
const char key010[] PROGMEM  = "strcmp";
const byte branch010[] PROGMEM  = { 255,255,255,12,11,255 };
const char key011[] PROGMEM  = "strcpy";
const byte branch011[] PROGMEM  = { 255,255,255,12,255,255 };
const char key012[] PROGMEM  = "strlen";
const byte branch012[] PROGMEM  = { 255,255,255,14,13,255 };
const char key013[] PROGMEM  = "strlwr";
const byte branch013[] PROGMEM  = { 255,255,255,14,255,255 };
const char key014[] PROGMEM  = "strstr";
const byte branch014[] PROGMEM  = { 255,255,255,15,255,255 };
const char key015[] PROGMEM  = "strupr";
const byte branch015[] PROGMEM  = { 255,255,255,255,255,255 };

PGM_P const key_list[ keys ] PROGMEM = {
  key000,key001,key002,key003,key004,key005,key006,key007,
  key008,key009,key010,key011,key012,key013,key014,key015
};

const uint8_t * const branch_list[ keys ] PROGMEM = {
  branch000,branch001,branch002,branch003,branch004,branch005,branch006,branch007,
  branch008,branch009,branch010,branch011,branch012,branch013,branch014,branch015
};

const uint8_t startChar[ 52 ] PROGMEM =
{
  255,255,255,255,255,255,255,255,255,255,255,255,255, // A-M
  255,255,255,255,255,255,255,255,255,255,255,255,255, // N-Z
  255,255,255,255,255,255,255,255,255,255,255,255,0, // a-m
  255,255,255,255,255,8,255,255,255,255,255,255,255 // n-z
};



PGM_P current_key;
const uint8_t * current_branch;
char data, notDone, done;


uint8_t state; // 0 = waiting, 1 = matching, 2 = matched, 4 = no match
uint8_t charsMatched;
char charToMatch;
uint8_t wordIndex, idx;
uint8_t matchRet;

uint8_t match( char txtChr ) // returns matched word number or 255 if none
{
  if (( state == 2 ) || ( state == 4 )) return 255;

  if ( txtChr < 'A' ) // anything less than A is now a delimiter
  {
    charsMatched = state = 0;
  }
  else if (( txtChr >= 'A' && txtChr <= 'Z' ) || ( txtChr >= 'a' && txtChr <= 'z' )) // legal
  {
    switch ( state )
    {
      case 0 : // 0 = waiting, get 1st char
      case 2 : // last word matched, new word starts
        if ( txtChr < 'a' ) idx = txtChr - 'A';
        else                idx = txtChr - 'a' + 26;

        wordIndex = pgm_read_byte( startChar + idx );
        if ( wordIndex == 255 )
        {
          charsMatched = 0;
          state = 4;
        }
        else
        { // current_key now points to the 1st char matched word in PROGMEM
          current_key = (PGM_P)pgm_read_word( key_list + wordIndex );
          current_branch = (const uint8_t *)pgm_read_word( branch_list + wordIndex );
          charsMatched = 1;
          state = 1;
        }
        break;

      case 1 :
        idx = 1; // used as a search branches flag in this case
        while (( state == 1 ) && ( idx ))
        {
          charToMatch = pgm_read_byte( current_key + charsMatched );

          if ( txtChr == charToMatch )
          {
            charsMatched++;
            idx = 0;
            charToMatch = pgm_read_byte( current_key + charsMatched );
            if ( charToMatch == 0 )
            {
              state = 2;
            }
          }
          else
          {
            wordIndex = pgm_read_byte( current_branch + charsMatched );
            if ( wordIndex == 255 )
            {
              charsMatched = 0;
              state = 4;
            }
            else
            {
              current_key = (PGM_P)pgm_read_word( key_list + wordIndex );
              current_branch = (const uint8_t *)pgm_read_word( branch_list + wordIndex );
            }
          }
        }
        break;

      default :  //  4 = no match, let it read till delimiter.
        break;
    }
  }
  else
  {
    charsMatched = 0;
    state = 4;
  }

  if ( state == 2 )   return wordIndex;
  else                return 255;
}


void setup()
{
  Serial.begin( 250000 );
  Serial.println( F( "\n\n\n\nTEST\n" ));

  for ( idx = 0; idx < keys; idx++ )
  {
    Serial.println((__FlashStringHelper*) (PGM_P)pgm_read_word( key_list + idx ));
  }
  Serial.println();
}

// these globals are for a speed test, up to 200 chars
unsigned long testMicros[ 200 ], elapsed;
char inBuf[ 200 ];
byte stateBuf[ 200 ], retBuf[ 200 ], testIdx;

void loop()
{
  if ( testIdx > 1 ) // input timeout locks sketch after 1 second break in serial input
  {
    if (( micros() - testMicros[ testIdx - 1 ] > 100000UL ) || ( testIdx == 200 ))
    {
      Serial.println( "TEST OUTPUT\n" );
      for ( byte i = 0; i < testIdx; i++ )
      {
        if ( !i )
        {
          Serial.print( "0" );
        }
        else
        {
          Serial.print( testMicros[ i ] - testMicros[ i - 1 ] );
        }
        Serial.print( "   " );
        if ( inBuf[ i ] < 'A' )
        {
          Serial.print( inBuf[ i ], DEC );
        }
        else
        {
          Serial.print( inBuf[ i ] );
        }
        Serial.print( "   " );
        Serial.print( stateBuf[ i ] );
        Serial.print( "   " );
        Serial.println( retBuf[ i ] );

      }
      while ( 1 );
    }
  }

  if ( Serial.available())
  {
    data = Serial.read();
    testMicros[ testIdx ] = micros();
    inBuf[ testIdx ] = data;
    stateBuf[ testIdx ] = state;

    if (( data == '\n' ) || ( data == ' ' )) // end of line delimiter is ASCII newline
    {
      state = 0;
    }
    else
    {
      matchRet = match( data );
      if ( matchRet < 255 )
      {
        //        Serial.print( "Matched word # " );
        //        Serial.print( matchRet );
        //        Serial.print( "  " );
        //        Serial.println((__FlashStringHelper*) (PGM_P)pgm_read_word( key_list + matchRet ));
        //        Serial.println();
      }
    }
    retBuf[ testIdx++ ] = matchRet;
  }
}