Using Multiple SPI Devices On Arduino Mega 2560

Hi there. Sorry if I am in the wrong forum for my problem, but I don't know where it can fit to.

So I am currently working on a project called 'Jukebox'. I want to play music over my Mega. So far so good. I get it to work easily using this shield: Sd-Card Shield
Now I want to combine it with a rfid-sensor chip like this one: rfid-shield.

Now both devices use the same spi pin (53). I've read this article: Article and it's telling me I need to use two different spi-pins to communicate between my rfid shield and my sd-card shield. But the Arduino Mega has only pin 53 as spi. So I need your help to understand if I can use both and communicate with both (does not require paralell communication).

My Base Idead is something like: a customer is coming with a rfid-card, authentifying himself with the sensor and afterwards choosing a song to play.

I'd like to know how I can wire it up to use both devices with the spi bus.

Thank you in Advance!

Pin 53 is the Mega's select pin for when some other device would want to make the Mega a slave.

You can use any Mega pin as the select pin for another device which the MEga master will control as a slave.

The only rule is that you must make Mega pin 53 an output, since if it was an input, some other device might make that pin low and force the Mega into being a slave.

So since you need that pin to be an output anyway, you "may as well" use it as the select pin for some other device as slave. Typically then, pin 53 is used as a select pin for a slave, but it needn't actually be. It can be ignored of you like, or used as an output to run an led; just don't make it an input.

Only real problem is likely to be when your slave devices are plug-on shields and both have the same pin, perhaps 53, hardwired as their select pins. But seems you have only one shield. So use as its select pin whichever one is hardwired, maybe 53 maybe not :wink: , and some other pin as select for the rfid, wired by you.

PS to previous: looking at your links, neither your SD nor RFID is actually a shield. Shields plug on over the Mega straight into the Mega pins; yours both look to me like loose modules that you attach with jumper wires.

PS to previous: looking at your links, neither your SD nor RFID is actually a shield

Sorry for that I wasn’t sure how to call it. Now I know that it isn’t a shield thank you.

So that I understand correctly: I can choose any digital Pin I like to be the CS (SS) if I make it an output?
I tried that in my code and wired my cable to pin 47 and made it and output. But when I connected my SD-Card Module, it couldn’t be played. So I assume that I do something wrong?

If it helps here is my code:

#include <SD.h>    //Zus. Bibliothek benötigt.
#include <SPI.h>    //Zus. Bibliothek benötigt
#include <TMRpcm.h>   //Zus. Bibliothek benötigt. Einfach nach "TMRpcm" suchen und Bibliothek einbinden


//SS (CS) Pin
#define SD_ChipSelectPin 47 //Default 53

//Initialisierung
TMRpcm tmrpcm;



void setup() {

  tmrpcm.speakerPin = 5;
  
  Serial.begin(9600);
  SPI.begin();
  pinMode(SD_ChipSelectPin, OUTPUT);
  if(!SD.begin(SD_ChipSelectPin)){
    Serial.println("SD-Card Fail");
    return;
  }
  else{
    Serial.println("SD-Card Found!"); 
  }
  
  tmrpcm.setVolume(2);
  digitalWrite(SD_ChipSelectPin, HIGH);
  
}

void loop() {
  //
  /*if (!mfrc522.PICC_IsNewCardPresent())           //Überprüfen, ob Karte vor Lesegerät
  {                                                 
    return;                                         //falls nicht, starte neu
  }
  if (!mfrc522.PICC_ReadCardSerial())
  {
    return;
  }
  long code=0;
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    code=((code+mfrc522.uid.uidByte[i])*10);
  }
  if(code = 1339530){
      Serial.println("Sie wurden als Standardbenutzer registriert!");
    }
  if(code = 767810){
      Serial.println("Si wurden als VIP-Benutzer registriert!");
    }
    else{
        return;
      }
  Serial.print("card number is: ");
  Serial.println(code);
  delay(3000);

*/
  //
  if(Serial.available()){
    switch(Serial.read()){
      case '1': digitalWrite(SD_ChipSelectPin, LOW); //for testing
                tmrpcm.play("music1.wav"); 
                Serial.println("Playing: Monkey Island - Main Theme 8-Bit");
                break;
      case '2': tmrpcm.play("music2.wav"); 
                Serial.println("Playing: Pokemon - Battle Theme 8-Bit");
                break;
      case '3': tmrpcm.play("music3.wav"); 
                Serial.println("Playing: Japanese");
                break;
      case '4': tmrpcm.play("music4.wav"); 
                Serial.println("Playing: Beach Boys - Woudlnt It Be Nice");
                break;
      case '5': tmrpcm.play("music5.wav"); 
                Serial.println("Playing: Childish Gambino - This is America");
                break;
      case '6': tmrpcm.play("music6.wav"); 
                Serial.println("Playing: Michael Jackson - Smooth Criminal");
                break;
      case '7': tmrpcm.play("music7.wav"); 
                Serial.println("Playing: Nat King Cole - Orange Colored Sky");
                break;
      case 'b': tmrpcm.pause(); digitalWrite(SD_ChipSelectPin, HIGH); break;
    }
  }

}

