SD Card Read/Write Not working on external power supply

Hi all,

I have a bit more than basic knowledge of Arduino code and hardware, with the use of AI I have created code and wired a data logger to record when an external signal goes high and record the time, date and then record the time, date and duration the signal was high when it goes off.

The code works when connected to the USB cable and both writes to the serial port and txt file, however when I connect to external power supply (9V 1.66A) it only records the high signal time and then nothing else.

I am using the 5V and 1 ground pin for the SD reader and 3.3V pin and the other ground pin for the RTC

I have read about level shifters, however this is above my knowledge and would appreciate some assistance. I have also tried on a Mega 2560 board however could not get the SD Card reader to initialise.

Thanks in advance,

Dave

This are the components,
Board - DFRDUINO UNO V3.0 ATMEGA328P -https://www.digikey.com.au/en/products/detail/dfrobot/DFR0216/6579366

SD Card - SD Card Data Logging Module MakerBotics https://www.makerstore.com.au/product/mb-elc-sdc-mod/?srsltid=AfmBOooHowTN-RKtIg--qi_jJW-SQ26yaNatK1H6cvzGwdvUi0LE4uqO

DS3231 RTC Module – MakerBotics - https://www.makerstore.com.au/product/mb-elc-rtc-ds3231-mod/

Code Below:

#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"

RTC_DS3231 rtc;
const int chipSelect = 10; // SD card CS pin
const int signalPin = A0;  // Analog pin where the signal is connected
const float voltageThreshold = 2.5; // Minimum voltage threshold to consider the signal as high
bool signalState = LOW;
bool lastSignalState = LOW;
DateTime signalHighTime;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50; // 50 milliseconds debounce delay

void setup() {
  Serial.begin(9600);
  if (!Serial) {
    delay(5000); // Give time for other setup tasks without blocking indefinitely
  }

  Serial.print("Initializing SD card...");

  pinMode(10, OUTPUT); // Ensure SS pin is set as output for Arduino Uno
  delay(1000); // Add a delay before initializing the SD card

  if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");

  if (!rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, setting the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  pinMode(signalPin, INPUT);
}

void loop() {
  float voltage = analogRead(signalPin) * (5.0 / 1023.0); // Convert analog reading to voltage
  bool reading = (voltage >= voltageThreshold);

  if (reading != lastSignalState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != signalState) {
      signalState = reading;

      if (signalState == HIGH) {
        signalHighTime = rtc.now();
        logSignal("HIGH", signalHighTime);
      } else {
        DateTime signalLowTime = rtc.now();
        logSignal("LOW", signalLowTime);
        logDuration(signalHighTime, signalLowTime);
      }
    }
  }

  lastSignalState = reading;
}

void logSignal(const char* state, DateTime time) {
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  if (dataFile) {
    String logEntry = String(state) + " " + formatWithLeadingZero(time.day()) + "/" + formatWithLeadingZero(time.month()) + "/" + String(time.year()) + " " + formatWithLeadingZero(time.hour()) + ":" + formatWithLeadingZero(time.minute()) + ":" + formatWithLeadingZero(time.second());
    dataFile.println(logEntry);
    dataFile.flush(); // Ensure data is written to the file
    dataFile.close();
    Serial.println(logEntry);
  } else {
    Serial.println("Error opening datalog.txt");
  }
}

void logDuration(DateTime start, DateTime end) {
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  if (dataFile) {
    TimeSpan duration = end - start;
    String logEntry = "Duration: " + formatWithLeadingZero(start.day()) + "/" + formatWithLeadingZero(start.month()) + "/" + String(start.year()) + " " + formatWithLeadingZero(start.hour()) + ":" + formatWithLeadingZero(start.minute()) + ":" + formatWithLeadingZero(start.second()) + " - " + String(duration.totalseconds()) + " seconds";
    dataFile.println(logEntry);
    dataFile.flush(); // Ensure data is written to the file
    dataFile.close();
    Serial.println(logEntry);
  } else {
    Serial.println("Error opening datalog.txt");
  }
}

String formatWithLeadingZero(int number) {
  if (number < 10) {
    return "0" + String(number);
  } else {
    return String(number);
  }
}

That SD module is the wrong kind to use with a 5V Arduino like the Uno or Mega 2560. SD cards are 3.3V devices. The module does have a 3.3V regulator to provide the proper power to the card. But the Arudino will be sending 5V signals on MOSI, SCK and CS to the 3.3V card. That's not good for the card, and probably exceeds the absolute maximum spec for voltage applied to any pin.

I don't think anyone makes a full size SD module with level shifting. At least I can't find one. I have a possible modification to the card that could make it work with 5V systems if you're interested. It involves cutting three traces and soldering in three diodes.

The other alternative is to switch to a microSD card. Those modules do have level shifting. The one Adafruit sells is good, but expensive.

But other than that I don't know why it's not working at all on the external power supply. It's possible that the Uno's 5V regulator is producing a bit higher voltage than USB, and that's pushing the SD card over the edge on those three lines. But that's just a guess. I don't think the Serial.print instructions care that there's nobody listening. They are just sent out.

Why are you testing if an SD card works in such a large code?

