Using SPI with multiple Modules

Hi all!

I’ve been googling for a couple of hours by now and cant find a definitive answer for my problem.
I want to be able to connect 2 modules to my Arduino UNO:

  • Micro-SD card Reader - 5v
  • RFIDRC522 module - 3.3v

I know all my connections are correct since if I remove the code of each device they independently work, without removing any module.
But wen both codes are present, only the SD card works, the RFID simply does not respond, although the loop is running since if a put a simple ‘Serial.println(“X”);’ it keeps printing it.

Any advise is welcome.

here is my code:

#include <SPI.h>
#include <MFRC522.h>
#include <SD.h>

#define SS_PIN 10    //Arduino Uno
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN);        // Create MFRC522 instance.

String NewCard="";
String TesteCode = "F058BC02";

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

/*
  SD CARD SETUP
  get card values 
*/
  
  
  Serial.print("Initializing SD card...");
   if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  
  /*
    RFID SETUP 
  */
  SPI.begin();                // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card

}


void loop() {
        // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
        MFRC522::MIFARE_Key k;
        // Look for new cards
        if ( ! mfrc522.PICC_IsNewCardPresent()) return;
      
        // Select one of the cards
        if ( ! mfrc522.PICC_ReadCardSerial())    return;
        
        Serial.print("Card UID:");    //Dump UID
        for (byte i = 0; i < mfrc522.uid.size; i++) {
          Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
          NewCard += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
          Serial.print(mfrc522.uid.uidByte[i], HEX);
          NewCard += String(mfrc522.uid.uidByte[i], HEX);
          NewCard.toUpperCase();
        }
        
        Serial.println("");
        
        if (NewCard == TesteCode){
          Serial.println("OPEN GATE");
        }else{
          Serial.println("NO CARD MATCH");
        }
        
        NewCard = "";
        delay(2000);
}
  SPI.begin();                // Init SPI bus

Don't you suppose that the SD class already did this, since it is an SPI device, too?

Any advise is welcome.

Add more Serial.print() statements, to see where the code is dying.

Check to make sure that the two devices/libraries are not trying to use the SPI bus at different speeds, etc. without resetting the bus as needed.

You need to manage the Slave Select pin. Read this: http://www.gammon.com.au/spi

Ok, so I followed both suggestion and here my findings:

PaulS

  • The code brakes on:
    if ( ! mfrc522.PICC_IsNewCardPresent()) return;
    That is the first ‘if’ in the Loop()

  • I do not know how to check the speed of each device :confused:

