Adafruit ESP32-S3 tft feather + RTC/SD Adalogger Featherwing

Hello all, I am new to using this forum, and new to ESP32 so please be kind.

Here is my issue -- I have an ESP32-S3 tft feather board:
ESP32-S3 TFT Feather

And an Adalogger FeatherWing:
Adalogger FeatherWing

I am having (hair-pulling) trouble getting the SPI bus to interface with the SD card on the Adalogger. The SPI for the mainboards TFT display and Neopixel work fine, and the i2c for the Adaloggers RTC works fine, but I just cannot get the SD to interface. Can someone point me in the right direction?

#include <Update.h>
#include <Arduino.h>
// --------------------
// Graphics and TFT Libraries
#include <Adafruit_GFX.h>
#include <Adafruit_GrayOLED.h>
#include <Adafruit_SPITFT.h>
#include <Adafruit_SPITFT_Macros.h>
#include <gfxfont.h>
#include <Adafruit_NeoPixel.h>
#define NEOPIN 33
#define NEOPOWER 34
//#include <Adafruit_ST7789.h>
#include <Adafruit_SCD30.h>
#include <Adafruit_ST7789.h>
// RTC + SD
#include <RTClib.h>
#include <SD.h>
// SPI Lib Required for ESP32 additional SPI busses 
#include <SPI.h>
// PREFERENCES LIBRARY FOR ACCESSING FLASH DATA
#include <Preferences.h>
// CO2LIMIT IS THE MAIN VARIABLE WE WANT TO STORE IN FLASH (FOR NOW)
int CO2LIMIT = 2500;
// ---------
// WIFI STUFF
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>

const char* ssid = "my ssid"; // REPLACED INTENTIONALLY
const char* password = "my password";  // REPLACED INTENTIONALLY



/*
// -----
// -----
MUSHROOM MONITOR 2.0 
// -----
// -----
*/

// -----
// SD Pins (Integrate for use with the SD card eventually)
// uint8_t const SS_PIN = SS;
// uint8_t const MOSI_PIN = MOSI;
// uint8_t const MISO_PIN = MISO;
// uint8_t const SCK_PIN = SCK;
#define SDCS 10
#define SDMOSI 35
#define SDMISO 37
#define SPICLK 36
//#define VSPI FSPI
//uninitalised pointers to SPI objects
SPIClass * fspi = NULL;
SPIClass * hspi = NULL;
//SPIClass spi = NULL;
//spi = new SPIClass(HSPI);
//spi->begin(SPICLK, SDMISO, SDMOSI, SDCS);
// BACKLIGHT AND RESET PINS (FOR ESP32S3-TFT)
#define TFT_BACKLIGHT 45
#define TFT_RST 40
#define RELAY_PIN 17
// Colour definitions (for TFT)
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define GREY 0xCCCC
// --------------------------

// Initializer Names
WebServer server(80);
Preferences preferences;
Adafruit_SCD30 scd30;
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
Adafruit_NeoPixel strip(1, NEOPIN, NEO_GRB + NEO_KHZ800);
RTC_PCF8523 rtc;
File myFile;
//int CO2LIMIT = 2500;
bool RELAY_ON = false;
bool manualOverride = false;
float latestTemp = 0;
float latestRH = 0;
float latestCO2 = 0;
String webTime = "";
String SendHTML() {
  String htmlData = "<html><head><meta name='viewport' content='width=device-width, initial-scale=1.0'><style>button{user-select:none}input,button{margin-bottom:1%;padding:1%;font-family:Century Gothic;}body{font-family:Century Gothic;background:#EEE; color:black}.links{color:black;margin-bottom:0.5%;margin-left:5%;width:20%;text-align:center;display:block;text-decoration:none;padding:0.5%;border:1px solid black}.links:hover{background:#ccc}</style></head>";
  htmlData += "<button style='float:right;margin-top:1%;margin-left:1%;'name='restart'onclick='getRestart()'>Restart</button>";
  htmlData += "<body><h1>MUSHY MONITOR</h1>";
  htmlData += "<h2>ROOM CONDITIONS: </h2>";
  htmlData += "<h3>TIME: <div id='timeVal'></div>  </h3>";
  htmlData += "<h3>TEMP (C): <div id='tempVal'></div>  </h3>";
  htmlData += "<h3>RH%: <div id='rhVal'></div>  </h3>";
  htmlData += "<h3>Current CO2: <div id='co2Val'></div>ppm </h3>";
  htmlData += "<h3>Current CO2 Limit: <div id='co2Lim'></div> </h3>";
  htmlData += "<div style='margin-bottom:1%;text-align:center;border:1px solid black;padding:2%;width:20%'id='relay'></div>";
  htmlData += "<input id='co2limit' type='number'placeholder='New C02 Limit (in ppm)'/><br>";
  htmlData += "<button style='margin-top:1%;'name='?co2limit='onclick='sendReq(this.previousSibling.previousSibling.value)'>Set C02 Limit</button>";
  htmlData += "<button style='margin-top:1%;'name='?manualoverride='onmouseup='manualOverrideOff()'onmousedown='manualOverrideOn()'>Manual Override (Hold Down)</button>";
  htmlData += "</body>";
  htmlData += "<script>";
  htmlData += "var xhttp = new XMLHttpRequest();";
  htmlData += "function getRestart(){xhttp.open('GET', 'restartESP', true);xhttp.send()};";
  htmlData += "function manualOverrideOn(){xhttp.open('GET', 'manualOverrideOn', true);xhttp.send()};";
  htmlData += "function manualOverrideOff(){xhttp.open('GET', 'manualOverrideOff', true);xhttp.send()};";
  htmlData += "function sendReq(data){xhttp.open('POST', 'updateLimit', true);xhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');xhttp.send('newLimit='+data)};";
  htmlData += "setInterval(function() {updateReq();}, 400);";
  htmlData += "function updateReq(){ xhttp.onreadystatechange = function() {";
  htmlData += "if (this.readyState == 4 && this.status == 200) {var tempData = this.responseText.split(',');";
  htmlData += "document.getElementById('tempVal').innerHTML = tempData[0];document.getElementById('rhVal').innerHTML = tempData[1];document.getElementById('co2Val').innerHTML = tempData[2];document.getElementById('co2Lim').innerHTML = tempData[3];document.getElementById('timeVal').innerHTML = tempData[5];";
  htmlData += "if(tempData[4] == true){document.getElementById('relay').innerHTML = 'RELAY ON';document.getElementById('relay').style.background='#FFB300'}else if (tempData[4] == false){document.getElementById('relay').innerHTML = 'RELAY OFF';document.getElementById('relay').style.background='#4CAF50'}}};";
  htmlData += "xhttp.open('GET', 'updateReq', true);xhttp.send();};";
  htmlData += "</script></html>";
  return htmlData;
}

