problems accessing PROGMEM


i have a problem accessing data in progmem. i dont't get back the correct data. so building a dds sound machine i want to read in a song listet like this

unsigned char song[] PROGMEM = {
  A_4, A_5, C_1, ...

i use enum for easier access into the notetab

enum {G_1, Gs1, A_1, ... , A_4, ...} notenames;

const double refclk = 31376.6;

const unsigned long notetab[] PROGMEM = {
  49.00 * pow(2,32) / refclk,
51.91 * pow(2,32) / refclk,
55.00 * pow(2,32) / refclk,
440.0 * pow(2,32) / refclk, // A_4

know i have a pointer to the song array

volatile unsigned char* song_ptr = &greensleeves[0];

now and then i increment the song pointer an read the new note

song_note_tone = pgm_read_byte(song_ptr++) & 0x3f; // 0x3f = 63 , got 64 notes -> like modulo

and then my problem happens. assume that the current note is A_4 position 38 in notetab. now in song_note_tone the enum for A_4 is stored with this i want to access notetab and get the correct caluclatet dds tune word for A_4 and this is 60229140

know i tried wild combinations of different array indices but should be all the same:

Serial.print("song_note_tone: ");
Serial.println(song_note_tone, DEC);

// OUTPUT: song_note_tone: 38


// OUTPUT: &
int check = int(song_note_tone);

// OUTPUT: 38


// OUTPUT: 878657792
Serial.print("note_value: ");
Serial.println(notetab[song_note_tone], DEC);
// OUTPUT: note_value: 878657792

Serial.print("38: ");
Serial.println(notetab[38], DEC);

// OUTPUT: 60229140

Serial.print("A_4: ");
Serial.println(notetab[A_4], DEC);

// OUTPUT: 60229140
Serial.println(pgm_read_byte (notetab[song_note_tone]), DEC);

// OUTPUT: 255
tword_m = pgm_read_byte(¬etab[song_note_tone]);

// OUTPUT: 20

what can i do here? i just get the correct value when i access over the direct int 38, but not with the song_gnot_tone... what is wrong here?

regards, peter

There is a lib to make acces to PROG_MEM easier, you might take a look at it See

Serial.println(pgm_read_byte (notetab[song_note_tone]), DEC);

notetab is an array of longs, so you will need the equivalent of pgm_read_long(¬etab[song_note_tone])

It looks like that should be pgm_read_dword()

thanks for thoses hints.
i tried to use:

error: 'pgm_read_word_far' was not declared in this scope

but it gives me this error:

error: ‘pgm_read_word_far’ was not declared in this scope

i don’t know why, because i included #include <avr/pgmspace.h>
and i looked it up and the function is defined:

667: #define pgm_read_word_far(address_long)  __ELPM_word((uint32_t)(address_long))

so the other 32-bit function do not work either.

#define pgm_read_byte_far(address_long)  __ELPM((uint32_t)(address_long))
#define pgm_read_dword_far(address_long) __ELPM_dword((uint32_t)(address_long))
#define pgm_read_float_far(address_long) __ELPM_float((uint32_t)(address_long))

the _far functions are for the AVRs with more than 64k of flash memory (atmega1280, atmega2560); they use 32 bits for the ADDRESS to read FROM. You just need to read 32bits of DATA from a normal 16-bit address, so you shouldn't be using the _far versions. I think.

(I'm also pretty sure that pgm_read_byte() and etc get properly defined to use either the _near or _far versions automatically based on the processor setting at the time of compile, so you probably don't ever need to use anything other than pgm_read_byte, pgm_read_word, or pgm_read_dword...)

There was a good tutorial on