SD card and OLED

I’m working on a project that will log data to an SD card and display a user interface on an OLED. The SparkFun OLED breakout was super easy to set up. I was also able to get the SD-Card library working independently, though that was harder.

The trouble is when I combine these examples the SD card only writes during “setup” after that it isn’t writing to the SD card as the loop continues. The OLED still works just fine. I’ve read up on SPI a bit and tried various things to get “chip select” to work (I suspect this is the problem) I even tried setting the CS pins to LOW or HIGH using digitalWrite, but this had no impact.

My pins are connected as follows:

          SD CARD      OLED  
MOSI        A5            A5     same pin
MISO        A4            --     just SD connected
SCK         A3            A3     same pin
CS          A1            A2     different pins

The SD card writes in the main loop if I comment out all of the code that runs the OLED. The OLED works either way. What could I try next?

Here is the code:

     #include "application.h"
     #include "sd-card-library/sd-card-library.h"
     #include "SparkFunMicroOLED/SparkFunMicroOLED.h"
     #include "math.h"

     //////////////////////////////////
      // MicroOLED Object Declaration //
     //////////////////////////////////
// Declare a MicroOLED object. If no parameters are supplied, default pins are
// used, which will work for the Photon Micro OLED Shield (RST=D7, DC=D6, CS=A2)
//Since I use A1 as the chip select pin for the SD card these defaults seem fine.

MicroOLED oled;
File myFile;

//These are the pins for the SD card. A5, A4, and A3 are all shared by the OLED.
const uint8_t chipSelectSD = A1;
const uint8_t mosiPin = A5;
const uint8_t misoPin = A4;
const uint8_t clockPin = A3;

////////////
//setup//
////////////
void setup() {
delay(500);

SD.begin(mosiPin, misoPin, clockPin, chipSelectSD);
File dataFile = SD.open("data.txt", FILE_WRITE);
dataFile.println("this text was printed to the SD card during setup");
dataFile.close();

oled.begin();  // Initialize the OLED
oled.clear(ALL); // Clear the display's internal memory
delay(1000);  // Delay 1000 ms
oled.clear(PAGE); // Clear the buffer.
randomSeed(analogRead(A0) + analogRead(A7)); //seed to make test pattern random.

}//end setup


//////////////////
//main loop//
//////////////////
void loop()  {

SD.begin(mosiPin, misoPin, clockPin, chipSelectSD);
File dataFile = SD.open("data.txt", FILE_WRITE);
dataFile.println("The text was added during the loop.");
dataFile.close();

//test the display with text and pixels. 
printTitle("Pixels", 1);
for (int i=0; i<512; i++)
{ oled.pixel(random(oled.getLCDWidth()), random(oled.getLCDHeight()));
oled.display(); }
delay(9000);

} //end loop


//-------------------------//
//function to print titles//
//-------------------------//
void printTitle(String title, int font)
{
int middleX = oled.getLCDWidth() / 2;
int middleY = oled.getLCDHeight() / 2;
oled.clear(PAGE);
oled.setFontType(font);
// Try to set the cursor in the middle of the screen
oled.setCursor(middleX - (oled.getFontWidth() * (title.length()/2)),
middleY - (oled.getFontWidth() / 2));
// Print the title:
oled.print(title);
oled.display();
delay(1500);
oled.clear(PAGE);
} //end title function 

This is how the SD card it hooked up.

1 Like

Have you only tried to activate the one you intended to use next, or have you also explicitly deactivated to other CS?

I deactivated and activated …

I am running something very similar and my SD card is recording without issue.

I am not a code expert, far from it, but briefly comparing your code to mine, I believe you only need to call SD.begin () once in setup() and not again in loop().

Thanks for responding! I added that line in since it didn’t work without it either. I tried removing it again and the SD still isn’t being written.

Just a stab in the dark, but since you are using hardware SPI, try to change this

into

SD.begin(SPI_FULL_SPEED, chipSelectSD);  // FULL_SPEED equals SPI_CLOCK_DIV4

and put SD.begin() after oled.begin() since oled.begin() sets SPI speed to SPI_CLOCK_DIV2 which may be a bit fast for SD.
And as @Jseiler said, one call to SD.init() should suffice.


BTW: I'm not too convinced that this part of MicroOLED lib is the best of implementations (see comments)

void MicroOLED::spiSetup()
{
	pinMode(MOSI, OUTPUT); // no harm, but unnecessary - SPI.begin() will take care
	pinMode(SCK, OUTPUT);  // no harm, but unnecessary - SPI.begin() will take care

	pinMode(csPin, OUTPUT);
	digitalWrite(csPin, HIGH);

	SPI.setClockDivider(SPI_CLOCK_DIV2);
	//SPI.setDataMode(SPI_MODE0);
	pinMode(csPin, OUTPUT);      // why again???
	//pinMode(10, OUTPUT);
	digitalWrite(csPin, HIGH);   // why again???
	SPI.begin();
	pinMode(SCK, OUTPUT);  // why this AFTER SPI.begin()???
	pinMode(MOSI, OUTPUT); // why this AFTER SPI.begin()???
}

No idea if this contributes to your problem, but just for having it pointed out.

1 Like

I noticed that to and it made me confused. Maybe I should fork the library? I’m using the online build environment because it’s more stable.

SD.begin(SPI_FULL_SPEED, chipSelectSD);  // FULL_SPEED equals SPI_CLOCK_DIV4

This didn’t but I tried changing the order as you suggested:

#include "application.h"
#include "sd-card-library/sd-card-library.h"
#include "SparkFunMicroOLED/SparkFunMicroOLED.h"  // Include MicroOLED library
#include "math.h"

