Error feedback

In an attempt to give the user feedback on possible failures, I have tagged each possible point of failure with an error code which I then use later on:

void setup() {
  if (!card.init(SPI_FULL_SPEED, SdChipSelect)) {
    myError = 3;
  }

  if (!volume.init(&card)) {
    myError = 4;
  }

  if (!sd.begin(SdChipSelect, SPI_FULL_SPEED)) {
    myError = 5;
  }
}

Problem is, I don't know when any of them would actually trigger. In the sketch loop, I have this:

  while (myError) {
    if (millis() - lastRun > pause) {
      if (!digitalRead(errorLED)) {
        digitalWrite(errorLED, HIGH);
        pause = 150;
      } else {
        digitalWrite(errorLED, LOW);
        if (myError > 1) {
          cntr++;
          if (cntr >= myError) {
            cntr = 0;
            pause = 750;
          }
        }
      }
      lastRun = millis();
    }
  }

That works. If I manually set the error code, the LED flashes accordingly, continuous or 2 up to 5 times depending on what I set it to. However, in real life, when would any of the codes 3, 4, or 5 trigger?

First test, I didn't insert the card: it errored out with code 5.
Second test I completely removed the uSD from the circuit. It errored out with code 5.
Third test, I only removed the SS connection: it errored out with code 5.
Fourth test, I only removed MOSI: it errored out with code 5.
Fifth test, I only removed the SCK line: it errored out with code 5.

Sooo at what point would it trigger code 3? And would code 4 trigger if the card was formatted in something other than FAT16/32?

You should never have a card or volume object in a sketch that has a SdFat object.

This code:

 if (!card.init(SPI_FULL_SPEED, SdChipSelect)) {
    myError = 3;
  }

  if (!volume.init(&card)) {
    myError = 4;
  }

Should not be in a sketch that has this call:

  if (!sd.begin(SdChipSelect, SPI_FULL_SPEED)) {
    myError = 5;
  }

The sd.begin() call initializes its own internal card and volume object.

The best way to diagnose sd.begin() problems is to use this form:

  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();

Here is a sketch that will print error information for SD card initialization problems.

#include <SdFat.h>
const uint8_t CS_PIN = SS;
SdFat sd;
void setup() {
  Serial.begin(9600);
  if (!sd.begin(CS_PIN)) sd.initErrorHalt();
  Serial.println("begin success");
}
void loop() {}

sd.initErrorHalt() will attempt to print a detailed message about the error. sd.initErrorHalt() calls sd.initErrorPrint() shown below.

void SdFat::initErrorPrint() {
  if (m_card.errorCode()) {
    pstrPrintln(PSTR("Can't access SD card. Do not reformat."));
    if (m_card.errorCode() == SD_CARD_ERROR_CMD0) {
      pstrPrintln(PSTR("No card, wrong chip select pin, or SPI problem?"));
    }
    errorPrint();
  } else if (m_vol.fatType() == 0) {
    pstrPrintln(PSTR("Invalid format, reformat SD."));
  } else if (!m_vwd.isOpen()) {
    pstrPrintln(PSTR("Can't open root directory."));
  } else {
    pstrPrintln(PSTR("No error found."));
  }
}

fat16lib:
You should never have a card or volume object in a sketch that has a SdFat object.

This code:

 if (!card.init(SPI_FULL_SPEED, SdChipSelect)) {

myError = 3;
 }

if (!volume.init(&card)) {
   myError = 4;
 }




Should not be in a sketch that has this call:


if (!sd.begin(SdChipSelect, SPI_FULL_SPEED)) {
   myError = 5;
 }




The sd.begin() call initializes its own internal card and volume object.

Ok, that, I did not know. Thanks for the lesson.

fat16lib:
The best way to diagnose sd.begin() problems is to use this form:

  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();

... snip ...

sd.initErrorHalt() will attempt to print a detailed message about the error. sd.initErrorHalt() calls sd.initErrorPrint() shown below.

Right, but the final unit will not have any way to print anything to a serial line. This is why I'm using an LED as indicator. Without the other two catches, it makes things simpler. Either it initializes or not, and the next two catches will be for actual file access.

Thanks!

I included the initErrorPrint() code so you could see to determine more error detail.

Do something like this:

  if (!sd.begin(SdChipSelect, SPI_FULL_SPEED)) {
    if (sd.card()->errorCode()) {
      // SD I/O error
      myError = 3;
    } else if ( sd.vol()->fatType() == 0) {
      // SD format error
      myError = 4;
    } else {
      // can't open root
      myError = 5;      
    }
  }