Problem with DUE, SdFat and OLED Display - SPI Conflict?

I have created a simple device that reads a bmp from an SD card and displays it on a small Adafruit OLED display. This device works great but is slow using the SD library but fails when I move the code over to SdFat library.

I have searched through many forum postings and this seems to be an SPI conflict problem. I have tried many of the recommendations with no improvement.

Your help is greatly appreciated.

To speed the process of testing I utilized the SD_Quickstart code from the SdFat example directory. I have cut the code down and added in the basic commands that display colors on the OLED display. I am uploading this to my device and have not changed the hardware in any way to keep the variables as limited as possible.

What I have tried so far that has had no impact:
--- setting DISABLE_CHIP_SELECT to -1, 10, 7 (the chip select of the OLED device) as I am unclear about this option's use based upon what I have read in the SdFat documentation.

--- setting the OLED chip select high and low to manually select it for writing (changing the color)

--- setting the cs lines with internal pull up resistors

--- changing the order of the #include statements

Lastly, what I have found is:
-- If I put the sd.begin before the tft.begin, the program reads the sd card without any issues but the OLED remains black

-- If I put the tft.begin before the sd.begin, the program flashes the OLED colors without any issues, but the reading of the SD card fails.

Chip Select for SD = 10 and for the OLED = 7.

I have read on one forum post that SdFat has a problem releasing the sclk line and "pulsing" it may work but I don't know how to go about doing that.

Here is the cut down code that has the tft.begin before the sd.begin.

// Quick hardware test for SPI card access.
//
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>
#include "SdFat.h"
#include <SPI.h>

//
// Set DISABLE_CHIP_SELECT to disable a second SPI device.
// For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
// to 10 to disable the Ethernet controller.
const int8_t DISABLE_CHIP_SELECT = -1;

//
// Test with reduced SPI speed for breadboards.  SD_SCK_MHZ(4) will select 
// the highest speed supported by the board that is not over 4 MHz.
// Change SPI_SPEED to SD_SCK_MHZ(50) for best performance.
#define SPI_SPEED SD_SCK_MHZ(40)


const int8_t SD_CHIP_SELECT = 10;


//------------------------------------------------------------------------------

// ---------------- TFT OLED Code

// OLED Display SPI PINS   -- Built in SD card on Teensy uses separate SPI
// If we are using the hardware SPI interface, these are the pins (for future ref)
#define sclk 13
#define mosi 11
#define cs   7
#define rst  4
#define dc   5

// Color definitions
#define  BLACK           0x0000
#define BLUE            0x001F
#define RED             0xF800
#define GREEN           0x07E0
#define CYAN            0x07FF
#define MAGENTA         0xF81F
#define YELLOW          0xFFE0  
#define WHITE           0xFFFF

// to draw images from the SD card, we will share the hardware SPI interface
Adafruit_SSD1351 tft = Adafruit_SSD1351(cs, dc, rst);

// SD card chip select
#define chipSelect 10


//------------------ End TFT OLED Code

// File system object.
SdFat sd;

// Serial streams
ArduinoOutStream cout(Serial);
/*
// input buffer for line
char cinBuf[40];
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));
*/

void cardOrSpeed() {
  cout << F("Try another SD card or reduce the SPI bus speed.\n");
  cout << F("Edit SPI_SPEED in this program to change it.\n");
}

void reformatMsg() {
  cout << F("Try reformatting the card.  For best results use\n");
  cout << F("the SdFormatter program in SdFat/examples or download\n");
  cout << F("and use SDFormatter from www.sdcard.org/downloads.\n");
}

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

    
 // ------- Start OLED Code
  pinMode(cs, OUTPUT);
  digitalWrite(cs, HIGH);




// recommended on forum  - No effect on code operation / non-operation
  pinMode(cs, INPUT_PULLUP);
  pinMode(chipSelect, INPUT_PULLUP);
  delay(2000);

  // initialize the OLED
  tft.begin();



