Compile errors with Progmem

I am getting a compile error with a sketch that uses Progmem in particular a CRC32 example from this post Arduino Forum. I am getting the error:

prog_uint32_t does not name a type

for this code:

static PROGMEM prog_uint32_t crc_table[16] = {
    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    ...etc...
};

Other folks have obviously gotten this to work but not me.....! Any help would be greatly appreciated.

static PROGMEM prog_uint32_t crc_table[16] = {

I wouldn’t use static to declare a PROGMEM table. Static is for RAM.
Maybe

uint32_t PROGMEM table[16] = { etc etc etc

Using an old method, this worked with char arrays and still runs:

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

const char PROGMEM namesTable[] = { // all this text stored in flash
  "MARK\0FRANCIS\0JOHN\0ANDREW\0ROBERT\0SEAN\0HAYES\0LUDWIG\0HARRISON\0GRAND\0SALTER\0BOND\0"
};

PGM_P nT; // will point into namesTable

#define  FIRSTNAMES    6
#define  LASTNAMES     6
PGM_P    firstName[ FIRSTNAMES ];
PGM_P    lastName[ LASTNAMES ]; 

void  printProgstring( PGM_P FM )
{
  char fb;
  do 
  {
    fb = pgm_read_byte( FM++ );    
    if ( fb )  Serial.print( fb );
  }
  while ( fb );
}

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

  nT = namesTable;
  firstName[ 0 ] = nT;
  
  byte i; // only counting to 6 so 1 byte is enough
  for ( i = 1; i < FIRSTNAMES; i++ )
  {
    while ( pgm_read_byte( nT++ ));
    firstName[ i ] = nT++;    
  }
  
  for ( i = 0; i < LASTNAMES; i++ )
  {
    while ( pgm_read_byte( nT++ )); // find the \0 at the end of name[ i-1 ]
    lastName[ i ] = nT++;    
  }

  for ( i = 0; i < FIRSTNAMES; i++ )
  {
    printProgstring( firstName[ i ] ); 
    Serial.println( );   
  }
  Serial.println( );   
  for ( i = 0; i < LASTNAMES; i++ )
  {
    printProgstring( lastName[ i ] ); 
    Serial.println( );   
  }

} 

void loop(void)
{
}

Try it the other way round:

prog_uint32_t  PROGMEM crc_table[16] = {

Making the change to const from static AND pulling off the prog_ prefix to the type got me a clean compile and a working sketch. I could have sworn that I had tried that combination but obviously did not!

PROGMEM const uint32_t crc_table[16] = {
    0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
    etc, etc...

Thanks for the help.

Cheers, Wisar

Did/were you able to check that it didn't put the table in RAM?
I ask because I've never seen PROGMEM as the first thing on the line.

I have not checked though I do mean to. http://www.arduino.cc/en/Reference/PROGMEM says it is position neutral…

Wisar

I have some confusion here of my own. The below is speculation.

Some thinking and I feel that if you access the data with a program space pointer then it should be program space data. But that leaves me wondering how come my code seems to work when it violates at least one rule in that article.

dataType PROGMEM variableName = {}; // not this one

Some answer to that is here in the pgmspace library doc.

Typedefs
typedef void PROGMEM 	prog_void
typedef char PROGMEM 	prog_char
typedef unsigned char PROGMEM 	prog_uchar
typedef int8_t PROGMEM 	prog_int8_t
typedef uint8_t PROGMEM 	prog_uint8_t
typedef int16_t PROGMEM 	prog_int16_t
typedef uint16_t PROGMEM 	prog_uint16_t
typedef int32_t PROGMEM 	prog_int32_t
typedef uint32_t PROGMEM 	prog_uint32_t
typedef int64_t PROGMEM 	prog_int64_t
typedef uint64_t PROGMEM 	prog_uint64_t

typedef dataType attribute alias
bang?

Note that PROGMEM appears to be an attribute like private, public or protected are. It is then that I see "prog_int8_t" is the same as "int8_t PROGMEM". If that is right then there's no need to use prog_int8_t and PROGMEM together, is there?

GoForSmoke:

I still have issues. As you suspected my 'solution' may have gotten me a clean compile but the array is NOT going to program memory. AND...when I put the prog_ prefix back in front of the type I get the compile error saying that it is a non existent type. Something else is going wrong in my environment and I am not sure where to look...!

Wisar

A little surfing got me here:
http://www.controllerprojects.com/2011/05/23/determining-sram-usage-on-arduino/

And I grabbed the function:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

After yet another try getting #ifdef to work (this time using 1.03, last time using 0023) I said screw it and made two versions of a sketch to check what I can:

This one uses PROGMEM and reports 1811 bytes free on my UNO using IDE 1.03.

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

const char PROGMEM textTable[] = { // all this text stored in flash
  "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\0"
};

PGM_P tT; // will point into namesTable

/*
const char textTable[] = { // all this text goes into RAM
  "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\0"
};
*/

void  printProgstring( PGM_P FM )
{
  char fb;
  do 
  {
    fb = pgm_read_byte( FM++ );    
    if ( fb )  Serial.print( fb );
  }
  while ( fb );
}


int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

void setup(void)
{
  Serial.begin( 9600 );
  Serial.print( "\nRAMSIZE_P Free RAM = " );
  Serial.print( freeRam());
  Serial.println( "\n" );

  tT = textTable;
  printProgstring( tT ); 
//    Serial.println( textTable );   
    Serial.println( );   
} 

void loop(void)
{
}

This one uses RAM and reports 1523 bytes free on my UNO using IDE 1.03.

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

/*
const char PROGMEM textTable[] = { // all this text stored in flash
  "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\0"
};

PGM_P tT; // will point into namesTable
*/

const char textTable[] = { // all this text goes into RAM
  "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\0"
};

/*
void  printProgstring( PGM_P FM )
{
  byte fb;
  do 
  {
    fb = pgm_read_byte( FM++ );    
    if ( fb )  Serial.print( fb );
  }
  while ( fb );
}
*/

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

void setup(void)
{
  Serial.begin( 9600 );
  Serial.print( "\nRAMSIZE_R Free RAM = " );
  Serial.print( freeRam());
  Serial.println( "\n" );

//  tT = textTable;
//    printProgstring( tT ); 
    Serial.println( textTable );   
    Serial.println( );   
} 

void loop(void)
{
}

Hey,

PROGMEM has changed since this code was written, so replace this line : static PROGMEM prog_uint32_t crc_table[16] = {
with: const uint32_t PROGMEM crc_table[16] = {
for it to compile and function properly.

GoForSmoke and Hashma:

Thanks for both of the above posts. Hashma: Not only does the CRC sketch compile it even returns the right answer!

GoForSmoke: I got sidetracked into trying to get the demo on the Arduino website to work which then convinced me there was something wrong with the configuration of my machine...which...etc, etc. While I have given up on using Progmem for a complex structure I can get what I need with a CSV string and the example you posted.

Cheers,
Wisar

When you're ready, make a struct or better yet a class for your complex structure. It will hold some number of bytes and you know that you can store and fetch bytes to and from PROGMEM.

Hashma:
Hey,

PROGMEM has changed since this code was written, so replace this line : static PROGMEM prog_uint32_t crc_table[16] = {
with: const uint32_t PROGMEM crc_table[16] = {
for it to compile and function properly.

Is there a full resource that explains the new usage of PROGMEM? I've been using avr-libc: Data in Program Space and that seems to explicitly say that using const isn't appropriate:

A Note On const

Many users bring up the idea of using C's keyword const as a means of declaring data to be in Program Space. Doing this would be an abuse of the intended meaning of the const keyword.

const is used to tell the compiler that the data is to be "read-only". It is used to help make it easier for the compiler to make certain transformations, or to help the compiler check for incorrect usage of those variables.

For example, the const keyword is commonly used in many functions as a modifier on the parameter type. This tells the compiler that the function will only use the parameter as read-only and will not modify the contents of the parameter variable.

const was intended for uses such as this, not as a means to identify where the data should be stored. If it were used as a means to define data storage, then it loses its correct meaning (changes its semantics) in other situations such as in the function parameter example.

Is there a better online manual for the version of avr-gcc that Arduino uses?

Whoever wrote that note is either confused or didn't think long enough. I don't know if const gets the variable to not be copied to RAM but I add PROGMEM to make sure it stays in flash and last time I asked here the PROGMEM keyword had to be used.

Work it out. Everything in the sketch gets put into flash. WHY would it make sense to copy a constant into RAM when it's right there accessible in flash? For 1 extra cycle in speed?

You know how people who really don't understand something will hang up over rules that aren't actually rules? That note strikes me as that kind of 'puritanism'.

The 'new' stuff uses the F() macro to keep string literals in flash and print them from there. I don't know what else it can do but it does that without needing the PROGMEM keyword.

GoForSmoke:
Whoever wrote that note is either confused or didn’t think long enough. I don’t know if const gets the variable to not be copied to RAM but I add PROGMEM to make sure it stays in flash and last time I asked here the PROGMEM keyword had to be used.

Work it out. Everything in the sketch gets put into flash. WHY would it make sense to copy a constant into RAM when it’s right there accessible in flash? For 1 extra cycle in speed?

You know how people who really don’t understand something will hang up over rules that aren’t actually rules? That note strikes me as that kind of ‘puritanism’.

That quote was only a part of the page from nongnu, you know, the home site of AVR Libc… It was arguing against using const as a prelude on how to use PROGMEM. While it may be ‘puritanism’, but no more than insisting on proper usage of terms.

The ‘new’ stuff uses the F() macro to keep string literals in flash and print them from there. I don’t know what else it can do but it does that without needing the PROGMEM keyword.

What better way to understand the extents and limitations of the F() macro than to look at how it is defined. Unfortunately, I’ve been scanning through the various core .h and avr/.h files looking for where F() is defined but so far no joy.

I’ve only seen examples of using the F() macro for sending strings over Stream methods. PROGMEM is much more flexible than that. Say you need a 5k lookup table on an UNO. Can’t do that with F(). Say you need to output the 7 different strings individually multiple times within several different functions. Instead of cluttering Flash with multiple copies of the same 7 strings using F(), use an array of strings with PROGMEM and call them by reference when needed.

I've only used PROGMEM and that only a few times.