SD SPI library issue - Working!! -SD and RFID SPI - cleaned up example

I am running a SD card (level shifters and 5v-3.3v PSU adapted) and a RFID device.

Both work independently in their own sketches.

If I join them the only way the SD works is to add a 330ohm resistor in line with the MISO pin but then the RFID wont initialise.

I’ve read similar posts with the issue and the help varies alot. Any new advice would be great!!

#include <SPI.h>
#include <PN532_SPI.h>
#include <SD.h>
#include "PN532.h"

PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);

boolean success;
int powerPin = A5;
int powerpinRead;
int prevpowerpinRead = LOW;
int powerpinState = LOW;
int prevpowerpinState = HIGH;

long time = 0;
long debounce = 200;

void setup(void) {
  Serial.begin(9600);
  pinMode (65, OUTPUT);//sd card CS
  pinMode(powerPin, OUTPUT);
  uint16_t time = millis();
  time = millis() - time;

  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  nfc.setPassiveActivationRetries(0x01);
  nfc.SAMConfig();

  //SD test
  File myFile;
  Serial.print("Initializing SD card...");
  if (!SD.begin(65)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  myFile = SD.open("test.txt", FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  // re-open the file for reading:
  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  //SD test
}

void loop()
{
  readRfid();
  powerpinRead = (success);
}

void readRfid()
{
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);

  if (success) {
    Serial.println("Found a card!");

    for (uint8_t i = 0; i < uidLength; i++)
    {
      // Serial.print(" 0x");Serial.print(uid[i], HEX);
    }
  }

  if (powerpinRead == HIGH && prevpowerpinRead == LOW && millis() - time > debounce)
  {
    if (powerpinState == HIGH)
      powerpinState = LOW;
    else
      powerpinState = HIGH;
    time = millis();
  }
  digitalWrite(powerPin, powerpinState);
}

Some SD card modules will not play well with other devices on the SPI bus. The problem is with the way the level shifter on the SD module is wired. The ones that do not work well have the MISO signal running through the level shifter. That causes the MISO signal to not be released so that the other devices can control it. The modules made by Adafruit (and some others) have the MISO signal going from the SD card straight to the MISO, bypassing the level shifter. Look at the schematic for the Adafruit module to see what to look for. DO (data out) is the MISO signal.

The answer, I think, is to get a SD module that is wired right or use hardware SPI for one device and software SPI for the other if you can find a library that supports soft SPI for that device and you have the spare pins. There are fixes on the net that you can try, though I tried some and had no luck because of the difficulty of working with the tiny parts.

Thanks.

I am already running a hard and soft SPI for a larger sketch that includes an OLED as well (not shown in this thread for clarity) so with other stuff going as well I am tight on pins and speed.

I tried the resistor trick in MISO as well but that didnt help.

I’ve seen posts suggesting the library has an issue as well but again advice is variable…

My post is based on personal experience. I wanted to use an RF24 radio and SD card. Once that I got an SD module that wired MISO directly from the SD card to the Arduino MISO pin, bypassing the level shifter, it worked great.

I use a gate of 74HC125 (or comparable one-gate chip, 74xx1G125xxx) to buffer MISO from 3.3V to 5V to the Arduino, controlled by Slave Select to the SD card.
Keeps the SD card off the bus when it's not active, keeps any circuit in the SD card from affecting the signal, and keeps the SD card from being exposed to 5V from other devices.
Have never had a problem in any design.

Sorry so are you saying use the 74HC125 chip in the CS line only or on all lines (miso/mosi)?

So my SD with its built in level shifter is no good?

If i use the level shifter on clk, mosi, miso and CS, Do i need a pullup on CS before the shifter as in the attached?

The SD card I have uses a SN74LVC125A buffer/level shifter on-board which I cant see why wont work as it looks similar to the 74HC125?

The enabling of the SN74LVC125A is done by the SD, so again is it more of a library issue?

Adding another inline buffer wont help will it?

Ive buzzed out the level shifter on the SD and it looks like the Buffer in line with CS is enabled by the MISO feed.

Surely this is round the wrong way and CS should control/enable MISO?

The other buffered feeds (miso, sclk) are permanently enabled (pulled low).

So based on previous post help, I have some progress....

One issue is the MISO line clash between the SD and the RFID.

The SD has an on-board level shifter as in the diagram but all buffers have their enables grounded so all lines are active.

I have added a link to control the MISO buffer with the CS line.

This now allows my sketch to run, the SD card test runs as does the main program BUT I still have the issue with the SD not opening correctly and the serialprrint doesnt report it has found a card.

If I scope the MISO line it seems low (around 3v pulses) compared to MOSI etc. which could be a clue?
Which is weird because in the sketch I am pulling the enable high so the buffer should be not passing MISO?

Is my 3v level shifter now setting the bus MISO line to 3v and therefore the RFID (although 3v compatible) having an issue with the 3v? Do I need to convert back up to 5v again from the SD card?

Any thoughts???

#include <SPI.h>
#include <PN532_SPI.h>
#include <SD.h>
#include "PN532.h"

PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);

boolean success;
int powerPin = A5;
int powerpinRead;
int prevpowerpinRead = LOW;
int powerpinState = LOW;
int prevpowerpinState = HIGH;

long time = 0;
long debounce = 200;

void setup(void) {
  Serial.begin(9600);
  pinMode (65, OUTPUT);//sd card CS
  pinMode(powerPin, OUTPUT);
  uint16_t time = millis();
  time = millis() - time;

  digitalWrite (65, HIGH); //set SD CS to disable MISO line on SD
  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  nfc.setPassiveActivationRetries(0x01);
  nfc.SAMConfig();

  //SD test
  File myFile;
  Serial.print("Initializing SD card...");
  if (!SD.begin(65)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  myFile = SD.open("test.txt", FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  // re-open the file for reading:
  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  //SD test
}

void loop()
{
  readRfid();
  powerpinRead = (success);
}

void readRfid()
{
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);

  if (success) {
    Serial.println("Found a card!");

    for (uint8_t i = 0; i < uidLength; i++)
    {
      // Serial.print(" 0x");Serial.print(uid[i], HEX);
    }
  }

  if (powerpinRead == HIGH && prevpowerpinRead == LOW && millis() - time > debounce)
  {
    if (powerpinState == HIGH)
      powerpinState = LOW;
    else
      powerpinState = HIGH;
    time = millis();
  }
  digitalWrite(powerPin, powerpinState);
  Serial.println(powerpinState);
}

Just looking at the activity on MISO.

With the level converter MISO line CS disabled (HIGH) the MISO signal (data) on the bus is around 3 v

If I write a LOW to CS the MISO line just goes high (no data) which explains why the RFID stops.

If I comment out all SD code and leave the SD CS HIGH (disabled), the RFID runs but if I write CS low, The MISO line just goes high again and cuts out the RFID.

With the SD code back in and the MISO disabled, the data on the MISO bus looks different compared to when the RFID running correctly (although still around 3v in both cases) which pushes me back to a library issue again?

Clock speed issues?
Why should a MISO line be around 3v? Its the same if working or not working.

I have been reading about SPI modes.

It seems the SD is Mode 0 and the RFID (PN532) could be mode 3.

I cant see how to switch the mode in my code. Given the libraries I am using is there an easy way to test this and see if this is the problem?

Thanks

I have it working now with the following observations.

  1. I must use the modified SD card as in the previous post #9 where I have the CS line controlling MISO.

  2. As in the sketch below I need to start the RFID after the SD card in setup then I don’t need the digitalwrite to the CS.

  3. If I move the SD card code from setup to a sub run from the main loop, I must use the digitalwrite CS line again to manage the CS line.

Now I need to work out exactly why!!!

#include <SPI.h>
#include <PN532_SPI.h>
#include <SD.h>
#include "PN532.h"

PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);

boolean success;
int powerPin = A5;
int powerpinRead;
int prevpowerpinRead = LOW;
int powerpinState = LOW;
int prevpowerpinState = HIGH;

long time = 0;
long debounce = 200;

void setup(void) {
  Serial.begin(9600);
  pinMode (65, OUTPUT);//sd card CS
  pinMode(powerPin, OUTPUT);
  uint16_t time = millis();
  time = millis() - time;




  //SD test
  File myFile;
  Serial.print("Initializing SD card...");
  if (!SD.begin(65)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  myFile = SD.open("test.txt", FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  // re-open the file for reading:
  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  //SD test
  //digitalWrite (65, HIGH); //set SD CS to disable MISO line on SD

  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  nfc.setPassiveActivationRetries(0x01);
  nfc.SAMConfig();

}

void loop()
{
  readRfid();
  powerpinRead = (success);
}

void readRfid()
{
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);

  if (success) {
    Serial.println("Found a card!");

    for (uint8_t i = 0; i < uidLength; i++)
    {
      // Serial.print(" 0x");Serial.print(uid[i], HEX);
    }
  }

  if (powerpinRead == HIGH && prevpowerpinRead == LOW && millis() - time > debounce)
  {
    if (powerpinState == HIGH)
      powerpinState = LOW;
    else
      powerpinState = HIGH;
    time = millis();
  }
  digitalWrite(powerPin, powerpinState);
  Serial.println(powerpinState);
}

I thought it best to clean up the code and show the example completely with the SD code running from a condition in the RFID loop .

So the code is;

#include <SPI.h>
#include <PN532_SPI.h>
#include <SD.h>
#include "PN532.h"

PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);

boolean success;
int powerPin = A5;
int powerpinRead;
int prevpowerpinRead = LOW;
int powerpinState = LOW;
int prevpowerpinState = HIGH;

long time = 0;
long debounce = 200;

void setup(void) {
  Serial.begin(9600);
  pinMode (65, OUTPUT);//sd card CS
  pinMode(powerPin, OUTPUT);
  uint16_t time = millis();
  time = millis() - time;
  digitalWrite (65, HIGH); //set SD CS to disable MISO line on SD
}

void loop()
{
  readRfid();
  powerpinRead = (success);
}

void readRfid()
{
  nfc.begin();
  uint32_t versiondata = nfc.getFirmwareVersion();
  if (! versiondata) {
    Serial.print("Didn't find PN53x board");
    while (1); // halt
  }
  nfc.setPassiveActivationRetries(0x01);
  nfc.SAMConfig();
  uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };  // Buffer to store the returned UID
  uint8_t uidLength;                        // Length of the UID (4 or 7 bytes depending on ISO14443A card type)

  success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength);
  if (success) {
    Serial.println("Found a card!");

    for (uint8_t i = 0; i < uidLength; i++)
    {
      // Serial.print(" 0x");Serial.print(uid[i], HEX);
    }
  }
  if (powerpinRead == HIGH && prevpowerpinRead == LOW && millis() - time > debounce)
  {
    if (powerpinState == HIGH)
      powerpinState = LOW;
    else
      powerpinState = HIGH;
    time = millis();
  }
  digitalWrite(powerPin, powerpinState);
  if (powerpinState == HIGH)
  { SDrun();
  }
  Serial.println(powerpinState);
}
void SDrun()
{
  //SD test
  File myFile;
  File myFile2;
  Serial.print("Initializing SD card...");
  if (!SD.begin(65)) {
    Serial.println("initialization failed!");
    while (1);
  }
  Serial.println("initialization done.");
  SD.remove("test.txt");//clars file then write in next line
  myFile = SD.open("test.txt", FILE_WRITE);
  // if the file opened okay, write to it:
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing A, B, 3.");
    // close the file:
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  // re-open the file for reading:
  myFile = SD.open("test.txt");
  if (myFile) {
    Serial.println("test.txt:");
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.write(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
  //SD test
}

and the modification to the level shifter circuit to add the control to the MISO buffer line where I lift the level shifter enable pin from ground to allow CS to control it (because the normal CS control to the SD doesn't seem to work) is....

The last thing I am trying to work out is why I have to write the CS for the SD HIGH in setup to free the bus and allow the RFID to work because later in the code, while the SD is running, the RFID still runs OK.

It must be something else in the library......more reading....