// HTTP REQUEST (GET + POST) HANDLING FUNCTIONS
void handleRoot() {
  //digitalWrite(led, 1);
  server.send(200, "text/html", SendHTML());
  //digitalWrite(led, 0);
}
void handleUpdate() {
  String updateData = String(latestTemp) + "," + String(latestRH) + "," + String(latestCO2) + "," + String(CO2LIMIT) + "," + String(RELAY_ON) + "," + String(webTime);
  server.send(200, "text/plane", updateData);
}
void handleRestart() {
  ESP.restart();
}
void handleOverride() {
  manualOverride = true;
}
void disableOverride() {
  manualOverride = false;
}
void updateLimit() {
  //Serial.print(server.args());
  String tempLimit = server.arg(0);
  preferences.putUInt("co2limit", tempLimit.toInt());
  CO2LIMIT = tempLimit.toInt();
  tft.print("newLim: " + String(tempLimit));
  //String updateData = String(latestTemp)+","+String(latestRH)+","+String(latestCO2)+","+String(CO2LIMIT);
  //server.send(200, "text/plane",updateData); //Send ADC value only to client ajax request
}
void handleNotFound() {
  //digitalWrite(led, 1);
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  //digitalWrite(led, 0);
}
// ----------
// SETUP
// ----------
void setup() {
  // SERIAL INIT

  Serial.begin(9600);
 
  // ------------

  // SPI INIT (ESP32 Requires initializing one of its extra SPI busses?)
  //hspi = new SPIClass(HSPI);
 // hspi->begin(SPICLK,SDMISO,SDMOSI,SDCS);
 // pinMode(hspi->pinSS(), OUTPUT);  //HSPI SS
  // -----------------------
  fspi = new SPIClass(FSPI);
  fspi->begin(SPICLK,SDMISO,SDMOSI,SDCS);  // I read online about initializing one of the other SPI buses, the pinout for the Feather shows the 'fspi' bus on the SPI breakout pins -- No luck here yet either.....

  pinMode(fspi->pinSS(), OUTPUT);  //FSPI SS
  //SPI.begin(SPICLK,SDMISO,SDMOSI,SDCS);
  // PREFERENCES INIT
  preferences.begin("monitorsettings", false);
  // ----------
  // PINMODE INITS
  pinMode(7,OUTPUT);
  pinMode(SDCS,OUTPUT);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(TFT_BACKLIGHT, INPUT);
  //pinMode(NEOPOWER,OUTPUT);
  //digitalWrite(NEOPOWER,LOW);
  //strip.begin();
 // strip.show();
  //strip.setPixelColor(0,255,255,255);
  //strip.show();
  analogWrite(TFT_BACKLIGHT, 128);
  // ----------

  // ----------
  // WIFI INIT AND SETTINGS
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  // ----------
  // RTC INIT
  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }
  if (!rtc.initialized() || rtc.lostPower()) {
    Serial.println("RTC is NOT initialized, let's set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  rtc.start();
  // ----------
  // SD INIT
  Serial.print("Initializing SD card...");
  //digitalWrite(7,LOW);
  //digitalWrite(SDCS,HIGH);
  SD.begin(SDCS);

  // ----------
  // CO2 SENSOR INIT
  Serial.println("Starting CO2 Monitor!");
  if (!scd30.begin()) {
    Serial.println("Failed to find SCD30 chip");
    while (1) { delay(10); }
  }
  if (scd30.selfCalibrationEnabled()) {
    Serial.print("Self calibration enabled");
  } else {
    Serial.print("Self calibration disabled");
  }
  // SETTING CO2 MEASUREMENT INTERVAL (IN SECONDS)
  scd30.setMeasurementInterval(4);
  Serial.println("SCD30 Found!");
  //-----------
  // TFT INIT
  tft.init(135, 240);  // Init ST7789 240x135
  tft.setRotation(1);
  tft.fillScreen(ST77XX_BLACK);
  tft.setTextSize(2);
  tft.setTextColor(WHITE);
  tft.setCursor(0, 0);
  tft.println("Mushy Monitor 2.0!");
  // SD FILE TEST
  
  myFile = SD.open("test.txt");
  if (myFile) {
    //tft.print("test.txt:");

  
    // read from the file until there's nothing else in it:
    while (myFile.available()) {
      Serial.print(myFile.read());
    }
    // close the file:
    myFile.close();
  } else {
    // if the file didn't open, print an error:
    Serial.println(SD.exists("test.txt"));
    //tft.println(myFile.size());
    Serial.println("error opening test.txt");
  }
  delay(3000);
  //digitalWrite(7,HIGH);
  //digitalWrite(SDCS,LOW);
  
  tft.fillScreen(ST77XX_BLACK);
  //-------------------
  // NAMESERVER INIT
  if (MDNS.begin("esp32")) {
    Serial.println("MDNS responder started");
  }
  // ----------
  // WEBSERVER INIT; WEBSERVER GET + POST HANDLERS
  server.on("/", handleRoot);
  server.on("/updateReq", handleUpdate);
  server.on("/restartESP", handleRestart);
  server.on("/manualOverrideOn", handleOverride);
  server.on("/manualOverrideOff", disableOverride);
  server.on("/updateLimit", HTTP_POST, updateLimit);
  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });
  // ----------
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP server started");
  // ----------
}

