Reading bytes from flash memory

Im trying to read data from the flash memory, my data is a two dimensional array of bytes. If I try to read individual bytes with pgm_read_byte(), the values all return 0. But if I use pgm_read_word and evaluate each byte the values are as expected. While this isn't a big deal since the second dimension of the array is 8 bytes, it is a little inconvenient. Clearly I've made a mistake, could someone advise me where I am going wrong?

Best Regards
Josh

const byte squareFont[84][8]  PROGMEM = { ... }


  // this doesn't work
  byte a = pgm_read_byte(&squareFont[0]); 
  byte b = pgm_read_byte(&squareFont[1]); 
  Serial.println(a); // prints 0
  Serial.println(b); // prints 0
  
  // but if we get a uint16 and mask off each byte we get the correct values
  int testByte = pgm_read_word(&squareFont[0]);
  byte low = testByte & 255;
  byte high = (testByte & (255 << 8)) >> 8;
  Serial.println();
  Serial.println(low); // prints 0 
  Serial.println(high); // prints 62

This reads the first byte of the second (8-byte) element of the array. I think you wanted squareFont[0][1].

It might be easier to use memcpy_P() to copy all eight bytes to an array in ram.

1 Like
const byte squareFont[84][8]  PROGMEM = { ... }

Let's assume this array is stored at flash memory address 5000.

byte a = pgm_read_byte(&squareFont[0]);

This will read the byte at address 5000.

byte b = pgm_read_byte(&squareFont[1]);

This will read the byte at address 5008.

int testByte = pgm_read_word(&squareFont[0]);

This will read the bytes at address 5000 and 5001.

So they won't necessarily give the same result, unless address 5008 happens to contain the same value as address 5001. Which in this case it doesn't.

1 Like

Thanks! For some reason I was sure I wouldn't be able to access the data on the flash using 2d square braces, I thought I would have to walk the array 0 to 84*8-1.

You are correct I did mean squareFont[0][1]. Thanks for your suggestion of memcpy_P I will investigate. Thanks!

That is how I do it. I tried failed at passing two-dimension arrays to functions and decided, using a single-dimension array, with the math you mention, was what I needed. A flat array was good enough to read ten bits wide and two hundred fifty long, AND I could have more sets of arrays of any length (not 10x250)... the calculation was; pgm_read_byte(&list[rows * columns + column]))

Thanks for your reply. I had considered making the 2d array flat also, but ultimately I didn't need to. I think my reasoning regarding array access was based on passing 2d arrays to functions, which I couldn't figure out how to do. So my solution was to pass a pointer to the start of the array.

void fontCopy(const byte * f) { 
  byte b;

  for (int i = 0; i < 84; ++ i) {
    for (int j = 0; j < 8; ++j) {
      font[i][j] = pgm_read_byte(&f[i*8 + j]); 
    }
  }

  calcCharBounds();
}

Here's one way. Compiles, untested because I don't have an AVR board handy.

#include "Arduino.h"

template<typename T, size_t ROWS, size_t COLS>
void fontCopy(T (&dest)[ROWS][COLS], const T (&src)[ROWS][COLS]) {
	memcpy_P(&dest[0][0], &src[0][0], ROWS * COLS * sizeof(T));
}

const uint8_t squareFont[84][8]  PROGMEM = { 0 }; // <--- Fill in With Real Font Data

void setup() {
	uint8_t font[84][8];

	fontCopy(font, squareFont);
}

void loop() {

}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.