c++arduinoprogmem

What am I missing when using PROGMEM?


So I'm trying to store a multi-dimensional CHAR array in program memory on my Arduino and I'm having problems getting it to work. Here's what I have...

typedef unsigned char RGBBitmap[8][8][3];
typedef prog_uchar ProgRGBBitmap[8][8][3]; // Have to use prog_uchar for stuff stored in progmem

ProgRGBBitmap Mailbox[3] PROGMEM = 
{
    ... // some initializing data
};

Per the PROGMEM documentation, to get a pointer back to the char data, you should use the pgm_read_word call. However, when I try to read it back out using this...

RGBBitmap * pMailbox0 = (RGBBitmap*)pgm_read_word( &Mailbox[0] );

...all I get back is garbage.

If I drop the PROGMEM line and only work with RGBBitmap pointers and drop the pgm_read_word, it works, but then its in RAM, which I'm out of.

So what am I missing here?


Solution

  • Your arrays are a block of values. Like this your code is defining a continuous block of values:

    ProgRGBBitmap Mailbox[3] PROGMEM = {...};
    ... removing typedef is same as ...
    prog_uchar Mailbox[3][8][8][3] = {...};
    

    So you cannot read a pointer from program memory because they are not stored there. The block is all uchar's.

    All your values are bytes, so you would read any value out of that block with:

    uc = (uchar)pgm_read_byte( someaddress );
    

    Now the tricky part for a 4 dimensional array is getting the address syntax correct.

    uc = (uchar)pgm_read_byte( &Mailbox[i][x][y][c] );
    

    The compiler will insert pointer arithmetic for the [i]...[c], which may be wasteful in a loop. So you can precalculate part of the pointer, which is I think what you where trying to accomplish. Something like this will save some code and clock ticks:

    ProgRGBBitmap* ptrOneBox = &(Mailbox[i]);  // this will be pointer into block
    for(x ...
      for(y ....
        uc = (uchar)pgm_read_byte( &(ptrOneBox[x][y][c]) ); // this indexes out one byte
    

    Pointer and arrays can make you crazy when it doesn't work. Throw in PROGMEM on a platform with no debugger...

    Strip down the problem to a simpler case and work back up.