PS: All comments needed are translated in egnlish

You need to make pin 53 an output too, pins default to input, and although you aren't using pin 53 for the sd card, it must be an output so the Mega doesn't become a slave by accident

Ok I am back again. I worked a bit on it and now I can use any digital Pin as SPI for my sd-card module.

Now I run into another problem. When I’ve connected my rfid-module and my sd-card module to the arduino mega no module is working.
For both I use the follwong structure:

  • Miso Pin 50 (For both modules)
  • Mosi Pin 51 (For both modules)
  • SCK Pin 52 (For both modules)
  • RST Pin 5 (For rfid module)
  • SS/SDA Pin 53 (For rfid module)
  • SS/CS Pin 45 (For sd-card module)

Here my code:

//Steckkonfig auf dem Arduino Mega:
//SS (CS)    53
//SPI (Miso) 50
//Mosi       51
//SCK        52
//Speaker an 5/6


/*
Zum Rfid-Rc522
 Pinanschlüsse
   RST        5
   Miso       50
   Mosi       51
   SCK        52
   SDA (SS)   53  
*/

//SD-Karteninfos:
//Fat32
//16000khz Music
//wav-format
//8bit
//pcm format: unsigned 8 bit
//audio channel: mono
//Link zum Umwandeln und Einstellen: https://audio.online-convert.com/convert-to-wav

//verschiedene Bibliotheken
#include <SD.h>    //Ist schon vorhanden -> keine zus. Bibliothek nötig
#include <SPI.h>    //Ist schon vorhanden -> keine zus. Bibliothek nötig
#include <TMRpcm.h>   //Zus. Bibliothek benötigt. Einfach nach "TMRpcm" suchen und Bibliothek einbinden
#include <MFRC522.h>


//SS (CS) Pin
#define SD_ChipSelectPin 45
#define SS_RFID 53


//Initialisierung
TMRpcm tmrpcm;
MFRC522 mfrc522(SS_RFID, 5);



void setup() {

  tmrpcm.speakerPin = 6;
  
  Serial.begin(9600);
  SPI.begin();
  pinMode(SD_ChipSelectPin, OUTPUT);
  pinMode(SS_RFID, OUTPUT);
  mfrc522.PCD_Init();
  if(!SD.begin(SD_ChipSelectPin)){
    Serial.println("SD-Card Fail");
    return;
  }
  else{
    Serial.println("SD-Card Found!"); 
  }
  
  tmrpcm.setVolume(2);
  digitalWrite(SD_ChipSelectPin, HIGH);
  digitalWrite(SS_RFID, HIGH);
  
}

void loop() {
  //RFID-Teil

    digitalWrite(SS_RFID, LOW);
    if(!mfrc522.PICC_IsNewCardPresent()){
      return;
    }

    if(!mfrc522.PICC_ReadCardSerial()){
      return;
    }

    long code = 0;
    
    for(byte i = 0; i < mfrc522.uid.size; i++){
      code = ((code+mfrc522.uid.uidByte[i])*10);
    }

    if(code == 1339530){
      Serial.println("Standardbenutzer");
      delay(3000);
    }

    if(code == 767810){
      Serial.println("VIP-Benutzer");
      delay(3000);
    }
    else {
      return;
    }
    digitalWrite(SS_RFID, HIGH);
   
  //Ende RFID

  //SD-Teil
  
  if(Serial.available()){
    switch(Serial.read()){
      case '1': digitalWrite(SD_ChipSelectPin, LOW);
                tmrpcm.play("music1.wav"); 
                Serial.println("Playing: Monkey Island - Main Theme 8-Bit");
                break;
      case '2': tmrpcm.play("music2.wav"); 
                Serial.println("Playing: Pokemon - Battle Theme 8-Bit");
                break;
      case '3': tmrpcm.play("music3.wav"); 
                Serial.println("Playing: Japanese");
                break;
      case '4': tmrpcm.play("music4.wav"); 
                Serial.println("Playing: Beach Boys - Woudlnt It Be Nice");
                break;
      case '5': tmrpcm.play("music5.wav"); 
                Serial.println("Playing: Childish Gambino - This is America");
                break;
      case '6': tmrpcm.play("music6.wav"); 
                Serial.println("Playing: Michael Jackson - Smooth Criminal");
                break;
      case '7': tmrpcm.play("music7.wav"); 
                Serial.println("Playing: Nat King Cole - Orange Colored Sky");
                break;
      case 'p': tmrpcm.pause(); break;
      case 'b': tmrpcm.stopPlayback(); digitalWrite(SD_ChipSelectPin, HIGH); break;
      
      //Ende SD-Teil
    }
  }

}