Nick Gammon

  • I read the link you sent, but it’s quite technical and it kinda lost me. The only intel I could gather is that Pin 10 has to be set as an Output… I tried and still no luck. :’(

Resuming, I assume the problem resides in the RFID library.
I have tried to invert the Setup(), setting the RFID before the SD-CARD settings, and the result is the same, crashing on line posted earlier.

Any help is appreciate…

Both devices need their own slave select pin. Please state which pin you are using for the SD card and which pin you are using for the RFID card.

I'm using (or trying to) :

SD-card: pin 4
RFID: pin 10

...hum...

For some reason, switching the order of the settings if affecting the result.

If I set the SD-card first, the card is detected and the RFID crashes.
If I set the RFID first, the card is not detected and the RFID still crashes.

Right. Well, better names would be in order:

#define SS_PIN 10    //Arduino Uno

Like, "RFID_SS_PIN".

Without wading through both libraries, what may be required (if the library doesn't do it) is to assert slave select as required, like this:

digitalWrite (RFID_SS_PIN, LOW);  // assert slave select for RFID card
// access RFID card
digitalWrite (RFID_SS_PIN, HIGH);

...

digitalWrite (SD_SS_PIN, LOW);  // assert slave select for SD card
// access SD card
digitalWrite (SD_SS_PIN, HIGH);

Unfortunately still no luck.

Here is my current code:

#include <SPI.h>
#include <MFRC522.h>
#include <SD.h>

#define RFID_SS_PIN 10    //Arduino Uno
#define SD_SS_PIN 4
#define RST_PIN 9
MFRC522 mfrc522(RFID_SS_PIN, RST_PIN);        // Create MFRC522 instance.

String NewCard="";
String TesteCode = "F058BC02";
int xx = 0;

void setup() {
  pinMode(RFID_SS_PIN, OUTPUT);
  pinMode(SD_SS_PIN, OUTPUT);
  digitalWrite(RFID_SS_PIN, HIGH);
  digitalWrite(SD_SS_PIN, HIGH);
  
  Serial.begin(9600);        // Initialize serial communications with the PC

  /*
  SD CARD SETUP
  get card values 
  */
  digitalWrite(SD_SS_PIN, LOW);
  Serial.print("Initializing SD card...");
   if (!SD.begin(4)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  digitalWrite(SD_SS_PIN, HIGH);
  
  /*
    RFID SETUP 
  */
  digitalWrite(RFID_SS_PIN, LOW);
  SPI.begin();                // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card



}


void loop() {
  //Serial.println(xx);
  
        // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
        MFRC522::MIFARE_Key key;
        // Look for new cards
        if ( ! mfrc522.PICC_IsNewCardPresent()) return;
      xx=xx+1;
        // Select one of the cards
        if ( ! mfrc522.PICC_ReadCardSerial())    return;
        
        Serial.print("Card UID:");    //Dump UID
        for (byte i = 0; i < mfrc522.uid.size; i++) {
          Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
          NewCard += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
          Serial.print(mfrc522.uid.uidByte[i], HEX);
          NewCard += String(mfrc522.uid.uidByte[i], HEX);
          NewCard.toUpperCase();
        }
        
        Serial.println("");
        
        if (NewCard == TesteCode){
          Serial.println("OPEN GATE");
        }else{
          Serial.println("NO CARD MATCH");
        }
        
        NewCard = "";
        delay(2000);
}

As Nick Gammon suggested I defined the RFID_SS_PIN and SD_SS_PIN as 10 and 4.
Set them all HIGH on start, then set them LOW before access and HIGH right after…
You can see I never set the RFID_SS_PIN back to HIGH since I never access the SD card after Setup()

But, still not working, it still crashes on the first access to the RFID.

edit: Aparently, if I unplug the SD-card from VCC (5v) the RFID starts working.
Could it have something to do this each module working with diferent voltages?
RFID: 3.3v
SD: 5v

You are not manipulating the slave select pins in loop().

Put ALL the code to read from the RFID card in a function. Set the SS pin for the RFID low. Call the function. Then, set the SS pin HIGH again.

Do the same with writing to the SD card (when you add that code).

I agree with PaulS. My suggested snippet was intended to show you that you assert Slave Select for the device every time you need to access it. It simply won’t work to leave SS activated for both devices. I don’t know if the library(s) handle this automatically or not. Possibly not.

It looks like some well-meaning advice has gone awry. Those two libraries (SD and MFRC22) are relatively complex and they both manage their own chip-select pin by themselves. There is no need for you to ever write high or low to those pins.

You should only call SPI.begin() once, before any calls to SD or the other. You only need to begin once.

Yes, the different voltages look like a problem. Exactly which Modules are you using? Links to where you bought them? Some SPI modules cannot be used with others on the same SPI bus. They don't release the MISO line like the standard says they should.

So…

A new day has started, fresh mind :slight_smile:

I read all you suggestions and implemented them all.

  • Setting the ‘SPI.begin()’ before the two calls makes de SD card fail for some reason, so it has to stay where it is.

  • I have created 2 functions:

CheckForCard() - for the RFID loop
TurnOnPIN(int pin) - Set all the SS pins HIGH and only the one I need LOW

Here is the Result:

#include <SPI.h>
#include <MFRC522.h>
#include <SD.h>

#define RFID_SS_PIN 7
#define SD_SS_PIN 4
#define RST_PIN 9
MFRC522 mfrc522(RFID_SS_PIN, RST_PIN);        // Create MFRC522 instance.

String NewCard="";
String TesteCode = "F058BC02";

int counter=0;

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

 

  /*
  SD CARD SETUP
  get card values 
  */
  
  TurnOnPIN(SD_SS_PIN);
  Serial.print("Initializing SD card...");
   if (!SD.begin(SD_SS_PIN,11,12,13)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  /*
    RFID SETUP 
  */
  TurnOnPIN(RFID_SS_PIN);
  SPI.begin();                // Init SPI bus
  mfrc522.PCD_Init();        // Init MFRC522 card
  
}


void loop() {
  
  CheckForCard();

  Serial.println(counter);
  counter=counter+1;
  
  delay(2000);
}




void TurnOnPIN(int pin){
  pinMode(RFID_SS_PIN, OUTPUT);
  pinMode(SD_SS_PIN, OUTPUT);
  digitalWrite(RFID_SS_PIN, HIGH);
  digitalWrite(SD_SS_PIN, HIGH);

  digitalWrite(pin, LOW);
}




void CheckForCard(){
  TurnOnPIN(SD_SS_PIN);
  
  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) return;

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())    return;
  
  Serial.print("Card UID:");    //Dump UID
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
    NewCard += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    NewCard += String(mfrc522.uid.uidByte[i], HEX);
    NewCard.toUpperCase();
  }
  
  Serial.println("");
  
  if (NewCard == TesteCode){
    Serial.println("OPEN GATE");
  }else{
    Serial.println("NO CARD MATCH");
  }
  
  NewCard = "";
}

The modules where both bought on ebay:

ho… and it still not working.

… it still not working …

