How to make an array of pointers to arrays in PROGMEM?

Hi all,

I've got a bunch of data in PROGMEM, like this:

static const uint16_t btn_0[] PROGMEM = {
    // header
    0x8160, 0x00B0,
    // 16 bits of data
    0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058,
    0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058,
    0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058,
    0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058,
    // repeat code burst
    0x8016, 0x069A, 0x8160, 0x00B0,
    // end of command
    0x8016, 0x0000,
};

static const uint16_t btn_1[] PROGMEM = {
    // header
    0x8160, 0x00B0,
    // 16 bits of data
    0x8016, 0x00B0, 0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058,
    0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058,
    0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058, 0x8016, 0x0058,
    0x8016, 0x00B0, 0x8016, 0x00B0, 0x8016, 0x00B0, 0x8016, 0x00B0,
    // repeat code burst
    0x8016, 0x04E2, 0x8160, 0x00B0,
    // end of command
    0x8016, 0x0000,
};
///// LOTS MORE

This works fine in that I can do this: [b]sendCmd (btn_0);[/b] and "sendCmd" reads the data out of PROGMEM and uses it properly.

Now, what I want to do is make an array that points to all of the data I have ... something like this:

const uint16_t arrayPtr[] PROGMEM = {
    btn_0,
    btn_1,
    btn_2,
    // etc...
    last_entry,
};

and then be able to do this:

uint8_t idx = 0;
sendCmd (arrayPtr[idx]);

The point is that I want this array of pointers to PROGMEM to also be in PROGMEM.

Everything I've tried doesn't work. Any ideas will be appreciated!

The point is that I want this array of pointers to PROGMEM to also be in PROGMEM.

Why? How much SRAM are you going to save putting a bunch of 2 byte pointers in PROGMEM?

Everything I've tried doesn't work.

The snippet of code that you showed is how to put the array of pointers in PROGMEM. The problem must be in the code that accesses the data. Accessing data in PROGMEM using a pointer in PROGMEM is a two step process, where first you get the pointer from PROGMEM and then you get the pointed to data from PROGMEM.

How different is this (conceptually) from the string (char array instead of uint16_t you have) example in the PROGMEM doc

#include <avr/pgmspace.h>
const char string_0[] PROGMEM = "String 0";   // "String 0" etc are strings to store - change to suit.
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";


// Then set up a table to refer to your strings.

const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};

J-M-L:
How different is this (conceptually) from the string (char array instead of uint16_t you have) example in the PROGMEM doc

#include <avr/pgmspace.h>

const char string_0[] PROGMEM = "String 0";   // "String 0" etc are strings to store - change to suit.
const char string_1[] PROGMEM = "String 1";
const char string_2[] PROGMEM = "String 2";
const char string_3[] PROGMEM = "String 3";
const char string_4[] PROGMEM = "String 4";
const char string_5[] PROGMEM = "String 5";

// Then set up a table to refer to your strings.

const char* const string_table[] PROGMEM = {string_0, string_1, string_2, string_3, string_4, string_5};

It's not different. I did it wrong. The way you showed works (modified for uint16_t of course).

This works:

const uint16_t* const keys[] PROGMEM = {
    btn_0,
    btn_1,
    btn_2,
/// etc...
};

I didn't have the second "const".

Thanks for the help!

Just be aware that the strategy shown in that string example is only safe if you're using an AVR with <= 64kb of flash, or take steps to ensure that your arrays reside only within the first 64kb of flash. Take it to a Mega 2560 as-is, and things may quickly fall apart. AVR GCC has no first-class support for 'far' pointers on the AVR, and so you have only a few lame options, such as: Side-step GCC and define your arrays in asm() blocks (and declare them 'extern' in your C code) or use pgm_get_far_address() to fetch a 32-bit address (conveniently, pgm_get_far_address() also cannot be used outside of function scope, so placing it directly inside a global array's initializer list doesn't work--although you can place it in a local static array's initializer list). Ho hum!

Krupski:
I didn't have the second "const".

Thanks for the help!

Ah, that kind of thing.

Where you the one that asked about const correctness recently?