SD_Card not working with We-Act Studio 2.13" Eink display on ESP32

Hi,
some weeks ago I submitted the same issue to this forum and I was not able to solve my problem, even if one of the forumers (ZinggJM) spent some time trying to help me.
The problem is that I am an old (73y) newbie and some problems that for you are trivial for me are just ... a problem
However, in these weekis I was able to arrange a datalogger with ESP32, two temp/hum sensors and a RTC (DS3231) in order to save data on a SD card in the following systems:
a) an ESP32 comnnected to SSD 1306 or SH1107;
b) a TTGO-Tdisplay-S3;
c) an ESP32 with integrated OLED display ( even ìf it just works when coded with micropython).

However, when I tried to use an E-ink display I was not able to save data on SD card.
In fact, both using the Lilygo-T5 Eink-display board and a 2.13" display from WeAct Studio connected with ESP32 I always get some errors even if the SD card is initialized and the display correctly shows the data from sensors and from RTC.

The error that I get is "Failed to open file for appending".

I also tried to contact people from Lilygo and I sent my code but they said that there was no error in the code.
So, at the present moment, I'm just stuck

Thanks in advance for your precious help

My code is

#include <SPI.h> //for the SD card 
#include <Wire.h>

#include "FS.h"
#include <SD.h> // for the SD card


#define SDCARD_SS 33
#define SDCARD_CLK 25
#define SDCARD_MOSI 26
#define SDCARD_MISO 27

SPIClass sdSPI(VSPI);

bool sdOK = false;

#include <RTClib.h> // for the RTC
RTC_DS3231 rtc; 

//libraries for e-paper display
#define ENABLE_GxEPD2_GFX 0

#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <Fonts/FreeMonoBold9pt7b.h>

// ESP32 SS=5,SCL(SCK)=18,SDA(MOSI)=23,BUSY=15,RST=2,DC=0 wiring to ESP32 for E_paper as requested by manufacturer

// 2.13'' EPD Module
GxEPD2_3C<GxEPD2_213_Z98c, GxEPD2_213_Z98c::HEIGHT> display(GxEPD2_213_Z98c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/15)); // GDEY0213Z98 122x250, SSD1680

//libraries for BME280 sensor
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

//library for SHT3x sensor
#include <SHT3x.h>
SHT3x Sensor; 
 
// variables to store data from sensors ( float type because they are value with a decimal part)

   float temp;
   float hum;
   float TEMP;
   float HUM;
    
String timeStamp;

// variables to define sleep time; the first multiplies the value to get seconds from microseconds; the second says the sleep time in seconds (1200 = 30 minutes)
uint64_t uS_TO_S_FACTOR = 1000000; 
uint64_t TIME_TO_SLEEP = 300; //sleep for 5 minutes

String dataMessage;

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

// setting a counter for data readings; it will increase every time data from sensors are collected
RTC_DATA_ATTR int sensor_data = 0;

// initializing string data to save data collected from sensors

String Data;

#define sensor_data(temp,hum,TEMP,HUM);

void gettimeStamp() {
    DateTime now = rtc.now();

char timeStamp[9];
 sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());

  Serial.println(timeStamp);
}

void Read_TempHum()
{  
    TEMP = Sensor.GetTemperature();
     HUM = Sensor.GetRelHumidity();

    DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
  Serial.print("Temp_BME280 = ");
  Serial.print(temp);
  Serial.println(" C");
  Serial.print("Hum_BME280 = ");
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temp_SHT3x = ");
  Serial.print(TEMP);
  Serial.println(" C");
  Serial.print("Hum_SHT3X = ");
  Serial.print(HUM);
  Serial.println(" %");
}

void logSDCard() {
   DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
//dataMessage = String(timeStamp) + "\r\n";
 dataMessage =  String(sensor_data) + ","+String(timeStamp) + "," + 
               String(temp) + "," + String(hum)+ "," + String(TEMP) + "," + String(HUM) +"\r\n";
  Serial.print("Save data: ");
  Serial.println(dataMessage);
  appendFile(SD, "/data.txt", dataMessage.c_str());
}

// Write to the SD card (DON'T MODIFY THIS FUNCTION)
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);
  File file = fs.open(path, FILE_WRITE);
  if(!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}
// Append data to the SD card (DON'T MODIFY THIS FUNCTION)
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);
  File file = fs.open(path, FILE_APPEND);
  if(!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void displayReadings() {
  DateTime now = rtc.now();

char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second()); 
display.init(115200,true,50,false);  
display.setRotation(1);
display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);
  display.setFullWindow();
  display.firstPage();
  do
  {
  display.fillScreen(GxEPD_WHITE);
  display.setCursor(0,10); 
     display.print("temp_BME= ");
    display.print(temp);
    display.println(" C");
    display.setCursor(0,30);
    display.print("temp_SHT= ");
    display.print(TEMP);
    display.println(" C");
    display.setCursor(0,50);
    display.print("hum_BME= ");
    display.print(hum);
    display.println(" %");
    display.setCursor(0,70);
    display.print("hum_SHT= ");
    display.print(HUM); 
    display.println(" %");
    display.setCursor(0,90);
    display.setTextColor(GxEPD_RED);
    display.print("sleeping for 5 min");
    display.setCursor(0,110);
    display.print("# ");
    display.print(sensor_data);
    display.print("    ");
    display.print(timeStamp);
  }
    while(display.nextPage());
    delay(100);
    display.hibernate();
      }

void setup() {
   //initializing Serial monitor
  Serial.begin(115200);
    while(!Serial);
  delay(1000);

   if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  } 

bme.begin(0x76);  
 temp = bme.readTemperature();
 hum= bme.readHumidity();

 // checking the BME280 connections and initializing the sensor

  //initializing the SHT31 sensor
  