// TEST -- try initializing the SD after the TFT
sd.begin(chipSelect, SPI_SPEED);
// TEST 




  Serial.println("init -- should see blue screen then green screen");
  
  tft.fillScreen(BLUE);
  delay(1000);
  tft.fillScreen(GREEN);
  delay(1000);

  // ------- End OLED Code


  // SD Quick start code from SdFat example 
  
  cout << F("\nSPI pins:\n");
  cout << F("MISO: ") << int(MISO) << endl;
  cout << F("MOSI: ") << int(MOSI) << endl;
  cout << F("SCK:  ") << int(SCK) << endl;
  cout << F("SS:   ") << int(SS) << endl;

  if (DISABLE_CHIP_SELECT < 0) {
    cout << F(
           "\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
           "a second SPI device.  For example, with the Ethernet\n"
           "shield, DISABLE_CHIP_SELECT should be set to 10\n"
           "to disable the Ethernet controller.\n");
  }
  cout << F(
         "\nSD chip select is the key hardware option.\n"
         "Common values are:\n"
         "Arduino Ethernet shield, pin 4\n"
         "Sparkfun SD shield, pin 8\n"
         "Adafruit SD shields and modules, pin 10\n");

  
  // show red screen... about to exit start up
  tft.fillScreen(RED);
  delay(500);
}

bool firstTry = true;

void loop() {
  // Read any existing Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);

  if (!firstTry) {
    cout << F("\nRestarting\n");
  }
  firstTry = false;

  cout << F("\nEnter any char to continue: ");
  while (!Serial.available()) {
    SysCall::yield();
  }

  if (DISABLE_CHIP_SELECT < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CHIP_SELECT to disable another device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CHIP_SELECT) << endl;
    pinMode(DISABLE_CHIP_SELECT, OUTPUT);
    digitalWrite(DISABLE_CHIP_SELECT, HIGH);
  }

  cout << F("\nCard successfully initialized - B.\n");

// ------------------ OLED Code
  cout << F("\nFilling Screen with BLUE\n");
//  digitalWrite(cs, LOW);
//    delay(1000);
   tft.fillScreen(BLUE); 
//   digitalWrite(cs, HIGH);
// ----------------- END OLED Code
  
  cout << endl;

  uint32_t size = sd.card()->cardSize();
  if (size == 0) {
    cout << F("Can't determine the card size.\n");
    cardOrSpeed();
    return;
  }
  uint32_t sizeMB = 0.000512 * size + 0.5;
  cout << F("Card size: ") << sizeMB;
  cout << F(" MB (MB = 1,000,000 bytes)\n");
  cout << endl;
  cout << F("Volume is FAT") << int(sd.vol()->fatType());
  cout << F(", Cluster size (bytes): ") << 512L * sd.vol()->blocksPerCluster();
  cout << endl << endl;

  cout << F("Files found (date time size name):\n");
  sd.ls(LS_R | LS_DATE | LS_SIZE);

  if ((sizeMB > 1100 && sd.vol()->blocksPerCluster() < 64)
      || (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
    cout << F("\nThis card should be reformatted for best performance.\n");
    cout << F("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
    cout << F("Only cards larger than 2 GB should be formatted FAT32.\n");
    reformatMsg();
    return;
  }
  // Read any extra Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);
  cout << F("\nSuccess!  Type any character to restart.\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
}

Here is an example of the output (tft.begin before sd.begin thus card not reading):

init -- should see blue screen then green screen

SPI pins:
MISO: 74
MOSI: 75
SCK:  76
SS:   10

Be sure to edit DISABLE_CHIP_SELECT if you have
a second SPI device.  For example, with the Ethernet
shield, DISABLE_CHIP_SELECT should be set to 10
to disable the Ethernet controller.

SD chip select is the key hardware option.
Common values are:
Arduino Ethernet shield, pin 4
Sparkfun SD shield, pin 8
Adafruit SD shields and modules, pin 10

Enter any char to continue: 
Assuming the SD is the only SPI device.
Edit DISABLE_CHIP_SELECT to disable another device.

Card successfully initialized - B.

Filling Screen with BLUE

Card size: 7948 MB (MB = 1,000,000 bytes)

Volume is FAT32, Cluster size (bytes): 32768

Files found (date time size name):
2015-10-30 10:46:06      92984 lily128.bmp
2015-11-01 08:24:46      36918 Speaker1.bmp
2015-11-01 08:23:10      36918 Speaker0.bmp
2015-11-01 12:18:18      26166 white.bmp

Success!  Type any character to restart.

OLED_Test_w_SD_QuickStart.ino (5.54 KB)

For the fun :slight_smile: :

If you could replace the SPI library by TurboSpi Library for Sam3x, maybe this could be better.

And some SPI hints:

https://www.dorkbotpdx.org/blog/paul/better_spi_bus_design_in_3_steps

Solved -- SPI speed had to be reduced.

ard_newbie -- thank you for your reply. It was through viewing and reading through the links that I learned how to use SPI transactions that gave me the speed control I needed.

Thank you!