It’s very hard to help with this level of detail. What isn’t working? The RFID card? The SD card? What do your debugging displays show?

Let me try to explain as detailed as possible.

First of all I striped the code to the bare minimum:

#include <SPI.h>
#include <MFRC522.h>
#include <SD.h>

#define RFID_SS_PIN 7
#define SD_SS_PIN 4
#define RST_PIN 9
MFRC522 mfrc522(RFID_SS_PIN, RST_PIN);        // Create MFRC522 instance.

String NewCard="";
String TesteCode = "F058BC02";


void setup() {
  Serial.begin(9600);

  //SD CARD SETUP
  
  TurnOnPIN(SD_SS_PIN);
  Serial.print("Initializing SD card...");
   if (!SD.begin(SD_SS_PIN,11,12,13)) {
    Serial.println("initialization failed!");
  }else{
    Serial.println("initialization done.");
  }

   
  //RFID SETUP 

  TurnOnPIN(RFID_SS_PIN);
  SPI.begin();
  mfrc522.PCD_Init();
  
}


void loop() {
  
  CheckForCard();

}




void TurnOnPIN(int pin){
  pinMode(RFID_SS_PIN, OUTPUT);
  pinMode(SD_SS_PIN, OUTPUT);
  digitalWrite(RFID_SS_PIN, HIGH);
  digitalWrite(SD_SS_PIN, HIGH);

  digitalWrite(pin, LOW);
}




void CheckForCard(){
  TurnOnPIN(SD_SS_PIN);
  
  // Prepare key - all keys are set to FFFFFFFFFFFFh at chip delivery from the factory.
  MFRC522::MIFARE_Key key;
  
  // Look for new cards
  if ( ! mfrc522.PICC_IsNewCardPresent()) return;

  // Select one of the cards
  if ( ! mfrc522.PICC_ReadCardSerial())    return;
  
  Serial.print("Card UID:");    //Dump UID
  for (byte i = 0; i < mfrc522.uid.size; i++) {
    Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
    NewCard += String(mfrc522.uid.uidByte[i] < 0x10 ? "0" : "");
    Serial.print(mfrc522.uid.uidByte[i], HEX);
    NewCard += String(mfrc522.uid.uidByte[i], HEX);
    NewCard.toUpperCase();
  }
  
  Serial.println("");
  
  if (NewCard == TesteCode){
    Serial.println("CARD MATCH");
  }else{
    Serial.println("CARD DOES NOT MATCH");
  }
  
  NewCard = "";
}

The final objective will be to read an RFID Card and check if that Card is listed in the SD-card, but for now I’m simply trying to initialize the SD-card and the RFID modules, read a RFID Card and compare it to the value in the Variable ‘TesteCode’.

If the RFID Card matches it should return:
Initializing SD card…initialization done!
Card UID:C7BE8769
CARD MATCH

If it doesn’t it should return:
Initializing SD card…initialization done!
Card UID:C7BE8769
NO CARD MATCH

But since the RFID crashes it only returns:
Initializing SD card…initialization done!

After several tries and error I reach the conclusion that the different voltages must be the cause of the problem, since if I unplug the MISO from the SD-card module the RFID works fine, but of course the SD-card doesn’t.

So what it returns is:
Initializing SD card…initialization failed!
Card UID:C7BE8769
CARD MATCH

(or NO CARD MATCH)

So now the question is, what should I do to fix the voltage problem?
I read about voltage sifters, or the use of resistors and diodes… anyone?

I have found the solution for my problem.
The user "dc42" in THIS POST says:

To convert a 5v output to 3.3v, use a potential divider, e.g. 5k6 to the Arduino pin and 10K to ground.

And that's what I did, and apparently it fixed my problem.
I say "apparently" because I have not tried to write/read to the SD-card yet, but the initialization works on both Modules, and the RFID works fine now.
As soon as I test it I'll bring more intel.

You should probably use a level-shifter for the 3.3V part.

OK, so here I am with more news.

The use of the two resistor did the trick... or I thought so.

I prepared my new functions to create and read my files, all was working well as long as I used my function right after the SD initialization.
As soon as I initialize the RFID, it's the SD card that stop having access to the files.

I'm reaching the conclusion that the SPI library has some sort of incompatibility with the SD library.
I come to this conclusion because I tried to put the SD.begin() before the SD initialization and the SD card doesn't even initialize.
I can´t remove the SD.begin() or else the RFID stops working.

Any library savi can give me a hand?

I must admit that I found that when trying to use the SD library (SDfat in my case) along with other SPI functions, they would fail. I eventually used "bit-banged" SPI for the other device (speed wasn't really all that important). I have a bit-banged SPI library here: http://www.gammon.com.au/spi

I don't know if your second library can easily use that, you may have to adapt the RFID library.

Thanks Nick, I'll look into that tomorow... but adapting a library, hum, I think that's a little over my head.