SD Cards works with 3.3V, as stated before. You might need a module with level shifter (micro sd modules usually) or another board, suchs as any esp32.

Get a level shifter module for the data lines, I have a few, some are bi-directional and accommodate as many as 8 pins. You still need 3.3V and 5V.
If the 9V is a 9V battery, get something else, they are not a good choice.

The RTC you specify is HIGHLY flawed and is not a proper DS3231, it has a bunch of extra stuff. Look for a Chronodot, or get a DS3231 chip from AE as long as you are comfortable with SMD. I use interposer boards for the DS3231 chips but also use a lot of Chronodots.

What is the voltage on the Uno's 5V pin when it is powered by USB, and when it is powered from the external 9V supply?

I would not recommend using a bidirectional level shifter on SPI. The lines are not bidirectional, as they are with I2C. And you don't need to shift the MISO line because the card's 3.3V output will be recognized as high by the Arduino. The microSD adapters typically use the 74LVC125A, which is just a 3.3V non-inverting buffer with 5V-tolerant inputs.

Also, I'm not sure it matters, and it's not the cause of the problem, but I think technically the RTC should be powered with 5V if it's communicating with a 5V Arduino. However, if you do that, you'll need to disable the "charging" circuit on the module if your backup cell is a normal CR2032.

https://www.onetransistor.eu/2019/07/zs042-ds3231-battery-charging-circuit.html

Hi all,
Thanks for the feedback and ideas, I have ordered a micro SD card and am waiting for it to arrive.

For some context on the project, I want to monitor when a remote solar pump turns on and off and record the time in the text file, so time accuracy is not super critical. Just a reasonably accurate start and stop time to check the system for any itamitant start commands as the pump control system is set to only turn on when 500 litres is needed in the tank. I will let it run for a few days and then go and get the SD card.

Ideally I want to get the point where I have a system that can send me alerts or I can look at the daily txt file with the run times to ensure the system is running according to plan. I'm thinking this might be a raspberry Pi setup.

I will report on how I go with the new SD card reader.

Cheers,

Dave

If you have nothing better to do while you're waiting for the microSD module, and if you have a supply of 1N4148 diodes, you could try this "fix" for the full-size card module. Solder in three diodes, cut three traces.

Hi all,

Quick update the micro SD card was the solution. I purchased the DFRobot MicroSD card module and it is working great on my Uno both on USB power and a 9 V DC wall power inverter.

Thanks all for your assistance.

Cheers,

Dave

Why don't you ask AI why it doesn't work?

There are SD card modules with a level shifter/tri-state buffer. Note the 74LVC125 on this.

This link points to a micro sd card module, which are available both on 5V and 3.3V version. What @ShermanP pointed is that perhaps a full sized SD card reader is not available in 5V .

Then it won't work. I found one, but at almost $10, I wouldn't buy it.
Without the 74LVC125, it isn't really SPI. It becomes a proprietary bus supporting only the SD card. The SD card itself will not release the MISO line.

Please elaborate, with sources to support this.

The ZS-042 for one thing assumes a rechargeable coin cell so if you insert a NON rechargeable cell you will get a nasty surprise.
Once I learn something I dpn't keep all the links and references since I have been doing this for nigh on 60 years and the piles of 'stuff' would overwhelm me and my computers. This one is however easy. Warning, you need to follow many links in many directions to get the entire 'flavour'. Some hints are traces need to be cut, pull ups need to be removbed and new pullups soldered. So much easier to just buy a Chronodot or a raw DS3231 chip. https://thecavepearlproject.org

That model nr wasn't the same as in the link OP provided. Expect when zooming in... You're right, there are info, and at least one thread in this forum that confirms this. So there's a misunderstanding, I'm sorry.

When I was researching I found lots of links (not on this forum) and I was shocked that everyone was calling the ZS-042 a DS32xx (xx can be 20 to 31 or more, just enhancements) There is a DS3231 on the ZS-042 but there is also EEPROM, a recharge circuit and issues around pullups. Have a close look at the ZS-042 and a Chronodot V2.0, 2.1, 3.0 to see the differences. I will try to add a picture of a ZS-042 undergoing required surgery if I can find one.

I noticed, not sure why one would want that when getting a RTC. And for the rest of the mess.. it's a bit messy :wink:

The latest Chronodot V3.0 has added an EEPROM. I guess there are enough use cases that require data to be remembered across a deep sleep to warrant it. At least with the Chronodot it's optional. Here is a video showing the surgery needed for a ZS-042 https://youtu.be/rG50U6bQhYo?si=FQBSky4tANiaaD0Z and here is a diagram showing what traces need cutting, resistor packs removed and more.

I've bought this Chronodot clone in the past:

https://www.ebay.com/itm/401482226870?var=671154997502

In the picture it's a "Chronodor". :slight_smile:

It actually had a genuine DS3231SN on it. It doesn't have pullup resistors installed, but through-holes are provided so you can easily add them. The only possible downside may be that this uses a smaller coin cell than the ZS-042. It's a CR1220 vs the larger CR2032, with about 1/4 the capacity. But that shouldn't matter if the coin cell is only for backup. It appears the genuine Chronodot uses a CR1632, which would have about 1/2 the capacity of a CR2032.