Hi folks,
First, I'm really, really green at this, so thanks in advance for bearing with me. I'm using an Uno.
I'm building a simple RFID based music player for my son, and I've run into problems adding more than about 12 songs to my code, as it gives me an error stating that my global variables exceed the dynamic memory limit (2,974 out of 2,048 with the code below). My goal is to have about 25 tracks on here if possible.
Here's my code:
/*
jukebox
this is the firmware for the contact-free jukebox.
that can play audio tracks depending on rfid tags.
attached to the arduino is an adafruit waveshield
and an id-12 rfid reader.
created @ 8.1.12 by dominik grob (@ruedi)
more information: http://tmblr.co/ZKZ-twHiQ_OK
*/
#include <FatReader.h>
#include <SdReader.h>
#include <avr/pgmspace.h>
#include "WaveUtil.h"
#include "WaveHC.h"
#include <SoftwareSerial.h>
// audio settings
boolean PlayComplete = false;
long playnext_prevmillis = 0;
long playanother_time = 3000;
// sdcard settings
SdReader card;
FatVolume vol;
FatReader root;
FatReader f;
WaveHC wave;
// rfid settings
SoftwareSerial RFIDSerial(8, 6);
int RFIDResetPin = 7;
char RFIDtag[14];
int RFIDindex = 0;
boolean RFIDreading = false;
boolean debug = true;
// define tag id and tracks
#define NUMTAGS 27
char audiotags[NUMTAGS][27] = {"0000EE1E6E9E",
"0000EECFC8E9",
"0000EECFA889",
"000048E1FD54",
"0000EB80A1CA",
"0000EC195EAB",
"0000EC1947B2",
"00004A201379",
"00004A1F590C",
"0000EEAF6322",
"000048888141",
"0000488860A0",
"000048A5CF22",
"000048A5CC21",
"000048572A35",
"00004A32B3CB",
"00004A32D2AA",
"000048578798",
"000048578897",
"0000488677B9",
"00004885FC31",
"0000EE3339E4",
"0000EECFCBEA",
"0000EECFC6E7",
"00004A1BDD8C"};
// make sure soundfile names are not longer then 8 chars (without filetype)
char audiofiles[NUMTAGS][27] = {"HELLO.wav",
"GOODBYE.wav",
"BIPPOLO.wav",
"BUTTER.wav",
"FTDOWN.wav",
"FTLIST.wav",
"FTSPRING.wav",
"FTTOM.wav",
"GUSTOV.wav",
"HORNBACK.wav",
"LUCKY.wav",
"MCBRIDE.wav",
"POLKA.wav",
"RABBIT.wav",
"RMAMBER.wav",
"RMRUBY.wav",
"RMSKY.wav",
"RMSTORM.wav",
"RMSUNNY.wav",
"SPOT.wav",
"STEAK.wav",
"STONE.wav",
"TAD.wav",
"TWINBABY.wav",
"RMINKY.wav"};
void setup() {
Serial.begin(9600);
putstring_nl("debug");
putstring_nl("----------------");
putstring("Free RAM: ");
Serial.println(freeRam());
// set output pins for DAC control
// pins are defined in the library
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
// pin13 LED
pinMode(13, OUTPUT);
if (!card.init()) {
putstring_nl("Card init. failed!");
sdErrorCheck();
while(1);
}
// enable optimize read
card.partialBlockRead(true);
// fat partition?
uint8_t part;
for (part = 0; part < 5; part++) {
if (vol.init(card, part))
break;
}
if (part == 5) {
putstring_nl("No valid FAT partition!");
sdErrorCheck();
while(1);
}
// show infos
putstring("Using partition ");
Serial.print(part, DEC);
putstring(", type is FAT");
Serial.println(vol.fatType(),DEC);
if (!root.openRoot(vol)) {
putstring_nl("Can't open root dir!");
while(1);
}
putstring_nl("> sdcard ready");
// rfid setup
pinMode(RFIDResetPin, OUTPUT);
digitalWrite(RFIDResetPin, HIGH);
RFIDSerial.begin(9600);
putstring_nl("> rfid ready");
// play startup chime
delay(500); // avoid loudspeaker click noise
playcomplete("CHIME.wav");
}
void loop() {
RFIDindex = 0;
// rfid data?
while(RFIDSerial.available()) {
int readByte = RFIDSerial.read();
if(readByte == 2) RFIDreading = true;
if(readByte == 3) RFIDreading = false;
if(RFIDreading && readByte != 2 && readByte != 10 && readByte != 13){
RFIDtag[RFIDindex] = readByte;
RFIDindex++;
}
}
// check tag and play track if tag id found
checkTag(RFIDtag);
// prepare for next read
clearTag(RFIDtag);
resetReader();
}
void playcomplete(char *name) {
playfile(name);
while (wave.isplaying) {
// playing
}
}
void playfile(char *name) {
if (wave.isplaying) {
wave.stop();
}
if (!f.open(root, name)) {
putstring("Couldn't open file "); Serial.println(name); return;
}
if (!wave.create(f)) {
putstring_nl("Not a valid WAV"); return;
}
wave.play();
}
void resetReader() {
digitalWrite(RFIDResetPin, LOW);
digitalWrite(RFIDResetPin, HIGH);
delay(150);
}
void clearTag(char one[]) {
for(int i = 0; i < strlen(one); i++){
one[i] = 0;
}
}
void checkTag(char tag[]) {
if(strlen(tag) == 0) return;
if(debug) {
putstring("rfid tag id: ");
for(int d = 0; d < 12; d++) {
Serial.print(tag[d]);
}
Serial.println();
}
boolean matching = true;
// compare tag id
for(int a = 0; a < NUMTAGS; a++) {
matching = true;
for(int c = 0; c < 12; c++) {
if(tag[c] != audiotags[a][c]) {
matching = false;
break;
}
}
// in case of a match play the track
if(matching) {
putstring("playing: "); Serial.println(audiofiles[a]);
delay(500); // avoid loudspeaker click noise
if(PlayComplete) {
digitalWrite(RFIDResetPin, LOW);
playcomplete(audiofiles[a]);
} else {
unsigned long playnext_currentmillis = millis();
// wait with playing another audio track
if(playnext_currentmillis - playnext_prevmillis > playanother_time) {
playfile(audiofiles[a]);
playnext_prevmillis = playnext_currentmillis;
}
}
break;
}
}
}
// ---------------------------
// debug functions
// ---------------------------
int freeRam(void) {
extern int __bss_end;
extern int *__brkval;
int free_memory;
if((int)__brkval == 0) {
free_memory = ((int)&free_memory) - ((int)&__bss_end);
}
else {
free_memory = ((int)&free_memory) - ((int)__brkval);
}
return free_memory;
}
void sdErrorCheck(void) {
if (!card.errorCode()) return;
putstring("\n\rSD I/O error: ");
Serial.print(card.errorCode(), HEX);
putstring(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
Is there anywhere in there that I can reduce the memory footprint so that I can have more than a dozen or so files linked? Note that I don't really have a way (that I know of) to reduce the length of the RFID codes under "audiotags", because I only have a reader, not a writer. I could change the "audiofiles" names to anything.
Thanks very much for any help you can give, I really appreciate it.