SD Card logging with card replacements

So yes, I have searched and read many threads about this; and I have been through the SdFat source files and documentation many times… here is why I am still posting this:

  • I couldn’t find a simple, clear example of how to log data while supporting card removes/inserts. Lots of instructions of how to do it, but no real sample code
  • I was looking for a solution using SdFat only (I am seriously memory constrained)
  • Many threads are old, and I see several posts from Bill Greinman mentioning updates to improve things and I wasn’t sure what applied and what didn’t anymore

… so I’d like your thoughts about the code below, and whether it could be improved? The goal is to keep the program running (no resets) while the card is occasionally removed & re-inserted. I do understand that corruption could happen if the card is removed while logging, I’ll handle that separately.

I have tested removing / re-inserting the card; and starting w/o a card and inserting it later.

A question I still have: I suspect the **Halt methods may be useful but I am not sure what they do exactly? If I call them every time I detect a failure will the next SD.begin still work?

#include <RTClib.h>
#include <SPI.h>
#include <SdFat.h>

#define SS_PIN 10
#define print2(F,V) if (V < 10) F.print('0'); F.print(V, DEC)

// clock
RTC_DS1307 rtc;

// SD Card
SdFat SD;

uint16_t log_id;
bool sdSetup(bool force = false);

void setup()

void rtcSetup()
  while (! rtc.begin()) {
    Serial.println("RTC not found!");
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running, setting the time");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  else {
    Serial.println("RTC is running");

bool sdSetup(bool force)
  if (force || SD.cardErrorCode()) {
    Serial.println("\nInitializing SD card...");

    if (SD.cardErrorCode()) {
      Serial.print("SD Card init failed! "); SD.errorPrint(&Serial);
  return ! SD.cardErrorCode();

void loop () {

void writeLog()
  SdFile log;
  if (! sdSetup()) {

  if (!, "test.csv", FILE_WRITE)) {
    Serial.print("Could not open file: "); SD.errorPrint(&Serial);

  DateTime now =;

  log.print(log_id); log.print(' ');
  log.print(now.year(), DEC);
  log.print('-'); print2(log, now.month());
  log.print('-'); print2(log,;
  log.print(' '); print2(log, now.hour());
  log.print(':'); print2(log, now.minute());
  log.print(':'); print2(log, now.second());

  bool log_ok = log.close() && ! log.getError();
  if (log_ok) {
    Serial.println("Log written");
  else {
    Serial.print("Could not write log: "); SD.errorPrint(&Serial);