// MAIN LOOP
void loop() {
  DateTime now = rtc.now();
  webTime = String(" " + String(now.day()) + "/" + String(now.month()) + "/" + String(now.year()) + " -- " + String(now.hour()) + ":" + String(now.minute()) + ":" + String(now.second()));
  // WATCHDOG FUNCTION

  unsigned int CO2LIMITSETTING = preferences.getUInt("co2limit", 0);
  CO2LIMIT = CO2LIMITSETTING;

  if (scd30.dataReady()) {
    scd30.read();
    latestTemp = scd30.temperature;
    latestRH = scd30.relative_humidity;
    latestCO2 = scd30.CO2;
    // ONLY UPDATE SCREEN ON A NEW READING
    tft.fillScreen(ST77XX_BLACK);
    tft.setCursor(0, 0);
    tft.setTextSize(3);
    tft.print("Temp: ");
    tft.println(String(latestTemp));
    tft.print("RH %: ");
    tft.println(String(latestRH));
    tft.print("C: ");
    tft.print(String(latestCO2));
    tft.println("ppm");
    tft.setTextSize(2);
    tft.print("LIMIT: " + String(CO2LIMIT));
    tft.println("ppm");
    tft.println(" ");
    tft.println("IP: " + String(WiFi.localIP().toString().c_str()));
    // SERIAL OUTPUT
    Serial.println("-------------------");
    Serial.print("Time:");
    Serial.println(webTime);
    Serial.print("Temp: ");
    Serial.println(scd30.temperature);
    Serial.print("RH %: ");
    Serial.println(scd30.relative_humidity);
    Serial.print("CO2: ");
    Serial.print(scd30.CO2, 3);
    Serial.println("ppm");
    Serial.print(CO2LIMIT);
    Serial.println("ppm");
    //Serial.print(CO2LIMITSETTING);
    //Serial.println("ppm");
  }

  if (latestCO2 > CO2LIMIT + 50 || manualOverride) {
    digitalWrite(RELAY_PIN, HIGH);
    RELAY_ON = true;
  } else {
    digitalWrite(RELAY_PIN, LOW);
    RELAY_ON = false;
  }
  server.handleClient();
  delay(20);  //allow the cpu to switch to other tasks
              /*
    Serial.print("MOSI: ");
  Serial.println(MOSI);
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);
  Serial.print("SS: ");
  Serial.println(SS);
  */

}

Thank you in advance -- If there is some glaring mistake please be kind in pointing it out

Forget about the existing code and try to get the SD working without it; integrating can come later.

Your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advice on) your project.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.