accessing data stored usingn PROGMEM

I'm using an LCD1604 screen to make a video game(crap idea, I know, but its really just a learning exercise) and I'm running out of local memory so in the hopes of improving this situation I've resorted to F()'s and PROGMEM.
the only constants I have that are not defined using #define are LCD special characters

const byte datRunner[8][8] PROGMEM =
{ { B00100,  // RUN 0
    B00101,
    B11111,
    B10100,
    B10100,
    B01100,
    B01010,
    B01010
  },

  { B00100,  // RUN 1
    B10100,
    B11111,
    B00101,
    B00101,
    B00110,
    B01010,
    B01010
  },

  { B00100,  // STAND
    B00100,
    B01110,
    B01110,
    B10101,
    B00100,
    B01010,
    B01010
  },

  { B00101,  // Shoot Up
    B00101,
    B01110,
    B01100,
    B01100,
    B00110,
    B01010,
    B01010
  },

  { B00100,  // Shoot Down
    B00100,
    B01110,
    B10101,
    B00101,
    B01101,
    B01010,
    B01010
  },

  { B00000,  // Shoot Left
    B00010,
    B00010,
    B11110,
    B00010,
    B01100,
    B10100,
    B10011
  },

  { B00000,  // Shoot Right
    B01000,
    B01000,
    B01111,
    B01000,
    B00110,
    B00101,
    B11001
  },

  { B11111,  // Wall
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111,
    B11111
  }
};
[\code]

and so I've written a function to access this data before setting that as Special Characters for the LCD1604.

[code]
byte* chrDatRunner(int intIndex)
{
  byte bytRetVal[8];

  for (byte bytCounter = 0; bytCounter < 8; bytCounter++)
    bytRetVal[bytCounter] = pgm_read_word_near(8 * intIndex  + bytCounter);
  return bytRetVal;
}

void charInit()
{
  for (int intCharCounter = 0; intCharCounter < defSpecChar_NumChars; intCharCounter++)
  {
    byte *bytSpecialCharacter = chrDatRunner(intCharCounter);
    lcd.createChar(intCharCounter, bytSpecialCharacter);
  }
}

I'm not sure whether its a pointer issue or a memory addressing issue but I've tried variations of the latter and still get a set of funky characters on the screen for both the player character (7 or 8 of these special characters) and the Wall. so, I don't know what I'm doing wrong.

You can't directly create an array of an array of PROGMEM constants. Read this reference where it talks about this, but juses strings as the example. You are using bytes, but the same idea.

bytRetVal[bytCounter] = pgm_read_word_near(8 * intIndex  + bytCounter);

i think you've specified the offset into the datRunner array, but don't specified the based.

bytRetVal[bytCounter] = pgm_read_word_near( datRunner + 8 * intIndex  + bytCounter);

bytRetVal is a local variable, when you exit the function the memory used for bytRetVal will be reused by other code so you cannot rely on its contents remaining unchanged.

byte* chrDatRunner(int intIndex)
{
  byte bytRetVal[8];
  for (byte bytCounter = 0; bytCounter < 8; bytCounter++)
    bytRetVal[bytCounter] = pgm_read_word_near(8 * intIndex  + bytCounter);
  return bytRetVal;
}

I usually just use memcpy_P when initializing special LCD characters from PROGMEM:

void charInit()
{
  byte bytSpecialCharacter[8];
  for (int intCharCounter = 0; intCharCounter < defSpecChar_NumChars; intCharCounter++)
  {
    memcpy_P(bytSpecialCharacter, datRunner[intCharCounter], 8);
    lcd.createChar(intCharCounter, bytSpecialCharacter);
  }
}

gcjr:

bytRetVal[bytCounter] = pgm_read_word_near(8 * intIndex  + bytCounter);

i think you've specified the offset into the datRunner array, but don't specified the based.

bytRetVal[bytCounter] = pgm_read_word_near( datRunner + 8 * intIndex  + bytCounter);

