Const (Constant) PROGMEM is there a difference?

Ok, trick question. From what I read Const is stored in Flash and SRAM where as PROGMEM is in flash only.

I’ve used FreeMemory() to give an idea of memory usage and constructed an array that is declared in 3 different ways, PROGMEM float array, const float array and just float array. Memory usage does not seem to agree with what I have learnt regarding Const and PROGMEM. Here is the code each declaration of the array there is a comment with what the run code reported free memory as. PROGMEM & Const are the same, I think they shouldn’t be… can anyone clear up my miss understanding?

float vpd_table[5][15][2] = {   // 1204 SRAM free, expected lower ram
//const  float vpd_table[5][15][2] = {  // 1808 SRAM free, I expected this to be the same as just a float but it's freed up memory!
//PROGMEM prog_float_t vpd_table[5][15][2] = {  // 1804 SRAM free as expected

Full code:

#include <MemoryFree.h>  // tells us what SRAM memory is free
#include <avr/pgmspace.h>  // So we cna use PROGMEM
typedef float PROGMEM prog_float_t; // Need to define this type before use

float vpd_table[5][15][2] = {   // 1204 SRAM free, expected lower ram
//const  float vpd_table[5][15][2] = {  // 1808 SRAM free, I expected this to be the same as just a float but it's freed up memory!
//PROGMEM prog_float_t vpd_table[5][15][2] = {  // 1804 SRAM free as expected
              //30%      35%      40%       45%       50%       55%       60%       65%       70%       75%       80%       85%       90%       95%       100%
/*10 degC*/{ {1.98,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00}   },
/*15 degC*/{ {00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,90},{00,00},{00,00},{00,00},{00,00}   },
/*20 degC*/{ {00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00}   },
/*25 degC*/{ {00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00}   },
/*30 degC*/{ {00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00},{00,00}   }};


void setup()			  // run once, when the sketch starts
{
  Serial.begin(9600);
}

void loop()			   // run over and over again
{
  //float absHumidity = pgm_read_float_near(&vpd_table[0][0][0]); // grab a value from progmem
  float absHumidity = vpd_table[0][0][0];                         // grab a value to use  
  Serial.print("freeMemory() reports ");
  Serial.print( freeMemory() );Serial.print( " VPD:" );Serial.println( absHumidity);
}

As the const array is only read from it gets compiled away ( not stored in sram ) and its literal values are in place of of the array access code. You would have different results if you created a reference to the array. This data has not been placed in its own program memory space, rather inside the code that uses it.

PROGMEM explicitly puts into program memory. if the data is not available at compile time, a block filled with garbage ends up in program memory

Ah so in this particular case there is no benefit using PROGMEM, by declaring constant (and not manipulating or referencing the data) it is compiled as literal values, and since the compiled sketch is stored in PROGMEM the const array is therefore also stored in PROGMEM.

PROGMEM explicitly puts into program memory. if the data is not available at compile time, a block filled with garbage ends up in program memory

then I presume at runtime that garbage is filled with meaningful data.

Now, why does referencing a const array change matters? My assumption is that since flash/PROGMEM isn't directly addressable it must be moved into SRAM to pass an addressable reference?

dannix: Ah so in this particular case there is no benefit using PROGMEM, by declaring constant (and not manipulating or referencing the data) it is compiled as literal values, and since the compiled sketch is stored in PROGMEM the const array is therefore also stored in PROGMEM.

That is happening as a result of compiler optimizations, NOT because const arrays are stored in flash. const arrays are NOT stored in flash unless specified so using the PROGMEM attribute.

Because you are not making any sort of random access of the const array, the compiler optimizes out the entire existance of that array. If your code randomly accessed it though, then the compiler could not optimize it out, and the array would end up in SRAM.

Now, why does referencing a const array change matters? My assumption is that since flash/PROGMEM isn't directly addressable it must be moved into SRAM to pass an addressable reference?

yes the compiler will have to keep it in SRAM, const is only of use to programmers, it doesn't exist past compilation. Things like const_cast and assigning to a non-const pointer can allow you to modify the data.

When I had bad data in the PROGMEM space, the globals section still was created to fill SRAM space on startup, so it effectively was twice the cost of the actual data needed to be stored in progmem.

jraskell:

dannix:
Ah so in this particular case there is no benefit using PROGMEM, by declaring constant (and not manipulating or referencing the data) it is compiled as literal values, and since the compiled sketch is stored in PROGMEM the const array is therefore also stored in PROGMEM.

That is happening as a result of compiler optimizations, NOT because const arrays are stored in flash. const arrays are NOT stored in flash unless specified so using the PROGMEM attribute.

Because you are not making any sort of random access of the const array, the compiler optimizes out the entire existance of that array. If your code randomly accessed it though, then the compiler could not optimize it out, and the array would end up in SRAM.

And now it all clicks into place. Thank you!!

To test your explanation I re-wrote the loop() as:

void loop()			   // run over and over again
{
  //float absHumidity = pgm_read_float_near(&vpd_table[0][0][0]); // grab a value from progmem
  float absHumidity = 0.0;
  for (int i = 0; i < 10; i++)  {
  absHumidity = vpd_table[i][0][0]; 
 
  // grab a value to use  
  Serial.print("freeMemory() reports ");
  Serial.print( freeMemory() );Serial.print( " VPD:" );Serial.println( absHumidity);
 delay(200);  
 }
}

It indeed did reduce SRAM significantly. :smiley: :smiley:

pYro_65:
yes the compiler will have to keep it in SRAM, const is only of use to programmers, it doesn’t exist past compilation. Things like const_cast and assigning to a non-const pointer can allow you to modify the data.

When I had bad data in the PROGMEM space, the globals section still was created to fill SRAM space on startup, so it effectively was twice the cost of the actual data needed to be stored in progmem.

I was beginning to wonder what the point of it was. I’ve programmed more in Perl and never used anything similar. I feel it’s upto me to ensure I’m not trampling on vars I shouldn’t be. If const doesn’t exist past compile, there is no sketch size penilty for using it. I guess it helps you find an error at compile time though if you have reassigned a const variable.

dannix: I was beginning to wonder what the point of it was. I've programmed more in Perl and never used anything similar. I feel it's upto me to ensure I'm not trampling on vars I shouldn't be. If const doesn't exist past compile, there is no sketch size penilty for using it. I guess it helps you find an error at compile time though if you have reassigned a const variable.

You can also use a const identifier to size an array. The compiler can easily optimize out most const identifiers that aren't arrays and don't have their address taken (so they're a replacement for #define essentially)

There are also other uses of const if you get into more complicated C++

WizenedEE: You can also use a const identifier to size an array. The compiler can easily optimize out most const identifiers that aren't arrays and don't have their address taken (so they're a replacement for #define essentially)

There are also other uses of const if you get into more complicated C++

Do you mean like this:

const int maxLimit = 50;
            int objects[maxLimit];

rather than :

int objects[50];

If so I'm not seeing any benefit?

Its not a benefit, its a requirement. statically allocated arrays must be specified with static values to specify size, either explicitly or from an initialiser list count .Only dynamic memory can use dynamic variables to specify a size ( new, malloc )

The only exception is on the stack

void foo( int a )
  {
    int b[ a ];
  }

But this is using a different memory heap and you don't have control of its scope

pYro_65: Its not a benefit, its a requirement. statically allocated arrays must be specified with static values to specify size

Isn't both the above declarations using static values? I'm being told I can use a const to size an array, I just don't see why anyone would bother.

So you know the number later on?

eg.

const int maxLimit = 50;
int objects[maxLimit];

...

for (int i = 0; i < maxLimit; i++)
  {
  // do something with objects [i]
  }

Otherwise you have this:

int objects[50];

...

for (int i = 0; i < 50; i++)
  {
  // do something with objects [i]
  }

Now if you decide to change 50 to 60 you have to remember to change two places, or twenty maybe.

Normally in other languages I’d size the array, assuming arduino “sizeof” would have been suitable but reading it’s not.

In C you can get the size of your array in bytes using sizeof(myarray);
To get the number of elements you divide this by the size of a single element, like this:

int size = sizeof(myarray) / sizeof(int);

but a better way is to always use a constant to define the array size, for example:

#define MY_SIZE 5
int myarray[MY_SIZE];

for( int i=0 i < MY_SIZE; i++)
myarray = i ;[/quote]
Realizing there is not simple way to get the arrays number of elements, the const method makes sense.
I’m sorry some of this seems like a daft question.

Realizing there is not simple way to get the arrays number of elements

Depends on where you try. If you have a global array, you can get the size of the array anywhere, and get the number of elements by dividing that value by the size of one element.

If you are in a function that has only a pointer to the array, then there is no way to get the size of the array that the pointer points to.

dannix: Normally in other languages I'd size the array, assuming arduino "sizeof" would have been suitable but reading it's not.

It's C++. There is no "Arduino language".

As PaulS said, you can use sizeof under certain circumstances, if you divide the whole thing by the size of one item. Doesn't help if you pass a pointer to a function. That may or may not matter to you.

[quote author=Nick Gammon link=topic=114719.msg864896#msg864896 date=1342685995]

It's C++. There is no "Arduino language".

[/quote]

That's just splitting hairs. Do enlighten me though, whats digitalWrite()? C++ or Arduino? Maybe I should have called it Arduino IDE instead.

Do enlighten me though, whats digitalWrite()?

It's a function, like strtok() or sprintf(). It's not part of the language, but part of a library developed to perform functions that most users of the language need to perform.

C++ or Arduino?

Neither. It's written in C.

Right.

Thanks everyone for clearing up my misunderstanding.

i have another question here

where does #define fit into? is it the same as a const ?

No, #define is part of the macro preprocessor, a basic but fairly powerful text replacement engine.

define doesn't have to create simple constants (actually, most of the time it just creates aliases), it can be used to create whole blocks of code or tables.

#define X 12
..

..
int a = X;

Here, all that happens is that int a = X; is replaced by the text int a = 13; before the compiler gets to see the text of the program.

so it's completely embedded in the compiled code and does not take any SRAM?