Accessing PROGMEM correctly with Structs

I am a miserable beginner, so please be patient with me, but I would very much appreciate help. I have a complex and growing program that displays information on a TFT display using an Arduino (Teensy 3.2, more specifically). I've been trying to tame the situation with some structs, but I'm not sure I'm doing this correctly in order to keep as much as possible in PROGMEM and out of RAM.

Some pseudo-code below to explain what I'm doing:

I have a file I have split all of my graphical data off into called "graphics.h" which I am #including where necessary to utilize its contents. This file has a number of data sets:

  • Multiple sets of 4-bit-per-pixel bitmap data. These are stored in PROGMEM in uint8_t arrays. EX:

  • const uint8_t bitmap1[] PROGMEM = { 0x00, 0x00... etc ... };*

  • const uint8_t bitmap2[] PROGMEM = { 0xFF, 0XFF... etc ... };*
    ... and so on, and so on. A bunch of these.

  • Sets of color palettes, stored in uint32_t arrays, which correlate with the bitmap sets. EX:

  • const uint32_t colorSet1[] PROGMEM = { 0xFF5A737E, 0XFF64808C... etc ... };[/li]*

  • [/list]*

  • These palettes don't correlate 1:1 to the bitmaps, meaning I use one palette for multiple images, rather than one palette per image.*

  • Now, I have been using the data in this file without issue. I am using a variant of Paul Stoffregen's ILI9341_t3 library, which has a 4-bit-per-pixel bitmap writing function that works with the above data types. I have an object from this library that I have named 'tft' and if I want to draw something, I just have to call the writeRect4BPP() function, EX:*

  • ```*

  • tft.writeRect4BPP(x, y, width, height, bitmap2, colorSet1);*

  • ```*
    The writeRect4BPP function is itself looking for pointers to the bitmap and colorSet:

  • ```*

  • void ILI9341_t3::writeRect4BPP(int16_t x, int16_t y, int16_t w, int16_t h, const uint8_t pixels, const uint32_t * palette ){}

  • ```*
    I set up a struct to organize all of the data sets necessary in my graphics.h file.

  • ```*

  • *struct imageSet{
    uint8_t *bitmap1;
    uint8_t *bitmap2;
    uint8_t *bitmap3;
    uint8_t *bitmap4;
    uint8_t *colorSet};

const imageSet set1 PROGMEM = {bitmap1, bitmap2, bitmap3, bitmap4, colorSet};**

  • ```*
  • I have a function that picks one of these bitmaps from the set based on other logic in the code (the value of an int, basically) and draws that image accordingly:*
  • ```*
  • if(int == 0){
    tft.writeRect4BPP(x, y, width, height, set1.bitmap1, set1.colorSet);
    } else if(int == 1){
    tft.writeRect4BPP(x, y, width, height, set1.bitmap2, set1.colorSet);
    } else if(int == 2){
    tft.writeRect4BPP(x, y, width, height, set1.bitmap3, set1.colorSet);
    } else {
    tft.writeRect4BPP(x, y, width, height, set1.bitmap4, set1.colorSet);
    }
    *
  • ```*
  • The thing I'm noticing is that as I increase this in complexity, my program is starting to hang, freeze, lock up, or otherwise show garbage data in other unrelated areas (text output, for example). If I get rid of the conditional statements above and just always write one bitmap from the set (i.e. set1.bitmap1), there are no issues, but once I start adding the conditionals in things get weird.*
  • I'm almost positive this weirdness is resulting from my RAM getting used up. This suggests to me that I may be doing the PROGMEM thing wrong, and that it may be inadvertently grabbing all of the separate bitmap data arrays for each image and trying to hold them in RAM. The actual flash memory is only seeing about 23% usage when I compile.*
  • Can anyone tell me if/how I'm approaching this wrong?*

Really nicely laid out post, lots of detail, code in code tags, great - but it would be easier for everyone to just include all the code.

struct imageSet{
uint8_t *bitmap1;
uint8_t *bitmap2;
uint8_t *bitmap3;
uint8_t *bitmap4;
uint8_t *colorSet};

How much SRAM do you think you are saving by putting these 5 pointers into PROGMEM? Is saving 10 bytes worth the doubling of effort required to access the data?

PaulS:

struct imageSet{

uint8_t *bitmap1;
uint8_t *bitmap2;
uint8_t *bitmap3;
uint8_t *bitmap4;
uint8_t *colorSet};



How much SRAM do you think you are saving by putting these 5 pointers into PROGMEM? Is saving 10 bytes worth the doubling of effort required to access the data?

Probably not! I may have misunderstood what I had been reading about program space - I thought if the struct wasn't in PROGMEM itself, it'd also end up pulling the bitmaps into data space (RAM). Pretty sure that's not what it was saying, on re-review. I've had a difficult few days trying to understand pointers, but I think in the last few hours it has clicked. Like I said... still a beginner at some of this stuff.

As it happens, I've solved the issues I was having anyway.

My project scope started on a Pro Trinket - AVR architecture - but I rapidly outgrew the capabilities of the device, even trying to put everything in PROGMEM. I switched to the Teensy 3.2, which had the same footprint as the Pro Trinket but way more metaphorical horsepower, and just kept trucking.

Teensy is not an AVR chip, it's ARM. Turns out, that means it doesn't use PROGMEM declarations at all. If something is a const, it handles the PROGMEM stuff automatically. I had been trying to set up what I thought were working pgm_read_byte/pgm_read_word lines to pull data from that memory space, only they were totally unnecessary and causing intermittent issues.

Once I discovered this error, I facepalmed mightily, stripped out all the PROGMEM-related stuff, replaced all my pgm_read stuff with straight variables, ran the program, and now everything seems to be working beautifully. Oh well!