PROGMEM problems with arrays

Hello. I am relatively new to Arduino code and I am having a problem reading an array from FLASH. I wrote a simple program to test it out and I am stuck. Any suggestions would be appreciated. Here is the code:

unsigned char i = 0; // Counter
PROGMEM const unsigned int mysine[] = { 0, 100, 3, 5, 101};

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);

Serial.print(mysine[0]); Serial.print("\n");
Serial.print(mysine[1]); Serial.print("\n");
Serial.print(mysine[2]); Serial.print("\n");
Serial.print(mysine[3]); Serial.print("\n");
Serial.print(mysine[4]); Serial.print("\n\n");

for (i = 0; i < 5; i++) {
Serial.print(i); Serial.print(": "); Serial.print(mysine[i]); Serial.print("\n");
}
}

When I run it this is what gets printed on the serial monitor:
0
100
3
5
101

0: 0
1: 184
2: 0
3: 1
4: 0

So if I put a number in the array index I get the correct info back. If I use a variable I get garbage back. I have tried the following:

  1. Changing the data does not change the data I get back (2nd group)
  2. If I read the array to an integer variable (temp) and then use that variable in the print statement I get the same results
  3. I have moved the PROGMEM statement to all the locations in the declaration statement and it did not change the results.

I have a much larger program I am working on, but I wrote this small one just to try and figure out the problem.

Thanks in advance for your help,

Sean

Did you read the PROGMEM documentation?

You have to use special functions to load data from PROGMEM: avr-libc: <avr/pgmspace.h>: Program Space Utilities

Yes, I did read the PROGMEM documentation.

It also says you only have to add pgmspace.h with older versions of the IDE, but I tried it anyway and got the same results.

First line : #include<avr/pgmspace.h>

I used this same declaration in a demo program for a 128x64 OLED and it worked fine. So I thought I would use it in my own program. Obviously I have missed something.

That only prepares the library for use. You didn't use any of the functions in it that you need. The documentation does explain it, please read more of it.

True. But why does "Serial.print(mysine[1]);" print out the correct data but "i=1; Serial.print(mysine[i]);" does not?

Perhaps the compiler out-smarted you. If a constant value is known at compile time, that value may be hardcoded into the object code.

Thanks for your help. I guess I really did not understand how to use FLASH storage. It is working now. Here is the new code:
#include<avr/pgmspace.h>
unsigned char i = 0; // Counter
PROGMEM const uint16_t mysine[] = { 0, 100, 3, 5, 101};

void setup() {

  • // put your setup code here, to run once:*
    Serial.begin(9600);

Serial.print(mysine[0]); Serial.print("\n");
Serial.print(mysine[1]); Serial.print("\n");
Serial.print(mysine[2]); Serial.print("\n");
Serial.print(mysine[3]); Serial.print("\n");
Serial.print(mysine[4]); Serial.print("\n\n");

/ for (i = 0; i < 5; i++) {*

  • Serial.print(i); Serial.print(": "); Serial.print(mysine[i]); Serial.print("\n");*

  • }*

  • /

  • for (i = 0; i < 5; i++) {*

  • Serial.print(i); Serial.print(": "); Serial.print(pgm_read_word_near(mysine +i)); Serial.print("\n");*

  • }*

}
void loop() {}

and here is what I get back:
0
100
3
5
101

0: 0
1: 100
2: 3
3: 5
4: 101

Thanks again!!!!

could be temporary memory, which would explain why it gets overwritten with gibberish

This is still incorrect, you're just getting lucky with compiler optimization. You have to use

Serial.print(pgm_read_word(&mysine[4])); Serial.print("\n\n");

@olearyds, can you please spend some time reading How to get the best out of this forum and in future apply code tags to code that you post so we don't have to look at things like mysine[] but at mysine[]. It also makes it easier to read (and copy if necessary).

1 Like

So the code is working now. But to be thorough, I tried your &mysine[4] and got a no matching function call to 'print(const uint16_t)' error.

PROGMEM const uint16_t mysine[] = { 0, 100, 3, 5, 101};

Serial.print(&mysine[0]); Serial.print("\n");

Please read my previous post again. Where did the pgm_read_word go in your snippet?

@PieterP Sorry, I must have misunderstood your comment. I have updated my code as follows:

#include<avr/pgmspace.h>
unsigned char i = 0;                      // Counter
PROGMEM const uint16_t mysine[] = { 0, 100, 3, 5, 101};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  Serial.print(pgm_read_word(&mysine[0])); Serial.print("\n");
  Serial.print(pgm_read_word(&mysine[1])); Serial.print("\n");
  Serial.print(pgm_read_word(&mysine[2])); Serial.print("\n");
  Serial.print(pgm_read_word(&mysine[3])); Serial.print("\n");
  Serial.print(pgm_read_word(&mysine[4])); Serial.print("\n\n");

  for (i = 0; i < 5; i++) {
    Serial.print(i); Serial.print(": "); Serial.print(pgm_read_word_near(mysine + i)); Serial.print("\n");
  }
}
void loop() {}

With the following results:
0
100
3
5
101

0: 0
1: 100
2: 3
3: 5
4: 101

Even though it is the same as before I see your point. I don't want to be lucky with code, but rather do it right so it works all the time. Thank you for your help.

where is fun in that?

1 Like

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