need help with struct and PROGMEM

The following code does not display the correct values for x and y. If I omit PROGMEM then it does display the correct values. I am trying to use PROGMEM because the my actual code is using an array of 8 256 char bitmaps but this simplified version demonstrates the problem. Can anyone point out what I am doing wrong?

const struct {
    int x,y;
} test[3] PROGMEM={
    {1,2},
    {3,4},
    {5,6},
};

void displayXY(int i) {
  Serial.println(test[i].x);
  Serial.println(test[i].y);
}

void setup() {
  Serial.begin(9600);
  displayXY(1);
  displayXY(2);
  displayXY(3);    
}

void loop() {

}

Hint: Get rid of the PROGMEM keyword in your code and what happens?

The compiler doesn't keep track of which data is in SRAM and which is in FLASH (PROGMEM). You have to remember for it and call the function for reading from FLASH if you want to read a value from FLASH.

In your case the data is type 'int' which is a 16-bit value. To read it you have to pass the address to pgm_read_word_near();

void displayXY(int i) {
  Serial.println((int) pgm_read_word_near(&test[i].x));
  Serial.println((int) pgm_read_word_near(&test[i].y));
}

The "&" means "the address of" since you want to pass the PROGMEM address to fetch the word rather than the value stored in SRAM at that address.

Why does this work...?

const struct {
    int x,y;
} test[3] PROGMEM={
    {1,2},
    {3,4},
    {5,6},
};

void setup() {
  Serial.begin(9600);
  Serial.println(test[1].x);
  Serial.println(test[1].y);
  Serial.println(test[2].x);
  Serial.println(test[2].y);
  Serial.println(test[3].x);
  Serial.println(test[3].y);
}

void loop() {

}

The compiler is optimizing out the structure, everything is known at compile time: test[2].y becomes a literal value and is removed just like normal static data. PROGMEM means nothing to the compiler, it just tells the linker which memory section the data will reside in.

Its similar to doing something like this:

const int i = 4;
Serial.print( i ); // i is stored as a simple load instruction. The variable i takes up no ram.

If this is how you use the data, you can simply avoid PROGMEM as values inlined into code are effectively in PROGMEM.

If you need to access the array sequentially (in a loop or from an index not known at compile time), then you'll need to use PROGMEM, otherwise the structure will creep back into ram.

Can anyone point out what I am doing wrong?

In addition to not accessing the data correctly, you are not accessing the array elements correctly. Array indexes start at 0, not 1.

PaulS:
In addition to not accessing the data correctly, you are not accessing the array elements correctly. Array indexes start at 0, not 1.

Yeah I caught that. I just typed that up as an example and made a mistake.

pYro_65:
The compiler is optimizing out the structure, everything is known at compile time: test[2].y becomes a literal value and is removed just like normal static data. PROGMEM means nothing to the compiler, it just tells the linker which memory section the data will reside in.

Its similar to doing something like this:

const int i = 4;

Serial.print( i ); // i is stored as a simple load instruction. The variable i takes up no ram.




If this is how you use the data, you can simply avoid PROGMEM as values inlined into code are effectively in PROGMEM. 

If you need to access the array sequentially (in a loop or from an index not known at compile time), then you'll need to use PROGMEM, otherwise the structure will creep back into ram.

Thank you very much!