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)