const uint8_t chipSelectOLED = A2;  
const uint8_t chipSelectSD = A1;  
const uint8_t mosiPin = A5;
const uint8_t misoPin = A4;
const uint8_t clockPin = A3;


File myFile;

//////////////////////////////////
// MicroOLED Object Declaration //
//////////////////////////////////
// Declare a MicroOLED object. If no parameters are supplied, default pins are
// used, which will work for the Photon Micro OLED Shield (RST=D7, DC=D6, CS=A2)
MicroOLED oled(MODE_SPI,D7, D6, A2);
//MicroOLED oled; 

void setup()  {

pinMode(chipSelectOLED, OUTPUT);
pinMode(chipSelectSD, OUTPUT);

//Make the pin for the SD card low to select it.
//Make the pin for the OLED high to deselect it.
//This is in case the libaries are not doing this.
digitalWrite(chipSelectSD,LOW);
digitalWrite(chipSelectOLED,HIGH);

//SPI.begin should happen in the libries. But just in case...
delay(500);

//Now begin the SD card and write something as a test.
SD.begin(mosiPin, misoPin, clockPin, chipSelectSD);   
int fsr1 = analogRead(A0);
File myFile = SD.open("data22.txt", FILE_WRITE);
myFile.println(fsr1);
myFile.println("setup");
myFile.close();

//Done with the SD card switch to OLED.
 digitalWrite(chipSelectSD,HIGH);
 digitalWrite(chipSelectOLED,LOW);

oled.begin();    // Initialize the OLED
}
void loop()
{
    
digitalWrite(chipSelectSD,LOW);
digitalWrite(chipSelectOLED,HIGH);    

delay(500);
int fsr1 = analogRead(A0);
File myFile = SD.open("data22.txt", FILE_WRITE);   
myFile.print(fsr1);
myFile.println("loop");
myFile.close();

digitalWrite(chipSelectSD,HIGH);
digitalWrite(chipSelectOLED,LOW);
 
  oled.clear(ALL); // Clear the display's internal memory
  delay(1000);     // Delay 1000 ms
  oled.clear(PAGE); // Clear the buffer.
  oled.display();
  randomSeed(analogRead(A0) + analogRead(A7));

  printTitle("text", 1);

// print random pixles all over
  for (int i=0; i<512; i++)
 { oled.pixel(random(oled.getLCDWidth()), random(oled.getLCDHeight()));
  oled.display(); }

 delay(2000);
 
}

This code fails to write anything to the SD card. Not even the “setup” test print which worked before.

Doh! Silly me - it should be SD.begin(chipSelectSD); - the other version came from the Sd2Card class Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).

And for the other part, could you activate Serial.begin(115200) and check if you get any debug output of the libraries?
Further more do I still see oled.begin() as last line in setup().
I'd also start with both CS lines inactive and let the respective libraries take the line active (don't need to care for pinMode() either).

BTW: If you need to take manual control of CS try to make sure to avoid both lines being LOW (active) at the same time
Unlike

void setup()  {
  ...
 digitalWrite(chipSelectSD,HIGH);
 digitalWrite(chipSelectOLED,LOW);
 ...
}
void loop()
{
  digitalWrite(chipSelectSD,LOW);
  digitalWrite(chipSelectOLED,HIGH);
  ...    
}

Best to put the HIGH line first.

It’s working!!!
Thanks so much for the help!

I didn’t need to mess with the HIGH and LOW values after all.

// must start with a comment or it won't compile?
     #include "application.h"
     #include "sd-card-library/sd-card-library.h"
     #include "SparkFunMicroOLED/SparkFunMicroOLED.h"
     #include "math.h"

     //////////////////////////////////
      // MicroOLED Object Declaration //
     //////////////////////////////////
     // Declare a MicroOLED object. If no parameters are supplied, default pins are
     // used, which will work for the Photon Micro OLED Shield (RST=D7, DC=D6, CS=A2)
     //Since I use A1 as the chip select pin for the SD card these defaults seem fine.

    MicroOLED oled;
    File dataFile;

//These are the pins for the SD card. A5, A4, and A3 are all shared by the OLED.
const uint8_t chipSelectSD = A1;
const uint8_t mosiPin = A5;
const uint8_t misoPin = A4;
const uint8_t clockPin = A3;

////////////
//setup//
////////////
void setup() {
delay(500);


// THIS CHANGE FIXED IT!
// Changed this:
// SD.begin(mosiPin, misoPin, clockPin, chipSelectSD);
// To this:
SD.begin(chipSelectSD);


File dataFile = SD.open("data.txt", FILE_WRITE);
dataFile.println("setup text");
dataFile.close();

                           }//end setup


//////////////////
//main loop//
//////////////////
void loop()  {

//SD.begin(mosiPin, misoPin, clockPin, chipSelectSD);
File dataFile = SD.open("data.txt", FILE_WRITE);
dataFile.println("The text was added during the loop.");
dataFile.close();
oled.begin();  // Initialize the OLED 
// is it good to do this over and over Hmmmm?
oled.clear(ALL); // Clear the display's internal memory
delay(1000);  // Delay 1000 ms
oled.clear(PAGE); // Clear the buffer.
randomSeed(analogRead(A0) + analogRead(A7)); //seed to make test pattern random.

//test the display with pixels. 
for (int i=0; i<512; i++)
{ oled.pixel(random(oled.getLCDWidth()), random(oled.getLCDHeight()));
oled.display(); }
delay(2000);

                      } //end main loop
2 Likes

I would not do this that often and it's not necessary.
If you happen to run into display troubles, you might do it on demand (maybe along with a display reset).