If I want to read a rfid-card or rfid-chip or playing music over 1,2,3, etc. nothing of it works. Only the Text “SD-Card Found” is shown in my Serial monitor and nothing else.
If I comment out all the rfid-stuff in the loop()-function and try to play my music it works fine.
If I comment out my sd-card stuff in the loop()-function my rfid module won’t work. It will only work if I unplug all cables going from my sd-card to the arduino.

What am I doing wrong?

I don't have a gap right now to look at that, but wonder if this pic that I saw just the other day helps?

One of pins SS0, SS1 and SS2 would probably be Mega's own SS pin 53 to prevent the Mega being made a slave by accident.

The graphic isn't helping me much. I've already built my components like that. Both of my slave devices are connected on the same miso, mosi and sck pins and they have both two different ss pins. But when I connect both of them neither one of them works. When I comment out all the code from the rfid-device my sd-card module is working again, even if the rfid-module is still connected with all of its pins.
But if I only comment out the code for the sd-module and let it still be connected to the arduino my rfid-module wont work.
It will only work when I disconnected all cables from sd-card module.

So maybe I am doing something wrong in cabling or in my code, since it should work theoretically, but it doesnt.

I'm sorry I can't help. My knowledge is theoretical as well.

But I now vaguely recall reading about some makes of SD card module "holding" the bus so other devices can't work. If that's so I wonder if setting the SD's select pin to high as an output to deselect the SD card could force it to relinquish the bus?

Ok for what it’s worth I did a bit of a test. I have an ethernet shield which has an sd card hardwired on pin 4, and and I also attached an external sd module, using pin 7 as select.

I took the SD listfiles example and modified it as below to use both, and got the results shown, both cards listed, so it’s obviously able to select.

My initial observation though, although more tests required, is that it doesn’t work reliably without explicitly disabling the card-not-in-use by making its select high. Don’t trust me on that though, more testing needed.

/*
  Listfiles for TWO SD CARDS, controlled on pins 4 (hardwired on e'net shield) and 7 (loose sd module)

  This example shows how print out the files in a
  directory on a SD card

  The circuit:
   SD card attached to SPI bus as follows:
 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK - pin 13
 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN)

  created   Nov 2010
  by David A. Mellis
  modified 9 Apr 2012
  by Tom Igoe
  modified 2 Feb 2014
  by Scott Fitzgerald

  This example code is in the public domain.

*/
#include <SPI.h>
#include <SD.h>

byte sdInt = 4; //bulit in on e'net shield
byte sdExt = 7; //external module

File root;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  pinMode(sdInt, OUTPUT);
  pinMode(sdExt, OUTPUT);


  Serial.println("");

  Serial.print("Initializing EXTERNAL SD card...");
  digitalWrite(sdInt, HIGH); //disable int

  if (!SD.begin(sdExt))
  {
    Serial.println(" failed");
    //return;
  }
  else
  {
    Serial.println(" succeeded");
    Serial.println("List of files on external sd: ");
    root = SD.open("/");

    printDirectory(root, 0);

    Serial.println("End of list of files on external sd");
  }
  Serial.println("");

  Serial.print("Initializing INTERNAL SD card...");
  digitalWrite(sdExt, HIGH); //disable ext

  if (!SD.begin(sdInt))
  {
    Serial.println(" failed");
    //return;
  }
  else
  {
    Serial.println(" succeeded");
    Serial.println("List of files on internal sd: ");
    root = SD.open("/");

    printDirectory(root, 0);

    Serial.println("End of list of files on internal sd");

  }
}

void loop() {
  // nothing happens after setup finishes.
}