Sensor.Begin();
Sensor.UpdateData();
TEMP = Sensor.GetTemperature(); 
 HUM = Sensor.GetRelHumidity();

  //Initialize DS3231
Serial.println("Initialize DS3231");

   // setup for the RTC
  while(!Serial); 
  delay(1000);
 if(! rtc.begin()) {
      Serial.println("Couldn't find RTC");
      while (1);
    }
    else {
      // following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

//initializing SD card
     sdSPI.begin(SDCARD_CLK, SDCARD_MISO, SDCARD_MOSI, SDCARD_SS);
    if (!SD.begin((33), sdSPI)) {
        sdOK = false;
        Serial.println("Card Mount Failed");
    } else {
        sdOK = true;
        Serial.println("SDcard initialized!!"); 
    }
   
  File file = SD.open("/data.txt");
  if(!file) {
    Serial.println("File doens't exist");
    Serial.println("Creating file...");
    writeFile(SD, "/data.txt", "dataMessage \r\n");
  }
  else {
    Serial.println("File already exists");  
  }
  file.close();
  
   display.init(115200,true,50,false);
   
   delay(1000);

  Read_TempHum();
  gettimeStamp();
    logSDCard();
    delay(3000);
  displayReadings();

  
 delay(4000);
 display.hibernate();

  // increasing the counter for the next data readings

  sensor_data++;
  
    Serial.println("Sensor data logged successfully! Going to sleep");

// ESP32 going to sleep for the amount of time you decided
   esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(3000);

  esp_deep_sleep_start(); 
}

void loop() {



I was working the ESP32 SD library a few weeks ago, and was having great difficulty.
I am not sure if it related to your situation, but in my case it turned out to be related to a bug in the library code:

The issue has not been resolved, but I did eventually work around the problem.

Unfortunately I did not test FILE_APPEND. Have you tried opening as FILE_READ or FILE_WRITE, just to test? I wouldn't expect it to work, but it might help identify whether you are facing the same issue as I was.

If you didn't already, it would be good to test open() with:

  • a non-existent filename
  • a blank file (0 bytes)
  • a file containing data

This could all be irrelevant, but maybe it can help identify the issue. If nothing else, be aware that there are current bugs in the ESP32 SD library.

I've just had a closer look at your code. Is this section here working correctly?

If so, what do you get in data.txt?

Hi,
thx for your help and sorry for the delay but I spent a goog part of this Sunday trying to understand what could be the problem, following your advice.
I checked side byu side and line by line two codes, one working as expected with an 1306 SSD display and the other one with the error ( Failed to append file ) when the display is an E-Ink.
Taking into account the differences in the libraries needed for these two different displays everything else seems to me the same. So I'm prone to think that the problem is not in the library of SD but on the interaction between the display and the SD card
In the serial monitor when the EInk is used the info on SD card is somewhat " truncated" as if the process is interrupted.

I'm enclosing the screenshot from serial monitor when using the 1306 SSD Oled display


and the screenshot from serial monitor when using the WeAct Studio 2.13" E-Ink display

Here you can find the code properly woking wgen an OLED display is used ( but the same happens if I use a TFT display)

/THIS CODE RUNS WITH THE ASSEMBLY ARRANGED ON BREADBOARD NUMBER 1
//REMEMBER AFTER COMPILING THAT YOU NEED TO COMMENT LINE 201 IN ORDER TO KEEP CORRECT rtc TIME DURING DEEP SLEEP

#include <SPI.h> //for the SD card 
#include <Wire.h>

#include "FS.h"
#include <SD.h> // for the SD card

#define SDCARD_SS 33
#define SDCARD_CLK 25
#define SDCARD_MOSI 26
#define SDCARD_MISO 27

SPIClass sdSPI(VSPI);

bool sdOK = false;

#include <RTClib.h> // for the RTC
RTC_DS3231 rtc; 

// libraries needed for SSD1306 OLED disoplay and definition of the display characteristics


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_ADDR   0x3C
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET 1  // Pin 8
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

//library for SHT3x sensor
#include <SHT3x.h>
SHT3x Sensor; //This operates in Celsius

// variables to store data from sensors ( float type because they are value with a decimal part)

   float temp;
   float hum;
   float TEMP;
   float HUM;

String timeStamp;

// variables to define sleep time; the first multiplies the value to get seconds from microseconds; the second says the sleep time in seconds (1200 = 30 minutes)
uint64_t uS_TO_S_FACTOR = 1000000; 
uint64_t TIME_TO_SLEEP = 300; 

String dataMessage;

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

// setting a counter for data readings; it will increase every time data from sensors are collected
RTC_DATA_ATTR int sensor_data = 0;

// initializing string data to save data collected from sensors
String Data;
#define sensor_data(temp,hum,TEMP,HUM);

void gettimeStamp() {
    DateTime now = rtc.now();

char timeStamp[9];
 sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());

  Serial.println(timeStamp);
}

void Read_TempHum()
{  
  TEMP = Sensor.GetTemperature();
  HUM = Sensor.GetRelHumidity();

    DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
  Serial.println(timeStamp);
  Serial.print("Temp_BME280 = ");
  Serial.print(temp);
  Serial.println(" C");
  Serial.print("Hum_BME280 = ");
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temp_SHT3x = ");
  Serial.print(TEMP);
  Serial.println(" C");
  Serial.print("Hum_SHT3X = ");
  Serial.print(HUM);
  Serial.println(" %");
}

void logSDCard() {
   DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
dataMessage = String(timeStamp) + "\r\n";
 dataMessage =  String(sensor_data) + ","+String(timeStamp) + "," + 
               String(temp) + "," + String(hum)+ "," + String(TEMP) + "," + String(HUM) +"\r\n";
  Serial.print("Save data: ");
  Serial.println(dataMessage);
  appendFile(SD, "/data.txt", dataMessage.c_str());
}

// Write to the SD card (DON'T MODIFY THIS FUNCTION)
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);
  File file = fs.open(path, FILE_WRITE);
  if(!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

// Append data to the SD card (DON'T MODIFY THIS FUNCTION)
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);
  File file = fs.open(path, FILE_APPEND);
  if(!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void displayReadings() {
   DateTime now = rtc.now();

char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
display.clearDisplay();
display.setCursor(0,0); 
display.println(timeStamp);
display.setCursor(0,10);
display.print("T_BME   ");
display.print(temp);
display.println(" C"); 
display.setCursor(0,20);
display.print("T_SHT   ");
display.print(TEMP);
display.println(" C");
display.setCursor(0,35);
display.print("Hum_BME  ");
display.print(hum);
display.println(" %");
display.setCursor(0,45);
display.print("Hum_SHT  ");
display.print(HUM);
display.println(" %");
display.print(sensor_data );
display.print("/");
display.print("sleep for 30 min");
display.display(); //Invia il buffer da visualizzare al display
}

void setup() {
  //initializing Serial monitor
  Serial.begin(115200);
    while(!Serial);
  delay(1000);

  bme.begin(0x76);  

  temp = bme.readTemperature();
  hum= bme.readHumidity();

    //initializing the SHT31 sensor
 Sensor.Begin();
 Sensor.UpdateData();
 TEMP = Sensor.GetTemperature(); 
 HUM = Sensor.GetRelHumidity();

   //Initialize DS3231
Serial.println("Initialize DS3231");

    // setup for the RTC
  while(!Serial); 
  delay(1000);
 if(! rtc.begin()) {
      Serial.println("Couldn't find RTC");
      while (1);
    }
    else {
      // following line sets the RTC to the date & time this sketch was compiled
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

 //initializing SD card
     sdSPI.begin(SDCARD_CLK, SDCARD_MISO, SDCARD_MOSI, SDCARD_SS);
    if (!SD.begin((33), sdSPI)) {
        sdOK = false;
        Serial.println("Card Mount Failed");
    } else {
        sdOK = true;
        Serial.println("SDcard initialized!!"); 
    }
   
  File file = SD.open("/data.txt");
  if(!file) {
    Serial.println("File doens't exist");
    Serial.println("Creating file...");
    writeFile(SD, "/data.txt", "dataMessage \r\n");
  }
  else {
    Serial.println("File already exists");  
  }
  file.close();
  
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C, false, false)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  delay(2000);

  display.clearDisplay(); 
  display.setTextSize(1);  
  display.setTextColor(WHITE);
  display.ssd1306_command(SSD1306_DISPLAYON); 

  Read_TempHum();
  gettimeStamp();
  logSDCard();
  displayReadings();
  
  
   esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(5000);

   display.ssd1306_command(SSD1306_DISPLAYOFF);

    // increasing the counter for the next data readings

  sensor_data++;

   Serial.println("Sensor data logged successfully! Going to sleep for 15 minutes");

// ESP32 going to sleep for the amount of time you decided

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
delay(3000);
esp_deep_sleep_start();
}

void loop() {
}

and here you have again the code that with the E_Ink display doesn't work




#include <SPI.h> //for the SD card 
#include <Wire.h>

#include "FS.h"
#include <SD.h> // for the SD card

#define SDCARD_SS 33
#define SDCARD_CLK 25
#define SDCARD_MOSI 26
#define SDCARD_MISO 27

SPIClass sdSPI(VSPI);

bool sdOK = false;

#include <RTClib.h> // for the RTC
RTC_DS3231 rtc; 

//libraries for e-paper display
#define ENABLE_GxEPD2_GFX 0

#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <Fonts/FreeMonoBold9pt7b.h>

// ESP32 SS=5,SCL(SCK)=18,SDA(MOSI)=23,BUSY=15,RST=2,DC=0 wiring to ESP32 for E_paper as requested by manufacturer

// 2.13'' EPD Module
GxEPD2_3C<GxEPD2_213_Z98c, GxEPD2_213_Z98c::HEIGHT> display(GxEPD2_213_Z98c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/15)); // GDEY0213Z98 122x250, SSD1680

#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

//library for SHT3x sensor
#include <SHT3x.h>
SHT3x Sensor; 
 
// variables to store data from sensors ( float type because they are value with a decimal part)

   float temp;
   float hum;
   float TEMP;
   float HUM;
    
String timeStamp;

// variables to define sleep time; the first multiplies the value to get seconds from microseconds; the second says the sleep time in seconds (1200 = 30 minutes)
uint64_t uS_TO_S_FACTOR = 1000000; 
uint64_t TIME_TO_SLEEP = 300; //sleep for 5 minutes

String dataMessage;

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

// setting a counter for data readings; it will increase every time data from sensors are collected
RTC_DATA_ATTR int sensor_data = 0;

// initializing string data to save data collected from sensors
String Data;
#define sensor_data(temp,hum,TEMP,HUM);

void gettimeStamp() {
    DateTime now = rtc.now();

char timeStamp[9];
 sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());

  Serial.println(timeStamp);
}

void Read_TempHum()
{  
    TEMP = Sensor.GetTemperature();
     HUM = Sensor.GetRelHumidity();

    DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
  Serial.println(timeStamp);
  Serial.print("Temp_BME280 = ");
  Serial.print(temp);
  Serial.println(" C");
  Serial.print("Hum_BME280 = ");
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temp_SHT3x = ");
  Serial.print(TEMP);
  Serial.println(" C");
  Serial.print("Hum_SHT3X = ");
  Serial.print(HUM);
  Serial.println(" %");
}

void logSDCard() {
   DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
dataMessage = String(timeStamp) + "\r\n";
dataMessage =  String(sensor_data) + ","+String(timeStamp) + "," + 
               String(temp) + "," + String(hum)+ "," + String(TEMP) + "," + String(HUM) +"\r\n";
  Serial.print("Save data: ");
  Serial.println(dataMessage);
  appendFile(SD, "/data.txt", dataMessage.c_str());
}

// Write to the SD card (DON'T MODIFY THIS FUNCTION)
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);
  File file = fs.open(path, FILE_WRITE);
  if(!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

// Append data to the SD card (DON'T MODIFY THIS FUNCTION)
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);
  File file = fs.open(path, FILE_APPEND);
  if(!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void displayReadings() {
  DateTime now = rtc.now();

char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second()); 
display.init(115200,true,50,false);  
display.setRotation(1);
display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);
  display.setFullWindow();
  display.firstPage();
  do
  {
  display.fillScreen(GxEPD_WHITE);
  display.setCursor(0,10); 
     display.print("temp_BME= ");
    display.print(temp);
    display.println(" C");
    display.setCursor(0,30);
    display.print("temp_SHT= ");
    display.print(TEMP);
    display.println(" C");
    display.setCursor(0,50);
    display.print("hum_BME= ");
    display.print(hum);
    display.println(" %");
    display.setCursor(0,70);
    display.print("hum_SHT= ");
    display.print(HUM); 
    display.println(" %");
    display.setCursor(0,90);
    //display.setTextColor(GxEPD_RED);
    display.print("sleeping for 5 min");
    display.setCursor(0,110);
    display.print("# ");
    display.print(sensor_data);
    display.print("    ");
    display.print(timeStamp);
  }
    while(display.nextPage());
    delay(100);

      }

void setup() {
   //initializing Serial monitor
  Serial.begin(115200);
    while(!Serial);
  delay(1000);

   if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  } 

bme.begin(0x76);  

 temp = bme.readTemperature();
 hum= bme.readHumidity();

  //initializing the SHT31 sensor
Sensor.Begin();
Sensor.UpdateData();
TEMP = Sensor.GetTemperature(); 
 HUM = Sensor.GetRelHumidity();

  //Initialize DS3231
Serial.println("Initialize DS3231");

   // setup for the RTC
  while(!Serial); 
  delay(1000);
 if(! rtc.begin()) {
      Serial.println("Couldn't find RTC");
      while (1);
    }
    else {
      // following line sets the RTC to the date & time this sketch was compiled
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

//initializing SD card
     sdSPI.begin(SDCARD_CLK, SDCARD_MISO, SDCARD_MOSI, SDCARD_SS);
    if (!SD.begin((33), sdSPI)) {
        sdOK = false;
        Serial.println("Card Mount Failed");
    } else {
        sdOK = true;
        Serial.println("SDcard initialized!!"); 
    }
   
  File file = SD.open("/data.txt");
  if(!file) {
    Serial.println("File doens't exist");
    Serial.println("Creating file...");
    writeFile(SD, "/data.txt", "dataMessage \r\n");
  }
  else {
    Serial.println("File already exists");  
  }
  file.close();
  
   display.init(115200,true,50,false);
   
   delay(1000);

  Read_TempHum();
  gettimeStamp();
  logSDCard();
  displayReadings();
  
 delay(2000);
 display.hibernate();

  // increasing the counter for the next data readings

  sensor_data++;
  
    Serial.println("Sensor data logged successfully! Going to sleep");

// ESP32 going to sleep for the amount of time you decided
   esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(3000);

  esp_deep_sleep_start(); 
}

void loop() {
}

My problem is just appending new data from sensors in the file to be saved on the SD card.
Maybe you could suggest some solution for my poroblem
Thanks again for your help and your patience
Bruno
PS I've changed my user name because I encountered some problems with two-step authentication now requested when accessing Arduino forum

I have tested part of your sketch today, and I think you're right: the issue is not related to the SD library bug I mentioned before.


As I understand, your wiring is:

SD CARD ESP32
SS 33
CLK 25
MOSI 26
MISO 27
Display ESP32
BUSY 15
RES 2
DC 0
CS 5
SCL (CLK) ?
SDA (MOSI) ?

I am assuming that SCL shares Pin 25 with SD Card CLK,
and that SDA shared Pin 26 with SD Card MOSI


Here's what I think is happening:

Line 13: You create an instance of the SPI class.

Line 241: You begin SPI using this instance. You specify custom pins, including the SS pin for the SD Card.

Line 242: You call SD.begin(), again specifying the SS pin.

Line 261: You call display.init(), after having used the SD card. Problems begin to appear.

You are using multiple devices on the same SPI. The SS / CS pins make this possible. Devices ignore all SPI data unless their CS pin is LOW. This way, they take turns.

When you begin to use SPI at line 241, you have not yet called display.init().
The display's CS pin has not yet been explicitly set HIGH, to ignore the SD Card data.
My theory is this is causing a miscommunication, with both devices trying to make sense of each other's signals.


There are a number of ways that you could address this. I would suggest making only one call to display.init(), and to avoid creating an instance of SPIClass altogether.

Along the lines of:

#define PIN_CLK 25
#define PIN_MISO 27
#define PIN_MOSI 26

#define PIN_CS_CARD 33

#define PIN_CS_DISPLAY 5
#define PIN_DC 0
#define PIN_RST 2
#define PIN_BUSY 15

// Create display instance
GxEPD2_3C<GxEPD2_213_Z98c, GxEPD2_213_Z98c::HEIGHT> display(GxEPD2_213_Z98c(PIN_CS_DISPLAY, PIN_DC, PIN_RST, PIN_BUSY));  // GDEY0213Z98 122x250, SSD1680


void setup() {
  // Begin SPI - no need to set SS here.
  SPI.begin(PIN_CLK, PIN_MISO, PIN_MOSI);

  // Initializing Display
  display.init(115200, true, 50, false);

  // Initializing SD Card
  if (!SD.begin((PIN_CS_CARD), sdSPI)) { /* etc */ }
}

Pardon me,
In the example code above, I incorrectly wrote:

In this example, sdSPI no longer exists. I meant to write:

 // Initializing SD Card
  if (!SD.begin(PIN_CS_CARD) ) { /* etc */ }

Hi,
really a big thanks for your help and spending your time for my coding problems.
I really appreciate your efforts.
I followed your advice and I changed the code as per your suggestions

#include <Wire.h>

#include "FS.h"
#include <SD.h> // for the SD card

#define PIN_CLK 25
#define PIN_MISO 27
#define PIN_MOSI 26

#define PIN_CS_CARD 33

#define PIN_CS_DISPLAY 5
#define PIN_DC 0
#define PIN_RST 2
#define PIN_BUSY 15

bool sdOK = false;

#include <RTClib.h> // for the RTC
RTC_DS3231 rtc; 

//libraries for e-paper display
#define ENABLE_GxEPD2_GFX 0

#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <Fonts/FreeMonoBold9pt7b.h>

// ESP32 SS=5,SCL(SCK)=18,SDA(MOSI)=23,BUSY=15,RST=2,DC=0 wiring to ESP32 for E_paper as requested by manufacturer

// 2.13'' EPD Module

GxEPD2_3C<GxEPD2_213_Z98c, GxEPD2_213_Z98c::HEIGHT> display(GxEPD2_213_Z98c(PIN_CS_DISPLAY, PIN_DC, PIN_RST, PIN_BUSY));
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C


//library for SHT3x sensor
#include <SHT3x.h>
SHT3x Sensor; 
 
// variables to store data from sensors ( float type because they are value with a decimal part)

   float temp;
   float hum;
   float TEMP;
   float HUM;
    
String timeStamp;

// variables to define sleep time; the first multiplies the value to get seconds from microseconds; the second says the sleep time in seconds (1200 = 30 minutes)
uint64_t uS_TO_S_FACTOR = 1000000; 
uint64_t TIME_TO_SLEEP = 180; //sleep for 5 minutes

String dataMessage;

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

// setting a counter for data readings; it will increase every time data from sensors are collected
RTC_DATA_ATTR int sensor_data = 0;

// initializing string data to save data collected from sensors
String Data;
#define sensor_data(temp,hum,TEMP,HUM);

void gettimeStamp() {
    DateTime now = rtc.now();

char timeStamp[9];
 sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());

  Serial.println(timeStamp);
}

void Read_TempHum()
{  
    TEMP = Sensor.GetTemperature();
     HUM = Sensor.GetRelHumidity();

    DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
  Serial.println(timeStamp);
  Serial.print("Temp_BME280 = ");
  Serial.print(temp);
  Serial.println(" C");
  Serial.print("Hum_BME280 = ");
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temp_SHT3x = ");
  Serial.print(TEMP);
  Serial.println(" C");
  Serial.print("Hum_SHT3X = ");
  Serial.print(HUM);
  Serial.println(" %");
}

void logSDCard() {
   DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
dataMessage = String(timeStamp) + "\r\n";
dataMessage =  String(sensor_data) + ","+String(timeStamp) + "," + 
               String(temp) + "," + String(hum)+ "," + String(TEMP) + "," + String(HUM) +"\r\n";
  Serial.print("Save data: ");
  Serial.println(dataMessage);
  appendFile(SD, "/data.txt", dataMessage.c_str());
}

// Write to the SD card (DON'T MODIFY THIS FUNCTION)
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);
  File file = fs.open(path, FILE_WRITE);
  if(!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}

// Append data to the SD card (DON'T MODIFY THIS FUNCTION)
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);
  File file = fs.open(path, FILE_APPEND);
  if(!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void displayReadings() {
  DateTime now = rtc.now();

char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second()); 
display.init(115200,true,50,false);  
display.setRotation(1);
display.setFont(&FreeMonoBold9pt7b);
  display.setTextColor(GxEPD_BLACK);
  display.setFullWindow();
  display.firstPage();
  do
  {
  display.fillScreen(GxEPD_WHITE);
  display.setCursor(0,10); 
     display.print("temp_BME= ");
    display.print(temp);
    display.println(" C");
    display.setCursor(0,30);
    display.print("temp_SHT= ");
    display.print(TEMP);
    display.println(" C");
    display.setCursor(0,50);
    display.print("hum_BME= ");
    display.print(hum);
    display.println(" %");
    display.setCursor(0,70);
    display.print("hum_SHT= ");
    display.print(HUM); 
    display.println(" %");
    display.setCursor(0,90);
    //display.setTextColor(GxEPD_RED);
    display.print("sleeping for 5 min");
    display.setCursor(0,110);
    display.print("# ");
    display.print(sensor_data);
    display.print("    ");
    display.print(timeStamp);
  }
    while(display.nextPage());
    delay(100);

      }

void setup() {
   //initializing Serial monitor
  Serial.begin(115200);
    while(!Serial);
  delay(1000);
 SPI.begin(PIN_CLK, PIN_MISO, PIN_MOSI);

  display.init(115200,true,50,false);
   if (!bme.begin(0x76)) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  } 

bme.begin(0x76);  

 temp = bme.readTemperature();
 hum= bme.readHumidity();

  //initializing the SHT31 sensor
Sensor.Begin();
Sensor.UpdateData();
TEMP = Sensor.GetTemperature(); 
 HUM = Sensor.GetRelHumidity();

  //Initialize DS3231
Serial.println("Initialize DS3231");

   // setup for the RTC
  while(!Serial); 
  delay(1000);
 if(! rtc.begin()) {
      Serial.println("Couldn't find RTC");
      while (1);
    }
    else {
      // following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }

//initializing SD card
        
      if (!SD.begin(PIN_CS_CARD) ) {
        sdOK = false;
        Serial.println("Card Mount Failed");
    } else {
        sdOK = true;
        Serial.println("SDcard initialized!!"); 
    }
   
  File file = SD.open("/data.txt");
  if(!file) {
    Serial.println("File doens't exist");
    Serial.println("Creating file...");
    writeFile(SD, "/data.txt", "dataMessage \r\n");
  }
  else {
    Serial.println("File already exists");  
  }
  file.close();
  
  
   
   delay(1000);

  Read_TempHum();
  gettimeStamp();
  logSDCard();
  displayReadings();
  
 delay(2000);
 display.hibernate();

  // increasing the counter for the next data readings

  sensor_data++;
  
    Serial.println("Sensor data logged successfully! Going to sleep");

// ESP32 going to sleep for the amount of time you decided
   esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(3000);

  esp_deep_sleep_start(); 
}

void loop() {
}

`Now, it works fine for SD card properly appending the data but the EInk display is no longer refreshing and updating.
In the serial monitor you can see that values from EInk _(PowerON: _UpdateFull -PowerOff) are very low
SD_WORKING_BUT_Eink_display_NOT_REFRESHING
while with the same hardware when using the code that allows for proper display refreshing/updating BUT NOT appending the data to the file the values appearing in the serial monitor are quite different
EInk_display_refreshing_BUT_SD_NOT_working
I think that you're really right about some strange interference between SDcard module and EInk display both working on SPI; by the way the SCL of the display is pin 18 and the SDA is pin 23 so apparently there is no pin shared between the SD and the display.
I tried also again my code on Lilygo T5-Eink display which is a board with integrated E-Ink display and a slot for SD card so it should work without any problem but it turned out that on 24 runs performed in succession , in 14 cases there was an error in appending the file but in the other 10 there was "Message appended". However in the file there were NO data.
So I'm really confused

Please try with SCL connected to 25, and SDA connected to 26. That is to say, sharing with the SD card.

Both the card and the display are using the same SPI (VSPI). When you call SPI.begin() here, you are customizing PIN_CLK, PIN_MISO, and PIN_MOSI for all devices using VSPI.

Devices share MOSI, MISO and CLK lines (wired in parallel). The card and the display should share pins.

It is possible to use both VSPI and HSPI, using a different SPI for each device, but there is no real advantage to it in this case.

Hi,
IT WORKS!
Thanks for your info on SPI ; I must confess that I've often used devices connected through I2C but very few with SPI and I mistakenly thought that different SPI devices should use different SPIs ( as shown by some examples and also by the presence of VSPI and HSPI).
As soon as I followed the sharing of pins as you suggested my problem was solved.
I understood that my amateur approach to this complex world must stimulate me to study the basics of programming more and better; I was really lucky to meet a person like you who was generous and available even for beginners in trouble and this is not a usual experience.
Thanks again
Bruno

Not a problem! Back in the heyday of Arduino Uno, SPI was pretty intuitive: only one SPI, and the pins were fixed in place. Nowadays with all this fancy ESP32 stuff, it's a lot less obvious to anyone just starting out.

Good to hear that everything's working! Best of luck with your project.

Hi,
sorry for bothering you again but I'm still stuck with a problem similar to that you solved a week ago.
As you probably remember thanks to your suggestions and explanations I was able to build a datalogger for recording on SD card data from two I2C sensor while displaying them on an E-Ink display ( the code is running on ESP32 and uses deep sleep to save power).

I tried to make the project more"compact" by using a Lilygo board based on ESP32 that has an E-Ink display and a SD card slot integrated.
I'm enclosing the pinout of the model I'm trying to use
T5-V2_16_600x600

As you can see the pins for Eink display are different from those used by SD card slot and as a result I'm not able to use the suggestion that you gave me when the Sd card module was separated.

I googled in oderr to find examples or solutions but I found nothing useful and the examples on the Lilygo Github are really too complicated for me.
I opened an issue on Lilygo Github
[SD card not working when using T5_V2.3.1_213]](SD card not working when using T5_V2.3.1_213] · Issue #46 · Xinyuan-LilyGO/LilyGo-T5-Epaper-Series · GitHub)

where you can also find my code that - according to lewishe from Lilygo - should work
but I didn't get any solution and, as you can see, the same problem was present in another issue from another forumer on October 22 and is apparently unsolved.

I'd be really very grateful if you could give me your opinion on this issue that is really above my forces.
Thanks for your help
Bruno

Hi,
I forgot to remark that this time the Eink display works properly but the SDcard not as you can see from serial monitor

serial_monitor
Thx again

Hi again,
I should probably mention that the community strongly prefers a new post when changing topic, but nobody seems to have noticed so we might get away with it.

I see in your Github issue, you were aiming to confirm that there is no hardware damage, by using a pre-built firmware image. The latest reply suggests that you were attempting to use the wrong image, suggesting instead T5_V213_BW_GxGDEM0213B74.bin. Did you end up testing this one?

I think it may not be important to focus on the pre-built firmware at this stage. I do not suspect that you have a hardware issue.


On the LilyGo, notice that the MOSI, MISO and CLK pins are different for the display and the card.

This is different than the wiring you were using with your last board, where the SPI devices were sharing pins:

Last time, you changed wiring in order to share pins on one SPI. This time, the wiring is unchangeable, set by LilyGo. The best option here is probably to use both of the SPIs: VSPI and HSPI.

The LilyGo wiring seems to suggest that display would use VSPI, and card would use HSPI (see default SPI pins here, if interested).


In the code you posted to the github issue:

Line 34: By passing SPI, you are telling display to use VSPI, the default (I believe?)

GxIO_Class io(SPI, /*CS=5*/ ELINK_SS, /*DC=*/ ELINK_DC, /*RST=*/ ELINK_RESET);

Line 37: You create a new SPI instance, for the card, also attempting to use VSPI.

SPIClass sdSPI(VSPI);

The first thing I would suggest is to try SPIClass sdSPI(HSPI); instead.
I haven't used HSPI before so I could be easily be wrong, but give it a go and see if anything changes.

Hi,
thx for your prompt answer and sorry for my having involuntarily transgressed the forum rules but I really thought that it was the same topic.
However, I followed your suggestion and I used
SPIClass sdSPI(HSPI);
defining SDcard_SS as 13, SDCARD_CLK as 14, SDCARD_MOSI as 15 and SDCARD_MISO as 2 according to the pinout of the Lilygo T5 Eink display board.
Is this approach correct ? I doubt no since I got this error

The bad news are that I haven't the slightest idea how to fix it...
The good news are that It's very comforting to me to know that if this Lilygo board fails I'm still able to use Eink display and SD card separated from the ESP32 thanks to your previous help.

Hmm, this sort of error seems to be something more fundamental than bad code.

Are you able to successfully upload an example sketch, like blink.ino? (File -> Examples)
Just as an experiment, would you try uploading with the SD card and all extra wiring removed?

If you cannot get any code to upload from Arduino IDE, I would seriously suggest going back and trying to get that pre-built github example to run.

Please do let me know the results of uploading a basic example sketch, with no SD card and additional wiring. This is all a bit beyond me, and I don't have the same hardware with me to investigate, unfortunately.

Hi,
I uploaded without problems the blink.ino example in three different conditions

  1. with SD card and all wiring to RTC and to two I2C sensors connected
  2. then removing in a progressive way - one at a time - all the items connected except the LED
  3. with everything removed and with just the LED
    The LED has been always working fine all the time
    This seems to me fairly reassuring on the hardware integrity.
    So probably it's again some strange interference between my code and the wiring one has to use for display and SD card set by default by this board.

As a final remark I retried to upload the code that had given before the error and - surprise ! - the upload was successful ( not just once but twice) even if there was in the serial monitor the usual message Failed to open file for appending

I'm enclosing the code that had given the error just in case I've made some stupid mistake
Thx for your patience

#include <SD.h>
#include <FS.h>

#include <SPI.h> //for the SD card 
#include <Wire.h>


#include <RTClib.h> // for the RTC
RTC_DS3231 rtc; 

// include library, include base class, make path known
#include <GxFont_GFX.h>

#include <GxEPD2.h>
#include <GxGDEM0213B74/GxGDEM0213B74.h>  // MY TEST

#include <Fonts/FreeMonoBold9pt7b.h>

#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>

#define SPI_MOSI 23
#define SPI_MISO -1
#define SPI_CLK 18
#define ELINK_SS 5
#define ELINK_BUSY 4
#define ELINK_RESET 16
#define ELINK_DC 17

#define SDCARD_SS 13
#define SDCARD_CLK 14
#define SDCARD_MOSI 15
#define SDCARD_MISO 2


GxIO_Class io(SPI, /*CS=5*/ ELINK_SS, /*DC=*/ ELINK_DC, /*RST=*/ ELINK_RESET);
GxEPD_Class display(io, /*RST=*/ ELINK_RESET, /*BUSY=*/ ELINK_BUSY);

SPIClass sdSPI(HSPI);
const char *skuNum = "SKU:H239";
bool sdOK = false;


#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 bme; // I2C

#include <SHT3x.h>
SHT3x Sensor; 

// variables to store data from sensors ( float type because they are value with a decimal part)

  float TEMP;
  float HUM;
  float temp;
  float hum;

  String timeStamp;

  String Data;

// variables to define sleep time; the first multiplies the value to get seconds from microseconds; the second says the sleep time in seconds (1200 = 30 minutes)
uint64_t uS_TO_S_FACTOR = 1000000; 
uint64_t TIME_TO_SLEEP = 180; //sleep for 3 minutes

String dataMessage;

void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch(wakeup_reason)
  {
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}

// setting a counter for data readings; it will increase every time data from sensors are collected
RTC_DATA_ATTR int sensor_data = 0;

#define sensor_data(temp,hum,TEMP,HUM);

   void gettimeStamp() {
    DateTime now = rtc.now();

char timeStamp[9];
 sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());

  Serial.println(timeStamp);
} 

   void Read_TempHum()
{  
  Serial.print("Temp_BME280 = ");
  Serial.print(temp);
  Serial.println(" C");
  Serial.print("Hum_BME280 = ");
  Serial.print(hum);
  Serial.println(" %");
  Serial.print("Temp_SHT3x = ");
  Serial.print(TEMP);
  Serial.println(" C");
  Serial.print("Hum_SHT3X = ");
  Serial.print(HUM);
  Serial.println(" %");
  Serial.print(timeStamp);
}

void displayReadings(){
   DateTime now = rtc.now();
  char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());
  display.setCursor(0,0);
   display.setTextColor(GxEPD_BLACK);
  display.setCursor(0,20);
    display.print("temp_BME = ");
    display.print(temp);
    display.println(" C");
    display.print("temp_SHT = ");
    display.print(TEMP);
    display.println(" C");
    display.print("hum_BME = ");
    display.print(hum);
    display.println(" %");
    display.print("hum_SHT = ");
    display.print(HUM);
    display.println(" %");
    display.setCursor(0,100);
    display.print(timeStamp);
    display.setCursor(100,100);
    display.print("Run n  ");
    display.println(sensor_data);
    display.setCursor(0,115);
    display.print("Now sleep for 3 min");
    
    display.update();
}


   void logSDCard() {
   DateTime now = rtc.now();
char timeStamp[9];
  sprintf(timeStamp, "%02i:%02i:%02i", now.hour(), now.minute(), now.second());

 dataMessage =  String(sensor_data) + ";"+String(timeStamp) + ";" + 
               String(temp) + ";" + String(hum)+ ";" + String(TEMP) + ";" + String(HUM) +"\r\n";
  Serial.print("Save data: ");
  Serial.println(dataMessage);
  appendFile(SD, "/data.txt", dataMessage.c_str());
}

// Write to the SD card (DON'T MODIFY THIS FUNCTION)
void writeFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Writing file: %s\n", path);
  File file = fs.open(path, FILE_WRITE);
  if(!file) {
    Serial.println("Failed to open file for writing");
    return;
  }
  if(file.print(message)) {
    Serial.println("File written");
  } else {
    Serial.println("Write failed");
  }
  file.close();
}
// Append data to the SD card (DON'T MODIFY THIS FUNCTION)
void appendFile(fs::FS &fs, const char * path, const char * message) {
  Serial.printf("Appending to file: %s\n", path);
  File file = fs.open(path, FILE_APPEND);
  if(!file) {
    Serial.println("Failed to open file for appending");
    return;
  }
  if(file.print(message)) {
    Serial.println("Message appended");
  } else {
    Serial.println("Append failed");
  }
  file.close();
}

void setup()
{
    Serial.begin(115200);
    while(!Serial);
    delay(100);

 // checking the BME280 connections and initializing the sensor
      bool status;
  status = bme.begin(0x76);  
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
  //initializing SD card
sdSPI.begin(SDCARD_CLK, SDCARD_MISO, SDCARD_MOSI, SDCARD_SS);
if (!SD.begin(SDCARD_SS)) {
sdOK = false;
} else {
sdOK = true;
}
     delay(1500);

 //initializing the SHT31 sensor
  Sensor.Begin();
Sensor.UpdateData();
TEMP = Sensor.GetTemperature(); 
HUM = Sensor.GetRelHumidity();

  delay(100);
  // setup for the RTC
   if(! rtc.begin()) {
      Serial.println("Couldn't find RTC");
      while (1);
    }
    else {
      // following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    }
  
   temp = bme.readTemperature();  
   hum = bme.readHumidity();
 SPI.begin(SPI_CLK, SPI_MISO, SPI_MOSI, ELINK_SS);
    display.init(); // enable diagnostic output on Serial
    display.setRotation(1);
    display.fillScreen(GxEPD_WHITE);
    display.setTextColor(GxEPD_BLACK);
    display.setFont(&FreeMonoBold9pt7b);
    display.setCursor(0, 0);
   delay(1500);
    
   display.update();

       Read_TempHum();
       displayReadings();
       logSDCard();
  // increasing the counter for the next data readings

  sensor_data++;
    
  Serial.println("Sensor data logged successfully! Going to sleep");

// ESP32 going to sleep for the amount of time you decided
   esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
  delay(5000);
  esp_deep_sleep_start(); 

   delay(3000);
    esp_deep_sleep_start();
  }

void loop()
{}


I did notice something similar when testing the code out this afternoon. It seems to happen while uploading new code, when existing code has previously caused a crash.


I suspect that the issue is with the SPI code.

Line 36: the default SPI (VSPI) is passed.

GxIO_Class io(SPI, /*CS=5*/ ELINK_SS, /*DC=*/ ELINK_DC, /*RST=*/ ELINK_RESET);

This should be acceptable, however for the sake of clarity, I suggest explicitly using VSPI. (Matching the style of Line 39)

SPIClass displaySPI(VSPI);
GxIO_Class io(displaySPI, /*CS=5*/ ELINK_SS, /*DC=*/ELINK_DC, /*RST=*/ELINK_RESET);

Line 205: sdSPI (HSPI) begins

sdSPI.begin(SDCARD_CLK, SDCARD_MISO, SDCARD_MOSI, SDCARD_SS);

I would not pass SS here. The SD library takes care of the SS pin, pulling it LOW when the card is accessed.

sdSPI.begin(SDCARD_CLK, SDCARD_MISO, SDCARD_MOSI);

Line 206: SD begins

if (!SD.begin(SDCARD_SS)) {

Need to specify that SD card is configured to use the HSPI, rather than VSPI (default). This might be the main issue.

if (!SD.begin(SDCARD_SS, sdSPI)) {

Line 232: displaySPI (VSPI) begins

SPI.begin(SPI_CLK, SPI_MISO, SPI_MOSI, ELINK_SS);

I am unsure if GxEPD automatically starts SPI for you. In any case, this line doesn't seem to hurt. SPI should be changed to displaySPI (from earlier). I would also omit the SS here .

displaySPI.begin(SPI_CLK, SPI_MISO, SPI_MOSI);

Let me know if you have any luck with these changes!

Dear friend,
I'm really happy to tell you that you've hit the mark again !
With your new suggestions the code now works correctly, refreshing the display

AND saving the data on SD card (graph from a brief test session)

So my project can be finished.

If it were not for your patient help and the precious time you spent meticulously checking my code I would never have achieved this result.
Thanks again for your help
You are living proof that the good Samaritan sometimes really exists...
Bruno
PS I will inform the Lilygo GitHub people that my problem was not related to the HW but to the SW and that my code judged by them to be working, actually contained more than one bug and that only the help of a forumer solved the issue

1 Like

Great to see it working. I can see that the data as a graph will be valuable information. All the best!

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