integer arrays in Progmem does not work [solved]

Hi,

I am trying to put constant integer arrays into the flash rom of an Arduino Nano V3, but it does not work. I want to store 7 (or more) integer arrays and select only one, depending on a random number. The one array should then be copied into the RAM, so that it can be read and processed…(actually, it does not have to be writeable, so in principal it could still reside in flash, if possible…)

Here are the (as I think) most important pieces of the code:

#include <avr/pgmspace.h>

#define  hh    4048    // 247 Hz
#define  nc    3821    // 262 Hz 
#define  cis   3606    // 277 Hz
#define  d     3404    // 294 Hz
#define  es    3212    // 311 Hz
#define  e     3032    // 330 Hz 
#define  f     2862    // 349 Hz
#define  fis   2702    // 370 Hz
#define  g     2550    // 392 Hz 
#define  gis   2407    // 415 Hz
#define  a     2272    // 440 Hz 
#define  b     2144    // 466 Hz 
#define  h     2024    // 494 Hz 
#define  C     1910    // 523 Hz  
#define  Cis   1803    // 554 Hz
#define  D     1702    // 587 Hz 
#define  Es    1606    // 622 Hz
#define  E     1516    // 659 Hz
#define  F     1431    // 699 Hz
#define  Fis   1351    // 740 Hz
#define  G     1275    // 784 Hz
#define  Gis   1203    // 831 Hz
#define  A     1136    // 880 Hz
#define  B     1072    // 932 Hz
#define  H     1012    // 988 Hz
#define  CC    955     // 1047 Hz

// variablen für die melodien
int melody[100];
int beats[100];
int maxcount;

...
...


void setup() {

...
...
  prog_uint16_t song1[] PROGMEM = {  h, h, C, D, D, C, h, a , g, g, a, h, h, a, a, h, h, C, D, D, C, h, a , g, g, a, h, a, g, g, R};
  prog_uint16_t beats1[] PROGMEM = { 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, 8, 32, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 24, 8, 32, 200 };
  
  prog_uint16_t song2[] PROGMEM = { f, f, f, b, F, Es, D, C, B, F, Es, D, C, B, F, Es, D, Es, C, f, f, f, b, F, Es, D, C, B, F, Es, D, C, B, F, Es, D, Es, C  };
  prog_uint16_t beats2[] PROGMEM = { 5, 5, 5, 32, 32, 5, 5, 5, 32, 16, 5, 5, 5, 32, 16, 5, 5, 5, 32, 5, 5, 5, 32, 32, 5, 5, 5, 32, 16, 5, 5, 5, 32, 16, 5, 5, 5, 32};

... and so on ....

// nach zufallszahlen auswählen
  if(thema<30)
  {
 
  maxcount = 31;
  for (int i=0;i<maxcount;i++)
  {
    melody[i] = pgm_read_word_near(&song1[i]);
    beats [i] = pgm_read_word_near(&beats1[i]);
    melody[i] = int (melody[i] / 1.1);
  }

  elseif .....

...

void loop() 
{ 
// MELODY and TIMING  =======================================
//  melody[] is an array of notes, accompanied by beats[], 
//  which sets each note's relative length (higher #, longer note) 


  for (int i=0; i<maxcount; i++) {
    tone_ = melody[i];
    beat = beats[i];

    duration = beat * tempo; // Set up timing

    playTone(); 
    // A pause between notes...
    delayMicroseconds(pause);
  }

....

...

without the progmem stuff it worked. But now, the additional melodies do not fit into RAM any more.

I tried a few different ways to move the values from flash to ram and searched for solutions, but it still does not work and I need help. Does anyone has a suggestion or sees my error?

thanks in advance!
Uwe

Move declaration of arrays out of setup, basically them declare global.

I don't see how that helps, unless there's a scope issue we can't see because we can't see all the code.

Oh my god! I tried so many variations, but didn't even think of the basics (shame about me)...many thanks! The problem is solved....

Thanks so much for posting this question. I had the same issue and did a search before posting a new thread and found this one. I was receiving incorrect data when I had everything done in setup(). I moved the progmem declaration before the setup() and now it works!

I would like to understand why this matters, is there a reason it has to be defined as global, or is that just a rule of progmem declarations that they always are supposed to be defined in the global declaration area?

The test code I used was:

unsigned char mydata[] PROGMEM = {82,83,82,82};
byte hut = pgm_read_byte(&(mydata[1]));
Serial.print ("READING PROGMEM POCKET 2: ");
Serial.print (hut);

I got a strange unexected value when I ran this as a block of code inside setup() but as soon as I moved the first line out of setup() it worked. Thanks again for posting this question!

Does anyone know the why behind why it works this way and has to be done this way?

I don't know why the compiler even accepts progmem declarations in auto variables. A variable (not declared static) inside a function has to reside on the stack, which directly conflicts with keeping it in program memory.