1

I am trying to store a large number of values into a couple of arrays using PROGMEM, but I am finding that a few of the values are read back corrupted. I am storing just 1s and 0s, but when I read these values back, I will sometimes get values greater than 1. I am using a MEGA 2560 to do this.

// Each array contains 32000 values
const byte VALUES_1[] PROGMEM = { 1, 0, 1, .... 0 };
const byte VALUES_2[] PROGMEM = { 1, 1, 0, .... 0 };
const byte VALUES_3[] PROGMEM = { 1, 0, 1, .... 1 };
const byte VALUES_4[] PROGMEM = { 1, 0, 1, .... 1 };
const byte VALUES_5[] PROGMEM = { 1, 0, 1, .... 1 };

const long ARR_LEN = 32000;
long index = 0;

void setup() {
  Serial.begin(57600);
  while (!Serial) {}
}

byte readNextValue() {
  if (index >= 160000L) {
    return -1;
  }

  Serial.print(index);
  Serial.print(" ");

  long arr = index / ARR_LEN;
  long i = index % ARR_LEN;
  index++;

  byte j = -1;
  switch(arr) {
    case 0:
      j = pgm_read_byte_far(VALUES_1 + i);
      Serial.println(j);
      return j;
    case 1:
      j = pgm_read_byte_far(VALUES_2 + i);
      Serial.println(j);
      return j; 
    case 2:
      j = pgm_read_byte_far(VALUES_3 + i);
      Serial.println(j);
      return j;
    case 3:
      j = pgm_read_byte_far(VALUES_4 + i);
      Serial.println(j);
      return j;
    case 4:
      j = pgm_read_byte_far(VALUES_5 + i);
      Serial.println(j);
      return j;
  }

  Serial.println("Unable to return next value");
  return -1;
}

void loop() {
  // put your main code here, to run repeatedly:
  readNextValue();
}

What I have noticed is that when I use pgm_read_byte_far for case 0 I will get garbage values for right away, but using pgm_read_byte_near will cause these garbage values to occur sometime later. Any insight to this problem is appreciated.

  • Don't use either near or far? Let the compiler work out which is which? – Majenko Apr 10 '18 at 23:58
  • Your total array size is 5 * 32000 = 160,000 bytes. Why not store it as bits which would only take 20000 bytes? Then all the issues of far-addressing would go away. You could use a small script to turn your 0s and 1s into suitable bytes, and then a simple macro or function to extract the individual bits. – Nick Gammon Apr 11 '18 at 1:42
  • Also see this question about indexing into large arrays, where I posted an answer that avoided corruption. – Nick Gammon Apr 11 '18 at 1:45
  • Thanks for the answers guys. Ill try some of the suggestions tomorrow and see how it goes. If worst comes to worst, it looks like I will have to just use bits like Nick suggested to avoid the 64k addressing problem that Arduino seems to have. – KaYBlitZ Apr 11 '18 at 2:34
  • The Mega has reasonably limited memory, if you are storing only 0 or 1 in a byte (8 bits) you lose a lot of memory (7 unused bits per byte). Consider combining 8 0's and 1's into 1 byte (using bit shifting operators). – Michel Keijzers Apr 11 '18 at 8:37
2

Just a follow up in case someone else has the same problem. One solution is Nick's answer in his comment, which grabs the far addresses first in the setup, storing them in an array, and using them. I

// Each array contains 32000 values
const byte VALUES_1[] PROGMEM = { 1, 0, 1, .... 0 };
const byte VALUES_2[] PROGMEM = { 1, 1, 0, .... 0 };
const byte VALUES_3[] PROGMEM = { 1, 0, 1, .... 1 };
const byte VALUES_4[] PROGMEM = { 1, 0, 1, .... 1 };
const byte VALUES_5[] PROGMEM = { 1, 0, 1, .... 1 };

long VALUES[] = { 0, 0, 0, 0, 0 };

const long ARR_LEN = 32000;
long index = 0;

void setup() {
  Serial.begin(57600);
  while (!Serial) {}

  VALUES[0] = (long) pgm_get_far_address(VALUES_1);
  VALUES[1] = (long) pgm_get_far_address(VALUES_2);
  VALUES[2] = (long) pgm_get_far_address(VALUES_3);
  VALUES[3] = (long) pgm_get_far_address(VALUES_4);
  VALUES[4] = (long) pgm_get_far_address(VALUES_5);
}

byte readNextValue() {
  if (index >= 160000L) {
    return -1;
  }

  Serial.print(index);
  Serial.print(" ");

  long arr = index / ARR_LEN;
  long i = index % ARR_LEN;
  index++;

  byte j = pgm_read_byte_far(VALUES[arr] + i);
  Serial.println(j);

  return j;
}

void loop() {
  // put your main code here, to run repeatedly:
  readNextValue();
}

This runs perfectly with all bytes correct. The better answer would be to convert the bytes into bits like everyone else was saying in order to save memory space.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.