SD Card module fails to initialize after a random amount of time; Fixes itself temporarily once ground pin is removed and reconnected

Hi, Im using this generic SD Card module
https://shopee.com.my/Arduino-SPI-ICSP-interface-Micro-SD-Card-Adapter-Reader-Module-i.96013540.4238884352?sp_atk=44e4ea6d-7dc2-4649-bd36-0815600d301e&xptdk=44e4ea6d-7dc2-4649-bd36-0815600d301e

To answer some basic questions:

-It does appear to have a LDO Voltage regulator from 5V to 3.3V
-It does have a logic level shifter for the pins aswell
-This SDCard module is connected directly, by 10cm approx jumper wires to an ESP32 expansion baseboard, the link to this baseboard is: NodeMCU ESP32 with Expansion Board

The other things connected to my esp32 system is:

  • A DS3231 rtc clock

  • A SHT31 sensor

  • A BH1750 Adafruit sensor

  • The esp32 system is powered via usb from a DFRobot Solar Power Manager DFR0559: Solar_Power_Manager_5V_SKU__DFR0559-DFRobot

  • A 8800mAH rechargable battery is connected to the power manager

  • A 400mA 6V solar panel is connected to the power manager ( A INA219 current sensor is between the solar panel and power manager to log current output of solarpanel)

A powerbank is also connected to the power manager as supplementary input power. Only the sensors are connected to the 5V output and ground of the power manager. The Ground of the power manager is the connected to the ground of the esp32. The RTC and SDCard module are connected directly to the ESP32 expansion board

The Issue:

This system is meant to log data onto the SDcard for use in a project of mine, The issue im encountering currently is that after a random amount of time, seemingly a few hours, the SDCard module simply stops initializing, until the ground pin of the module is reset, or the sdcard is reinserted.

To summarize what my code does:

  • it first setups all the sensors, rtc, and sdcard, then it logs the data ,prints to serial monitor,
  • then goes into deep sleep mode using ESP32 library function for approx 10 seconds, after which it runs setup again, and so on and so forth.

Majority of the code is borrowed from the associated libraries, I don't suspect its a coding issue, if the problem is resolved by simply reconnecting ground, but might be possible

Here is the code below:

#include <Wire.h>
#include "Adafruit_SHT31.h"
#include <RtcDS1302.h>
#include <RtcDS3231.h>
#include <BH1750.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_INA219.h>
#include <esp_sleep.h>
#include <esp32-hal-cpu.h>  // Include this header to set the CPU frequency
//POWER MANAGER CONTROL

const int enablePin = 13;
// SD CARD STUFF
const int SDA_PIN = 25;    // GPIO pin for data (SDA)
const int SCL_PIN = 32;    // GPIO pin for clock (SCL)
const int CE_PIN = 33;     // GPIO pin for chip enable (CE)
const int chipSelect = 5;  // SD card module CS pin

// INA219 STUFF
float busvoltage = 0;
float current_mA = 0;
float power_mW = 0;
Adafruit_INA219 ina219;

// CLOCK STUFF
// ThreeWire myWire(SDA_PIN, SCL_PIN, CE_PIN);  // Define ThreeWire object with specified pins
// RtcDS1302<ThreeWire> rtc(myWire);            // Define RTC object with ThreeWire interface
RtcDS3231<TwoWire> Rtc(Wire);

// LIGHT SENSOR STUFF
BH1750 lightMeter;

// TEMPERATURE SENSOR STUFF
Adafruit_SHT31 sht31 = Adafruit_SHT31();

//RETRY VARIABLES
int LightRetry = 0;
int TempRetry = 0;
int PowerRetry = 0;
int SDRetry = 0;

bool sdCardInitialized = false;

void setup() {
  // Set CPU frequency to 80 MHz
  Serial.begin(115200);
  setCpuFrequencyMhz(80);
  pinMode(enablePin, OUTPUT);
  digitalWrite(enablePin, HIGH);
  Wire.begin(21, 22);  // SDA, SCL pins for ESP32

  // Initialize RTC with ThreeWire interface
  Rtc.Begin();
  delay(1000);
  // Initialize the BH1750 sensor
  while (LightRetry < 4) {
    if (!lightMeter.begin()) {
      Serial.println("Error initializing BH1750 sensor");
      LightRetry++;
    } else {
      Serial.println("BH1750 sensor initialized");
      break;
    }
  }
  while (TempRetry < 4) {
    // Initialize the SHT31 sensor
    if (!sht31.begin(0x44)) {  // Set to 0x45 for alternate I2C address
      Serial.println("Couldn't find SHT31");
      TempRetry++;
    } else {
      Serial.println("SHT31 sensor initialized");
      break;
    }
  }
  while (PowerRetry < 4) {
    if (!ina219.begin()) {
      Serial.println("Failed to find INA219 chip");
      PowerRetry++;
    } else {
      Serial.println("INA219 chip initialized");
      // Initialize the INA219 sensor
      ina219.setCalibration_16V_400mA();
      break;
    }
  }
  // Attempt to initialize SD card
  initializeSDCard();
  
}