thank you,
that's correct .. and I'm sure its a start but there's still the issue of declaring an array in PROGMEM...

david_2018:
I usually just use memcpy_P when initializing special LCD characters from PROGMEM:

void charInit()

{
  byte bytSpecialCharacter[8];
  for (int intCharCounter = 0; intCharCounter < defSpecChar_NumChars; intCharCounter++)
  {
    memcpy_P(bytSpecialCharacter, datRunner[intCharCounter], 8);
    lcd.createChar(intCharCounter, bytSpecialCharacter);
  }
}




Perfect! that worked out great.

blh64:
You can't directly create an array of an array of PROGMEM constants.

Sure you can:

const byte datRunner[8][8] PROGMEM = {
  {0b00100, 0b00101, 0b11111, 0b10100, 0b10100, 0b01100, 0b01010, 0b01010},
  {0b00100, 0b10100, 0b11111, 0b00101, 0b00101, 0b00110, 0b01010, 0b01010},
  {0b00100, 0b00100, 0b01110, 0b01110, 0b10101, 0b00100, 0b01010, 0b01010},
  {0b00101, 0b00101, 0b01110, 0b01100, 0b01100, 0b00110, 0b01010, 0b01010},
  {0b00100, 0b00100, 0b01110, 0b10101, 0b00101, 0b01101, 0b01010, 0b01010},
  {0b00000, 0b00010, 0b00010, 0b11110, 0b00010, 0b01100, 0b10100, 0b10011},
  {0b00000, 0b01000, 0b01000, 0b01111, 0b01000, 0b00110, 0b00101, 0b11001},
  {0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111, 0b11111}
};

void setup() {
  Serial.begin(115200);
  delay(1000);
  for (uint8_t row = 0; row < 8; row++) {
    for (uint8_t col = 0; col < 8; col++) {
      uint8_t mask = 0b10000;
      uint8_t value = pgm_read_byte((uint8_t *)&datRunner[row][col]);
      for (uint8_t bit = 0; bit < 5; bit++) {
        if (value & mask) {
          Serial.print("1");
        } else {
          Serial.print("0");
        }
        mask >>= 1;
      }
      Serial.print(" ");
    }
    Serial.println();
  }
}

void loop() {
}

Output in Monitor:

00100 00101 11111 10100 10100 01100 01010 01010 
00100 10100 11111 00101 00101 00110 01010 01010 
00100 00100 01110 01110 10101 00100 01010 01010 
00101 00101 01110 01100 01100 00110 01010 01010 
00100 00100 01110 10101 00101 01101 01010 01010 
00000 00010 00010 11110 00010 01100 10100 10011 
00000 01000 01000 01111 01000 00110 00101 11001 
11111 11111 11111 11111 11111 11111 11111 11111

blh64:
You can't directly create an array of an array of PROGMEM constants. Read this reference where it talks about this, but juses strings as the example. You are using bytes, but the same idea.

The strings are what will get you into trouble with PROGMEM, because the array ends up being an array of pointers to the strings, not the strings themselves. That will store the array itself in PROGMEM, but the strings get stored in ram. You can put it all in PROGMEM using a two-dimension char array, but that wastes memory because you have to allocate memory based on the longest string, works well if all strings are the same length.

void charInit()

  byte bytSpecialCharacter[8];
  for (int intCharCounter = 0; intCharCounter < defSpecChar_NumChars; intCharCounter++)
  {
    memcpy_P(bytSpecialCharacter, datRunner[intCharCounter], 8);
    lcd.createChar(intCharCounter, bytSpecialCharacter);
  }
}

You could save some RAM by changing

byte bytSpecialCharacter[8];

to

char bytSpecialCharacter[8];

You could also eliminate the function and move this into setup() if it never needs to be called more than once.

You could save some RAM by changing

byte bytSpecialCharacter[8];

to

char bytSpecialCharacter[8];

How does that save RAM? byte and char are both one byte (8 bits) of storage.