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)
{
}
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!
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.
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?
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...!
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)
{
}
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.
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.
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.
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.