Simultaneous use of mp3shield and rfid reader

Hi all,

after half a day of frustration I hope someone can help me here :slight_smile:

I want to play mp3s (using sparkfun’s mp3shield) controlled by an rfid reader (c522). I’m using an Arduino Mega. In order to use the sparkfun mp3shield i used jumpers to bridge
11 → 51
12 → 50
13 → 52
The SPI (51, 51, 52) is simultaneously also used by the rfid reader. My problem is now that the mp3shield seems to block the SPI while playing a file.
The only solution I saw is to wait until an audio file is finished playing and then check the rfid reader again - which doesn’t make sense in my project, i want to swap rfid cards in the middle of a song and listen to the new song.

I’m pasting below a piece of code that works perfectly because the test files track001.mp3 and track002.mp3 that i’m using are less then 5 seconds long and i’m putting a delay(5000); command after starting to play them so by the time the rfid reader is checking for new cards the song finished already. Replacing the delay(5000); by a delay(1000); would result in the arduino hanging after playing a second of the file and i have to reboot.

Any comments are most welcome :slight_smile:

#include <SPI.h>
#include <MFRC522.h>
#include <BlockDriver.h>
#include <FreeStack.h>
#include <MinimumSerial.h>
#include <SdFat.h>
#include <SdFatConfig.h>
#include <SysCall.h>
#include <SFEMP3Shield.h>

// Pins for rfid reader
#define RST_PIN   5     // Configurable, see typical pin layout above
#define SS_PIN    53    // Configurable, see typical pin layout above

byte currentByte = 0x00;

SdFat sd; 
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance
SFEMP3Shield MP3player; 
const uint8_t volume = 80; // MP3 Player volume 0=max, 255=lowest (off)

MFRC522::MIFARE_Key key;

void setup() {
 Serial.begin(9600);  // Initialize serial communications with the PC
 initSD();  // Initialize the SD card

 while (!Serial);     // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4)
 SPI.begin();         // Init SPI bus
 mfrc522.PCD_Init();  // Init MFRC522 card

void loop() {

 // Print out current card ID
 Serial.print(F("Card UID:"));
 Serial.print(mfrc522.uid.uidByte[3], HEX);

 // Check if a new card id is used and play the respective song
 if(mfrc522.uid.uidByte[3] != currentByte){
   currentByte = mfrc522.uid.uidByte[3];
   if(mfrc522.uid.uidByte[3] == 0xA4){
   else if(mfrc522.uid.uidByte[3] == 0x63){

void initSD()
 //Initialize the SdCard.
 if(!sd.begin(SD_SEL, SPI_HALF_SPEED)) 

void initMP3Player()
 uint8_t result = MP3player.begin();
 MP3player.setVolume(volume, volume);

rfid_test.ino (1.85 KB)

1.) ALWAYS (always) put your code in between CODE TAGS!!!
2.) You didnt provide a link to your MP# player of choice..(so we dont know much about it)
3.) Maybe think about switching to a SERIAL audio player (like the DFPlayer mini board?)
4.) Are you sure the MP# player is blocking the code? Seems like you have some DELAYS() in there (5 seconds?) right after you trigger an audio track playback... you wont be able to do ANYTHING for those 5 seconds..

DELAY() is a blocking function.. nothing runs/happens when you are in a delay()....

You should checkout the BLINK WITHOUT DELAY sketch in the IDE examples.. this will demonstrate the correct way to write non-blocking code. (ie: using millis() instead!)

Thanks for the comment!
2) This is the mp3 player: SparkFun MP3 Player Shield - DEV-12660 - SparkFun Electronics
3) Thanks for the hint, I will check for serial audio players as an alternative
4) The reason why I put the delay is that otherwise nothing is playing. If I'd just write
the song would never play as one millisecond later or so the loop would restart and the rfid reader tries to access (at least that's my hypothesis). Putting a delay(5000); there ensures that the mp3 is played for 5 seconds (i checked this with longer mp3 files as well).
I will try converting this to millis(), but don't believe it would solve the big problem

I find it odd that the MP3 player board would need to continuously be 'talked to'..

Should be just send an SPI command to trigger playback.. and go on about your other duties?
Isnt that the case?

Maybe try trimming down the sketch to only trigger playback via button press...

I dont quite grasp WHY the delay() would be needed here?

ok, here is a code example with a button - works perfectly. The problem starts when putting the second shield that also uses the SPI.

#include <SPI.h>
#include <SdFat.h>
#include <SFEMP3Shield.h>

int buttonApin = 36;
SdFat sd;
SFEMP3Shield MP3player;
int8_t current_track = 0;
long randNumber;

void setup() {
  pinMode(buttonApin, INPUT_PULLUP);  

  if(!sd.begin(9, SPI_HALF_SPEED)) sd.initErrorHalt();
  if (!sd.chdir("/")) sd.errorHalt("sd.chdir");

  Serial.println(F("Looking for Buttons to be pressed..."));

void loop() 
  if (digitalRead(buttonApin) == LOW)
      randNumber = random(167);
      Serial.print(F("B_PLAY pressed, Start Playing Track # "));

I did some further debugging and read out some of the SPI pins at different points in the program. What i can see is that pin #50 (MISO) is set to 0 when no mp3 is playing and 1 when an mp3 is playing. When i’m starting the loop again with pin 50 = 1 the arduino freezes. When putting the delay(5000); there the mp3 has time to finish playing and pin 50 = 0 again when starting the next loop and there is no freezing.

Thanks all for the help. The hint with the serial player was good. I got the dfplayer mini and all problems were solved.