0

Is it safe to use PROGMEM variable like dynamically allocated memory (a pointer to PROGMEM variable which is out of scope).

I need this so I can generate a variable size (before compilation), constant values, lookup array stored in flash.

Working example:

class Ex_class {
  public:
    Ex_class(int table_size, int value_range) {
      int flash_table[table_size + 1] PROGMEM;
      _ex_table = flash_table;
      for (int i = 0; i <= table_size; i++) {
        _ex_table[i] = random(value_range);
      }
    }

    int get_value(int index) const { return _ex_table[index]; }

  private:
    int* _ex_table;
};

void setup() {
  randomSeed(analogRead(0));
  Serial.begin(9600);
  Ex_class ex_object(5, 50);
  for (int i = 0; i <= 5; i++) {
    Serial.print(i); Serial.print(": "); Serial.println(ex_object.get_value(i));
  }
}

void loop() {}
  • I am amazed this even compiles... You cannot assign a value to a PROGMEM variable, the only thing you can do with PROGMEM is store compile-time constants. And you cannot dereference a pointer to PROGMEM with * nor [], you need one of the pgm_read_*() macros. – Edgar Bonet Feb 17 '17 at 20:46
  • The compiler cannot run "Ex_class ex_object(5, 50);" at compile time. – Mikael Patel Feb 17 '17 at 20:50
  • I am surprised too, but it actually works. – Vasil Kalchev Feb 17 '17 at 20:51
  • 1
    It's probably getting the data from RAM that was allocated (and deallocated) in the stack. – Edgar Bonet Feb 17 '17 at 21:06
  • You are right, it stored a new variable in the same address. – Vasil Kalchev Feb 17 '17 at 21:14
4

The closest I could get to what you are trying to do is this:

template <size_t table_size> struct Ex_class {
  int get_value(int index) const {
    return pgm_read_word(&_ex_table[index]);
  }
  int _ex_table[table_size];
};

void setup() {
  Serial.begin(9600);
  static PROGMEM const Ex_class<5> ex_object = {1, 2, 3, 4, 5};
  for (int i = 0; i < 5; i++) {
    Serial.print(i);
    Serial.print(": ");
    Serial.println(ex_object.get_value(i));
  }
}

void loop() {}

avr-nm and avr-objdump confirmed that the object lives indeed in the text section of the program. Please note that:

  • The object is PROGMEM const. It would make no sense to try to put in PROGMEM anything that is not constant.

  • The object is allocated statically. It can be either a global or a static local, but not an automatic local like in your example.

  • I am using aggregate initialization here. I know no other way to statically initialize an array of variable length. If you have an idea, I would be interested to know though.

  • Thanks. The only thing I can think of is initializing the flash variables separately (because they need to be calculated) and then putting the pointers to them in an array. It shouldn't be a problem since the flash is read-only. – Vasil Kalchev Feb 17 '17 at 22:13

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.