void loop() {
  digitalWrite(enablePin, HIGH);
  delay(1000);
  // Read light level
  float lux = lightMeter.readLightLevel();
  float t = sht31.readTemperature();
  float h = sht31.readHumidity();
  busvoltage = ina219.getBusVoltage_V();
  current_mA = ina219.getCurrent_mA();
  power_mW = ina219.getPower_mW();

  // Get current time
  RtcDateTime now = Rtc.GetDateTime();
  String currentTime = getTimeString(now);  // Convert time to string

  // Log data to SD card if initialized
  if (sdCardInitialized) {
    File dataFile = SD.open("/data.csv", FILE_APPEND);
    if (dataFile) {
      // Write to file as CSV
      dataFile.print(currentTime);
      dataFile.print(",");
      dataFile.print(lux);
      dataFile.print(",");
      dataFile.print(t);
      dataFile.print(",");
      dataFile.print(h);
      dataFile.print(",");
      dataFile.print(busvoltage);
      dataFile.print(",");
      dataFile.print(current_mA);
      dataFile.print(",");
      dataFile.println(power_mW);

      // Close the file
      dataFile.close();
    } else {
      Serial.println("Error opening file");
      sdCardInitialized = false;  // Try reinitializing the SD card next loop
    }
  } else {
    Serial.println("SD card not initialized, retrying...");
    initializeSDCard();  // Retry initializing the SD card
  }
  Serial.print("Time: ");
  Serial.print(currentTime);
  Serial.print(", Lux: ");
  Serial.print(lux);
  Serial.print(", Temp: ");
  Serial.print(t);
  Serial.print(", Humidity: ");
  Serial.print(h);
  Serial.print(", Bus Voltage: ");
  Serial.print(busvoltage);
  Serial.print(", Current: ");
  Serial.print(current_mA);
  Serial.print(", Power: ");
  Serial.println(power_mW);

  // Put ESP32 to deep sleep for 10 seconds
  digitalWrite(enablePin,LOW);
  Serial.println("Going to sleep...");
  esp_sleep_enable_timer_wakeup(9000000);  // 10 seconds
  esp_deep_sleep_start();
}

void initializeSDCard() {
  Serial.print("Initializing SD card...");
  if (SD.begin(chipSelect)) {
    Serial.println("SD card initialized.");
    sdCardInitialized = true;

    // Check if file exists and create if it doesn't
    if (!SD.exists("/data.csv")) {
      Serial.println("File does not exist. Creating file...");
      File dataFile = SD.open("/data.csv", FILE_WRITE);
      if (dataFile) {
        Serial.println("File created successfully.");
        dataFile.println("Time,Lux,Temp,Humidity,BusVoltage,Current_mA,Power_mW");  // Write header
        dataFile.close();
      } else {
        Serial.println("Error creating file.");
      }
    } else {
      Serial.println("File already exists.");
    }
  } else {
    Serial.println("SD card initialization failed!");
    sdCardInitialized = false;
  }
}

String getTimeString(const RtcDateTime &dt) {
  // Convert RTCDateTime object to string
  char buffer[25];
  sprintf(buffer, "%04u-%02u-%02u %02u:%02u:%02u", dt.Year(), dt.Month(), dt.Day(), dt.Hour(), dt.Minute(), dt.Second());
  return String(buffer);
}

I have a bunch of retry code just incase any of the components might randomly just not work, and it doesn't continue onward, but my SDcard simply makes no sense, I need a third perspective on what might be causing the issue

Just to summarize:

  • The RTC and SDcard module are connected directly to ESP32 expansionboard
  • The I2C wires of the ina219, bh1750 and sht31 are connected via breadboard, their remaining pins are connected to the Solar power manager 5V and GND output, which is turned on and off every 10 seconds in conjunction with the Deep sleep reset of the ESP32, to save power

Can't see it in the link. How about a picture ?

but probably has a 3.3v input as well.

Can't see it in the link. How about a picture ?

It accepts both 3.3V and 5V as input, but I wired it to the 3.3V output of the ESP32 just to be safe

I suspect that it doesn't actually. Can you measure what the voltage regulator puts out when you feed it with 3.3v.

It looks like a lineair regulator like AMS1117 3.3v, but that requires at least 4v to provide 3.3v

Just measure the voltage on C3, i think that is just the main capacitor of the voltage regulator. (confirm this with the module unplugged)

My mistake, the SDcard module has been connected to 5V from the start not 3.3V

Also, ill measure and post the results of the voltage regulator a bit later; my system is currently deployed a bit far away from it for the time being :sweat_smile:

That module, at least for me, doesn't work properly at 3.3V.

It's known that ESP32 when goes to sleep its similar to press restart.

But it is not. Before sleep, close all conections with SD.close, SPI.end, and such commands.
Check every initialization, and then do the oposite before sleep.
Actually, I even call SD.end(); and SPI.end(); before initializing it. Then I call SD.begin() and spi.begin() multiple times with retries to minimize this problem.

bool setup_SPI(int i) {
  bool success = false;
  Serial.print("Init SD | .");
  
  for (int attempt = 0; attempt < maxAttempts; attempt++) {
    SD.end();
    SPI.end();
    spi.begin(SD_CLK, SD_MISO, SD_MOSI, SD_CS);
    SdSpiConfig sdConfig(SD_CS, DEDICATED_SPI, SD_SCK_MHZ(i), &spi);
    if (SD.begin(sdConfig)) {
      Serial.println("SPI CLK = " + String(i) + " MHz SUCCESS!!! ");
      success = true;
      break;
    }
    Serial.println("Retry SPI and SD...");
    delay(100);
  }
  if (!success) return false;
  return true;
}

So for the purposes of my code, calling SD.end() and SPI.end() before the deep sleep command should potentially solve my issue?

one question, I don't use SPI.begin() in my code, I assume SD.begin() calls something similar automatically so calling SPI.end() shouldn't be an issue?

You should have a 2nd set of hardware for testing.

It solved for me.
How to know if it will work for you?

Yes SD.begin() call s SPI.begin(), but i would just make sure that the CS pin of the SD card is 'HIGH'

Add a physical pullup resistor (10K to 3.3v) to the CS pin on the ESP. and explicitly set the CS pin HIGH programmatically before putting the ESP to sleep.