Pages: [1]   Go Down
Author Topic: Confusing Behavior with 2D Array in Flash  (Read 679 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm seeing some confusing behavior with a 2D Array I've created in Flash (using the PROGMEM attribute).  First, some code:

Code:
// Macro to perform "sizeof" on PROGMEM Arrays
#define ELEM_CNT(x)                          (sizeof(x) / sizeof(x[0]))

// Individual Arrays
const byte a0[] PROGMEM = {0, 0, 1, 2, 3, 4, 5, 6};
const byte a1[] PROGMEM = {0, 0, 9, 8, 7, 6, 5, 4};
const byte a2[] PROGMEM = {0, 0, 5, 6, 7, 8, 9, 0};

// Array of arrays
const byte *arrays[] PROGMEM = {
  a0,
  a1,
  a2,
};

byte i,j;

for (i = 0; i < ELEM_CNT(arrays); i++)
  { 
    Serial.print("Array #");
    Serial.print(i, DEC);
    Serial.print(": ");
   
    for (j=0; j<8; j++)
    {
      Serial.print(pgm_read_byte(&(array[i][j])), DEC);
      Serial.print(" ");
    }
    Serial.println();
  }

Like this, I get gibberish in the serial output, like this:
Code:
Array #0: 0 0 251 193 0 0 249 193
Array #1: 2 3 4 5 6 1 2 3
Array #2: 2 3 4 5 6 1 2 3
But if I make one change, things work great...

Code:
// snippet from above with modification
for (i = 0; i < ELEM_CNT(arrays); i++)
  { 
    Serial.print("Array #");
    Serial.print(i, DEC);
    Serial.print(": ");
   
    for (j=0; j<8; j++)
    {
      if (i == 0)
        Serial.print(pgm_read_byte(&(array[i][j])), DEC);
      Serial.print(" ");
    }
    Serial.println();
  }

Output:
Code:
Array #0: 0 0 1 2 3 4 5 6
Array #1:         
Array #2:

Now with this, I get the expected output, with the obvious caveat of it only works for one case, which defeats the entire purpose of trying to make a 2D array in the first place.  Alternatively, I can just hardcode in a value for the first index (i) of the array and it works great, but as soon as I try to iterate over more than one index, it doesn't work.  I'm confuse by it because I don't see any obvious errors, especially since it works with a hardcoded value, but this is my first foray into the PROGMEM attribute, so I could just be missing something frustratingly obvious.  Any ideas?

Thanks!
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You have two lots of PROGMEM here, but are only reading one. If you can afford the space, take out PROGMEM from the array of arrays:

Code:
// Array of arrays
const byte *arrays[] = {
  a0,
  a1,
  a2,
};

Or how about a 2D array in the first place?

Code:
const byte a[] [8] PROGMEM =
{
{0, 0, 1, 2, 3, 4, 5, 6},
{0, 0, 9, 8, 7, 6, 5, 4},
{0, 0, 5, 6, 7, 8, 9, 0},

// and so on

};
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick,

There's actually another identical set of arrays (same structure, different data) and then a much bigger 3D array as well.  This probably could all go in SRAM, but there's thought that this project could grow, and I'm trying to future proof it by just dumping all of the arrays into PROGMEM.  I copied this setup from the Arduino PROGMEM example, here: http://arduino.cc/en/Reference/PROGMEM.

One thought, would it work to have the Array of Arrays (aka, array of pointers) as a regular variable, but leave the longer Arrays in PROGMEM?  Like I said, I was just following the example as best I could so I assumed it was easier for everything to be PROGMEM, but now I'm not sure.

Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, well arrays (as you called it) was a collection of pointers, where the pointers themselves were in PROGMEM.

So you have to do a "read word" to get the pointer from progmem, and then use that pointer to get the actual data.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah, that's making more sense.  I've re-worked my code to just have the whole thing declared as a single 2D array because that's a little easier to understand at a quick glance.

One thing I'm still a bit confused on, if I used a hardcoded index it worked fine, but if I used a variable it failed.  Any thoughts on why that be?

For example, the following would fail:
Code:
Serial.print(pgm_read_byte(&(array[i][j])), DEC);

But this would print the correct data:
Code:
Serial.print(pgm_read_byte(&(array[0][j])), DEC);

I see why the code itself is wrong, but I don't understand why hardcoding the first index would allow it to work.  Obviously I'd rather just code this correctly, but I'd like to understand this better because it tripped me up for the better part of a day.

Thanks!
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Was the variable "i" zero? If not then it probably had to look up the offset, but in the wrong sort of memory (RAM rather than PROGMEM).
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Yeah, "i" was definitely 0, which is what was confusing me the most.  Oh well, I've got it working now, not quite as I thought it would look, but it's actually a lot more maintainable this way, so I'm ok with that!

Thanks for your help.
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I would have to assume compiler optimization changed something.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 32
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I would have to assume compiler optimization changed something.

That was my thought, but I'm not all that familiar with modifying compiler flags within the Arduino environment.  One time where I'd rather be using a "full fledged" IDE!
Logged

Pages: [1]   Go Up
Jump to: