Yun SPI Conflict with 2 shields - Adafruit 2.8" TFT & NFC Shield

I am looking for guidance and suggestions on how to fix an SPI conflict between the Adafruit 2.8" TFT Touch Cap shield and Seeedstudio NFC Shield v2. Both are working fine on their individual sketches, even when stacked and connected at the same time. However, when the sketch requires the TFT to perform a function and then the NFC shield to perform a function, only the function from the first shield in the code runs. The SPI activity is not shifting from one shield to the other.

These are connected with an Arduino Yun.
TFT shield
SPI - ICSP header
Pin 8 - CS (Manually wired from pin 10 to pin 8 on the Arduino)
Pin 9 - DC

NFC Shield
SPI - ICSP header
Pin 10 - CS

In the example below, no tags are read by the NFC reader since I ask the TFT to perform a few functions at the end of setup. If I remove those functions, the tags are read.

Any help and ideas would be appreciated.

//Touchscreen shield
#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>       
#include <Adafruit_ILI9341.h>
#include <Wire.h>      // this is needed for FT6206
#include <Adafruit_FT6206.h>

//NFC Shield
#include <PN532_SPI.h>
#include "PN532.h"

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

// The FT6206 uses hardware I2C (SCL/SDA)
Adafruit_FT6206 ctp = Adafruit_FT6206();

// The display also uses hardware SPI, plus #9 & #10
#define TFT_CS 8
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

void setup() {
  Serial.println(F("Cap Touch Paint!"));

  if (! ctp.begin(40)) {  // pass in 'sensitivity' coefficient
    Serial.println("Couldn't start FT6206 touchscreen controller");
    while (1);
  Serial.println("Capacitive touchscreen started");
//NFC Shield
    Serial.println("NFC Reader");
  // Set the max number of retry attempts to read from a card
  // configure board to read RFID tags

//Opening TFT sequence
  tft.setCursor(100, 50);
  tft.setTextColor(ILI9341_BLACK);  tft.setTextSize(2);
  tft.println("Welcome to My Project");

void loop() {
  //loop checks to see if NFC tag is present
  boolean success;
  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.print("UID Value: ");
    for (uint8_t i=0; i < uidLength; i++) 
      Serial.print(" 0x");Serial.print(uid[i], HEX); 

    // Display some basic information about the card
    cardid = uid[6]; //find unique card id
    cardid <<=8; cardid |= uid[5];
    cardid <<=8; cardid |= uid[4];
    cardid <<=8; cardid |= uid[3];
    cardid <<=8; cardid |= uid[2];
    cardid <<=8; cardid |= uid[1];
    cardid <<=8; cardid |= uid[0];

    // wait until the card is taken away
    while (nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength)) {}
    // PN532 probably timed out waiting for a card
    Serial.println("Timed out waiting for a card");

Just a guess: the two shields may use different SPI settings (speed, clock polarity, clock phase) that are not compatible with each other.

Your code sets up the LCD first, then sets up the NFC, then talks to the LCD, and finally talks to the NFC. One way what you describe can happen is if the NFC only sets the SPI parameters in its setup function, while the LCD sets it up before each call:

  • LCD library sets up SPI the way the LCD wants it
  • NFC library sets up SPI the way the NFC wants it
  • LCD display operations resets SPI the way it wants it and updates display
  • NFC assumes SPI is still set up the way it wanted it, and fails because LCD changed it

If that's the sequence that's happening, that would explain the behavior. In addition, if you left out step 3, the display update, then things work because SPI is still set up the way the NFC shield wants it (LCD didn't change it.)

I much prefer SPI over I2C: it's more robust and reliable, and once you get it working it just plain works, as opposed to I2C which can easily crash or lock up the bus. BUT, with SPI, you do need to make sure that all of the devices on the bus use the same speed/clock settings, or you need to make sure that settings have been updated before each operation. It's easier to use the same settings for all devices, but that's not always possible, especially when using an existing library.

Some analysis of the two library's source code will confirm or deny this theory.

Ok, I took a look at the libraries for each.

Both use SPI_MODE0.

However, the clocks are different for each.

SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!)

_spi->setClockDivider(SPI_CLOCK_DIV8); // set clock 2MHz(max: 5MHz)

So if I change the LCD clock divider from 2 to 8, it should work?

That sounds promising. Maybe you can get away with a divide by 4, giving 4 MHz to each device?

I made the change in the LCD library in the CPP file. I changed the clock from 2 to 8 to match the NFC shield. Unfortunately, it did not fix my issue.

Is there something else I should change?


HOWEVER, I did take into consideration your comments about the initialization of devices. If I use nfc.begin() before I want to use the NFC shield in loop, it works.

The strange thing is I can always talk to the LCD after talking to the NFC, but I cannot talk to the NFC after talking the the LCD, except if I use nfc.begin() before.

The strange thing is I can always talk to the LCD after talking to the NFC, but I cannot talk to the NFC after talking the the LCD, except if I use nfc.begin() before.

I guess that makes sense, because the LCD can handle the NFC’s slower speed, but the NFC can’t handle the LCD’s faster speed?

I don’t have time to study those libraries at the moment. Are you sure you are using the edited file in your project? Maybe the edited file isn’t being compiled in? (A quick and dirty way I can check if a file is actually being built into the project is to edit it and introduce an intentional error - if the project still builds properly, the file you edited is NOT being included in your project: you have the wrong file.)