void printDirectory(File dir, int numTabs) {
  while (true) {

    File entry =  dir.openNextFile();
    if (! entry) {
      // no more files
      break;
    }
    for (uint8_t i = 0; i < numTabs; i++) {
      Serial.print('\t');
    }
    Serial.print(entry.name());
    if (entry.isDirectory()) {
      Serial.println("/");
      printDirectory(entry, numTabs + 1);
    } else {
      // files have sizes, directories do not
      Serial.print("\t\t");
      Serial.println(entry.size(), DEC);
    }
    entry.close();
  }
}
Initializing EXTERNAL SD card... succeeded
List of files on external sd: 
SYSTEM~1/
 WPSETT~1.DAT 12
 INDEXE~1 76
BLAH001.DAT 113
End of list of files on external sd

Initializing INTERNAL SD card... succeeded
List of files on internal sd: 
SYSTEM~1/
 WPSETT~1.DAT 12
 INDEXE~1 76
FILE001.TXT 65
FILE002.TXT 65
End of list of files on internal sd

(And PS to previous, I also turned on the Ethernet using pin 10 in between the 2 SD card lists, and it connected to my modem and is pingable.

So right now I am able to use SPI by selecting via pin 7 for one SD card list, then pin 10 for ethernet which connects to modem, then pin 4 for the other SD card.)

So I’ve looked around google and other forums which have kinda the same problem as I have. There are many with this problem. It’s often said that even if the SD-Card module is set on “high” for “off” the miso-line of the sd-card blocks the communication for other spi-devices.

Often the topic to solve this is a called a “tri state buffer”. I tried searching it, but I didn’t find any useful information on how to build this with arduino.

There were also some other few solutions for that like changing the SD-Card from 5V to 3.3V or setting a resistor of 330 ohm between the miso lanes of the sd-card module. But I hadn’t time to try it out yet. So it’s not impossible to do that since others already worked a way around it, but it’s often not fitting for my problem or is too complicated for me to understand properly.

I thank you for your help so far. It seems not possible for me to do that. But it’s not much of a need. I will just leave the rfid-sensor out of my project. Or replace it with something else.

SchnoppDog:
There are many with this problem. It's often said that even if the SD-Card module is set on "high" for "off" the miso-line of the sd-card blocks the communication for other spi-devices.

So I wonder if that's peculiar to a certain brand of SD card module? And if so, is there anyway to distinguish visually a "good" one from a "bad" one?

All I can say is my last test worked, where I had an external SD, an E'net shield, and the shield's on-board SD, all working together.

I am however, about to embark on testing with an nRF24, also SPI, so let's see if I can add a 4th device into the mix.

Perhaps the SD-Card module and the rfid-sensor aren'T working together but others do. Unfortunately I can't tell you.

I had some trouble getting an digitalpot IC and a display IC to work together. Either one worked as it should by it's self, but together only one would work.

I was using a library for the MAX7219 display, but I had to write my own code for the digital pot, so that was what I thought might be upsetting things. I figured out that I needed to call SPI.end() to free up the SPI bus for the display. Perhaps you have the same problem.

I might know now what’s causing the rfid module to fail. I searched for the company and found many forums with the exact same problem. So it’s likeley that the sd module isn’t working properly because of the manafacturers fault.

Well I think there is nothing to do besides buying another sd module from another manufacturer.
But thank you for your help so far.

After many times searching on websites for any reasonable solutions I managed to make a little workaround.

I examined those two websites for the workaround:

I attached two images explaining the circuit of the catalex SD-Module (V1.0). One of them is the basic and the other is the modified version.

On the second website I’ve linked you can solder two pins together for the workaround. But since I am very awful in soldering I came up with another workaround just by looking at the modified version of the catalex SD-Module.

Short said:
I used a 1KΩ resistor between the MISO of the Arduino and the MISO of the SD-Card module.
Now I can use more SPI devices.

Hello having the same problem just with SD module and MPU9250 accelerometer... I dont know if it wont destroy the module in long term ... but I just put the power pin of the SD moudule to one of the digital pins ... and put it high just when I need it ... initialisation of both devices will work for me that way. But I just tried it so ...

SD cards can have high current draw when they start up, over 150mA.
SD cards run on 3.3V, not 5V.

I see 3 things likely happening: you will damage the IO pin eventually by using it to power an SD card; the SD card will not work reliably from a lack of available current; the SD card will not work reliably as the voltage drops on the IO pin from being overloaded.
Does the SD module have a 5V to 3.3V regulator on it?