PROGMEM problem. (almost there)

My project will have an LCD to display a menu to control things and to set various parameters. The menu will be arranged like most user interfaces so that, depending on the item, something is controlled, a value is displayed for adjustment, or another list of menu items is displayed. So far I plan to have 114 menu strings to display. Obviously I’ll need to store them in flash memory. So before I dive in too deep, I thought I’d start with a small test sketch.

Here is my test sketch:

// Lists of item numbers for each menu

const static uint8_t nextItemList0[] PROGMEM = {1, 2, 3, 4, 5};
const static uint8_t nextItemList1[] PROGMEM = {6, 7, 8};
const static uint8_t nextItemList2[] PROGMEM = {9, 10, 11, 12};
const static uint8_t nextItemList3[] PROGMEM = {13};


// This will be the master list tree for all menus

const static uint8_t* const itemTree[] PROGMEM =
{
    nextItemList0,   nextItemList1,   nextItemList2,   nextItemList3
};

// The number of items in each list

const static uint8_t numItems[] PROGMEM =
{
    5, 3, 4, 1
};

void setup()
{
    Serial.begin(9600);
    for (uint8_t i = 0; i < 4; i++)
    {
        for (uint8_t ii = 0; ii < (uint8_t)pgm_read_byte_near(numItems + i); ii++)
        {
            Serial.print((uint8_t)pgm_read_byte_near((*itemTree + i) + ii), DEC);
            Serial.print(' ');
        }
        Serial.println();
    }
}

void loop()
{
    
}

I expect it to print out

1 2 3 4 5
6 7 8
9 10 11 12
13

what I get is

1 2 3 4 5
2 3 4
3 4 5 0
4

So, it looks like it’s reading the first set of numbers correctly, but it doesn’t increment to the next set of items. I’ve read up on pgmspace.h and PROGMEM and arrays of strings is covered quite a bit. However, arrays of byte arrays is not. It seems from what I’ve read byte data Is not handled the same way. I assume it’s because of the lack of a terminating NULL byte. Anyway I know I’m very close I just need little help to see what I’m missing.

I’ve almost got it but I just can’t wrap my head around the PROGMEM stuff.

Thanks for any replies.
DigitalJohnson

  Serial.print((uint8_t)pgm_read_byte_near((*itemTree + i) + ii), DEC);

You are dereferencing a variable that resides in PROGMEM, as you experience that does not work, you could try

 Serial.print((uint8_t)pgm_read_byte_near(pgm_read_ptr_near(itemTree + i) + ii));
ii < (uint8_t)pgm_read_byte_near(numItems + i)

what is this statement saying?

Stay closer to the PROGMEM documentation and tutorial:
https://www.arduino.cc/reference/en/language/variables/utilities/progmem/.
Gammon Forum : Electronics : Microprocessors : Putting constant data into program memory (PROGMEM).

As Whandall wrote, you have to use the pgm_… functions, every time you want to read something from PROGMEM, regardless if that is a pointer or a byte.

It is possible to put “sizeof()” in an array, but you could also add a ‘0’ at the end to indicate the end of the data.
When you are using a Arduino Mega 2560, then you could create a single array in PROGMEM and have fixed length for all data. Maybe you will waste 20 kbytes, but who cares ? It is your memory, you paid for it, so use it :wink:

// Lists of item numbers for each menu

const static uint8_t nextItemList0[] PROGMEM = {1, 2, 3, 4, 5};
const static uint8_t nextItemList1[] PROGMEM = {6, 7, 8};
const static uint8_t nextItemList2[] PROGMEM = {9, 10, 11, 12};
const static uint8_t nextItemList3[] PROGMEM = {13};


// This will be the master list tree for all menus

const static uint8_t* const itemTree[] PROGMEM =
{
    nextItemList0,   nextItemList1,   nextItemList2,   nextItemList3
};

// The number of items in each list

const static uint8_t numItems[] PROGMEM =
{
  sizeof( nextItemList0),
  sizeof( nextItemList1),
  sizeof( nextItemList2),
  sizeof( nextItemList3),
};

void setup()
{
  Serial.begin(9600);
  for( uint8_t i = 0; i < 4; i++)
  {
    uint8_t n = pgm_read_byte_near( numItems + i);
    const uint8_t *p = (const uint8_t *) pgm_read_word_near( &(itemTree[i]));

    for( uint8_t ii = 0; ii < n; ii++)
    {
      Serial.print( (int) pgm_read_byte_near(&(p[ii])));
      Serial.print(' ');
    }
    Serial.println();
  }
}

void loop()
{
}

@Wandall,
Thank you very much! It's working now. I must have skipped over the pgm_read_ptr_near() stuff, not realizing the significance. Duh! :o

@ Arduino_new,
That statement is saying if ii is less than the value returned from numItems*. The values contained in the array numItems are the number of items for each array contained in itemTree.*

@Koepel,
Good tip. I will include that in my code.