ATTiny + PROGMEM

Hi there,

Since I read this article on High-Low-Tech, I've been trying to get my ATTiny45-20PU to play a piece by Bach.
So far, it's working quite well. The only problem is that the IC can't take more than nine bars of notes - I guess, this fills the capacity of the RAM.

Therefore, I wanted to save the scores to the flash memory to save RAM. For reasons unknown, this didn't seem to work out.

This works w/o any problems:

/**************************

Plays Wohltemperiertes Clavier Prelude 1 by J.S.Bach (BWV 846)
on Pin 0
Programmed for an ATTiny45

2012, Niklaus Messerli

***************************/

int periods[] = {19250,18169,17149,16186,15278,14421,13611,12847,12126,11446,10803,10197,9625,9084,8574,8093,7639,7210,6805,6423,6063,5723,5401,5098,4812} ;
int song[]  = {3,7,10,15,19,10,15,19,3,5,12,17,20,12,17,20,2,5,10,17,20,10,17,20,3,7,10,15,19,10,15,19,3,7,12,19,24,12,19,24,3,5,9,12,17,9,12,17,2,5,10,17,22,10,17,22,2,3,7,10,14,7,10,14,0,3,7,10,14,7,10,14} ;

unsigned long time;
unsigned long time2;
unsigned long timeTone;
boolean on; // speaker high/low?
boolean repeat; // each half bar is repeated in bwv 846, saving space
int notecounter; 
int barcounter;
int currentNote;

void setup() {                
  pinMode(0, OUTPUT); // speaker
  time = 0;
  time2 = 0;
  timeTone = 0;
  on = 0;
  repeat = 0;
  notecounter = 0;
  barcounter = 0;
  currentNote = 16168;
}

void loop() {
  time2 = micros(); // only call micros() once probably saves resources. i guess...
  
  if(time2 - timeTone > 2000000){ // about 0.5s per 16th-note
    time = time2;
    timeTone = time2;
    notecounter++;
    if(!(notecounter % 8)){ // one half-bar is reached
      if(repeat){ // one full bar
        barcounter++;
        repeat = 0;
      } else repeat = 1;
      notecounter = 0;
    }
    currentNote = periods[song[notecounter+barcounter*8]];
  }
  
  if(time2 - time > currentNote){
    time = time2;
    on = 1 - on;
    digitalWrite(0, on ? HIGH : LOW);
  }
}

Whereas this just produces random beeping:

/**************************

Plays Wohltemperiertes Clavier Prelude 1 by J.S.Bach (BWV 846)
on Pin 0
Programmed for an ATTiny45

2012, Niklaus Messerli

***************************/

#import <avr/pgmspace.h>

int periods[] = {19250,18169,17149,16186,15278,14421,13611,12847,12126,11446,10803,10197,9625,9084,8574,8093,7639,7210,6805,6423,6063,5723,5401,5098,4812} ;
const int song[] PROGMEM = {3,7,10,15,19,10,15,19,3,5,12,17,20,12,17,20,2,5,10,17,20,10,17,20,3,7,10,15,19,10,15,19,3,7,12,19,24,12,19,24,3,5,9,12,17,9,12,17,2,5,10,17,22,10,17,22,2,3,7,10,14,7,10,14,0,3,7,10,14,7,10,14} ;

...etc.

Is there a difference between reading from RAM and reading from Flash?
Or is pgmspace.h filling Flash itself?
Or am I just too stupid to realize the obvious?

Thanks in advance for any help!
nik

bach_ram.mp3 (295 KB)

bach_flash.mp3 (225 KB)

Is there a difference between reading from RAM and reading from Flash?

Yes. They exist in different address spaces. You have to use special functions to get bytes out of Flash/PROGMEM:

http://www.nongnu.org/avr-libc/user-manual/group__avr__pgmspace.html

johnwasser:
You have to use special functions to get bytes out of Flash/PROGMEM:

avr-libc: <avr/pgmspace.h>: Program Space Utilities

That's exactly what I was looking for.
Now I could probably fit Beethoven's 9th on that ATTiny, thank you very much!

nik