Two SPI devices not working [SOLVED]

Hello World,

It's been 2 days since I have started searching for a solution to solve this issue. The issue - as suggested by the title of the post - is that 2 devices communicating with Arduino using SPI are malfunctioning!! That is, I cannot establish connection with both of them at the same time.
However, I have solved the issue after reading so many posts here and there. So, as to thank the forum and the community for helping me out (even though I haven't posted a question), I want to post the problem and the solution.

Problem Description:
It's required to connect this RFID reader and this SD card to Mega Arduino board so I can read RFID tags and load some files from the card to process some data.

Solution:

Part 1 (if you know about software SPI, you can skip to part 2):

The PN532 library (the library used to interface with the NFC device using SPI) implements Software SPI. It doesn't use the hardware SPI. Meaning, you don't have to stick to the SPI pins mentioned for your arduino module. You can use any other digital pin for the SPI.
example using Mega:
It's mentioned in the Mega product page, that the SPI pins are:

  • MISO: 50
  • MOSI: 51
  • SCK: 52
  • SS: 53

So, without learning about the software SPI, one would connect the MOSI of the NFC device with the MOSI pin of the arduino, the MISO of the device with the MISO pin of the arduino and so on and so forth. Here's a code sample:

#define SCK 52
#define MOSI 51
#define SS 53
#define MISO 50

PN532 nfc(SCK, MISO, MOSI, SS);

The new thing here is that you can change the pins connected to the arduino board. For example, we can connect SS [NFC] to pin 40 [Mega], MISO [NFC] to pin 38 [Mega], MOSI [NFC] to pin 39 [Mega] and SCK [NFC] to pin 37 [Mega] (completely random digital pins) and use the same initialization after editing the pin definitions:

#define SCK 37
#define MOSI 39
#define SS 40
#define MISO 38

Part 2:
Now that you know about the software SPI. You need to know that Software SPI doesn't work with libraries that use hardware SPI.
The SD card library uses hardware SPI. That's why I faced the problem of making them communicate over the same data lines.
By the way, the SD card library I use is the standard - out dated - library pre-installed with arduino setup.

Here's a full version of some test code I created to test both devices together: (Note: I have used hardware SPI pins mentioned in the Mega Product page for the SD card device. Obviously, I have used Mega Arduino board)

#include <PN532.h>
#include <SD.h>

#define SCK 37
#define MOSI 39
#define SS 40
#define MISO 38

PN532 nfc(SCK, MISO, MOSI, SS);
const uint8_t SdChipSelect = 53;

void setup() {
  Serial.begin(9600);
  pinMode(SS, OUTPUT);
  pinMode(SdChipSelect, OUTPUT);
  digitalWrite(SS, HIGH);
  digitalWrite(SdChipSelect, HIGH);
  Initialize_NFC_First();
  checkPins();
  testNFC();
}

void loop() {
  
}

void Initialize_NFC_First() {
  InitializeNFC();
  InitializeSDCard();
}

void Initialize_SDCard_First() {
  InitializeSDCard();
  InitializeNFC();
}

void InitializeNFC() {
  digitalWrite(SdChipSelect, HIGH);
  digitalWrite(SS, LOW);
  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
      Serial.print("Didn't find PN53x board");
      while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
  Serial.print("Supports "); Serial.println(versiondata & 0xFF, HEX);

  // configure board to read RFID tags and cards
  nfc.SAMConfig();
  digitalWrite(SS, HIGH);
  digitalWrite(SdChipSelect, HIGH);
}

void InitializeSDCard() {
  digitalWrite(SdChipSelect, LOW);
  digitalWrite(SS, HIGH);
  digitalWrite(SdChipSelect, LOW);
  Serial.print("Initializing SD card...");
    if (!SD.begin()) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  digitalWrite(SS, HIGH);
  digitalWrite(SdChipSelect, HIGH);
}

void checkPins() {
  if(digitalRead(SS) == LOW) Serial.println("Reader is Active");
  else Serial.println("Serial is inActive");
  if(digitalRead(SdChipSelect) == LOW) Serial.println("SD Card is Active");
  else Serial.println("SD Card is inActive");
}

void testNFC() {
  digitalWrite(SdChipSelect, HIGH);
  digitalWrite(SS, LOW);
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
      Serial.print("Didn't find PN53x board");
      while (1); // halt
  }
  // Got ok data, print it out!
  Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
  Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
  Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
  Serial.print("Supports "); Serial.println(versiondata & 0xFF, HEX);
  digitalWrite(SS, HIGH);
  digitalWrite(SdChipSelect, HIGH);
}

Note:
You may need to read the user guide to have the NFC library work.

Another note:
There's no specific reason to use uint8_t data type for sd card select. I just happened to use it.

and this concludes the post.

Maybe a bit late and maybe not relevant

I was having the same problem using the TFT_ILI9341 Library with the SD library as well as the MFRC522 they all use SPI and i could only update the TFT in the Setup before the SD or the MFRC522 was initialized

after surfing on google for days and trying everything i could think of i read through the TFT_ILI9341.cpp file and found this:

#ifdef SPI_HAS_TRANSACTION
 #ifdef SUPPORT_TRANSACTIONS

static inline void spi_begin(void) __attribute__((always_inline));

static inline void spi_begin(void) {
 SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
}

static inline void spi_end(void) __attribute__((always_inline));

static inline void spi_end(void) {
 while (!(SPSR & _BV(SPIF))); // wait for everything SPI to finish before freeing up the bus
 SPI.endTransaction();
}
 #else // we do not want to SUPPORT_TRANSACTIONS

#define spi_begin()
#define spi_end()

 #endif // SUPPORT_TRANSACTIONS

#else
#define spi_begin()
#define spi_end()
#endif

this is defined in the user_setup.h file and by default commented out in other words not defined
i uncommented that little line and all my devices worked perfectly

if you can find a way to work that bit of code in to your libraries it will work for you too

this is an advanced fix so it might be better to download the TFT_ILI9341-master library and read the code follow all lines until you can understand how it works then you should have no problem implementing it in your library

Hope this helps:)