0
\$\begingroup\$

I am trying to interface with a 32GB MicroSD card with an Arduino Uno, but the code consistently fails at the initialization stage. Below is my schematic (sorry for the horrendous schematic, I'm not very good with Fritzing):

enter image description here

Seems fairly straightforward, just connecting SCK to SCK, MISO to MISO with a 12k ohm pullup, MOSI to MOSI through a voltage divider, and CS to digital pin 4. The reserved and NC pins have been tested floating and with pullup resistors (I read somewhere that they're needed).

The code I'm running is the QuickStart example sketch from the SdFat library:

// Quick hardware test for SPI card access.
//
#include <SPI.h>
#include "SdFat.h"
#include "sdios.h"
//
// Set DISABLE_CHIP_SELECT to disable a second SPI device.
// For example, with the Ethernet shield, set DISABLE_CHIP_SELECT
// to 10 to disable the Ethernet controller.
const int8_t DISABLE_CHIP_SELECT = -1;
//
// Test with reduced SPI speed for breadboards.  SD_SCK_MHZ(4) will select
// the highest speed supported by the board that is not over 4 MHz.
// Change SPI_SPEED to SD_SCK_MHZ(50) for best performance.
#define SPI_SPEED SD_SCK_MHZ(4)
//------------------------------------------------------------------------------
// File system object.
SdFat sd;

// Serial streams
ArduinoOutStream cout(Serial);

// input buffer for line
char cinBuf[40];
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));

// SD card chip select
int chipSelect;

void cardOrSpeed() {
  cout << F("Try another SD card or reduce the SPI bus speed.\n");
  cout << F("Edit SPI_SPEED in this program to change it.\n");
}

void reformatMsg() {
  cout << F("Try reformatting the card.  For best results use\n");
  cout << F("the SdFormatter program in SdFat/examples or download\n");
  cout << F("and use SDFormatter from www.sdcard.org/downloads.\n");
}

void setup() {
  Serial.begin(9600);

  // Wait for USB Serial
  while (!Serial) {
    SysCall::yield();
  }
  cout << F("\nSPI pins:\n");
  cout << F("MISO: ") << int(MISO) << endl;
  cout << F("MOSI: ") << int(MOSI) << endl;
  cout << F("SCK:  ") << int(SCK) << endl;
  cout << F("SS:   ") << int(SS) << endl;

  if (DISABLE_CHIP_SELECT < 0) {
    cout << F(
           "\nBe sure to edit DISABLE_CHIP_SELECT if you have\n"
           "a second SPI device.  For example, with the Ethernet\n"
           "shield, DISABLE_CHIP_SELECT should be set to 10\n"
           "to disable the Ethernet controller.\n");
  }
  cout << F(
         "\nSD chip select is the key hardware option.\n"
         "Common values are:\n"
         "Arduino Ethernet shield, pin 4\n"
         "Sparkfun SD shield, pin 8\n"
         "Adafruit SD shields and modules, pin 10\n");
}

bool firstTry = true;
void loop() {
  // Read any existing Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);

  if (!firstTry) {
    cout << F("\nRestarting\n");
  }
  firstTry = false;

  cout << F("\nEnter the chip select pin number: ");
  while (!Serial.available()) {
    SysCall::yield();
  }
  cin.readline();
  if (cin >> chipSelect) {
    cout << chipSelect << endl;
  } else {
    cout << F("\nInvalid pin number\n");
    return;
  }
  if (DISABLE_CHIP_SELECT < 0) {
    cout << F(
           "\nAssuming the SD is the only SPI device.\n"
           "Edit DISABLE_CHIP_SELECT to disable another device.\n");
  } else {
    cout << F("\nDisabling SPI device on pin ");
    cout << int(DISABLE_CHIP_SELECT) << endl;
    pinMode(DISABLE_CHIP_SELECT, OUTPUT);
    digitalWrite(DISABLE_CHIP_SELECT, HIGH);
  }
  if (!sd.begin(chipSelect, SPI_SPEED)) {
    if (sd.card()->errorCode()) {
      cout << F(
             "\nSD initialization failed.\n"
             "Do not reformat the card!\n"
             "Is the card correctly inserted?\n"
             "Is chipSelect set to the correct value?\n"
             "Does another SPI device need to be disabled?\n"
             "Is there a wiring/soldering problem?\n");
      cout << F("\nerrorCode: ") << hex << showbase;
      cout << int(sd.card()->errorCode());
      cout << F(", errorData: ") << int(sd.card()->errorData());
      cout << dec << noshowbase << endl;
      return;
    }
    if (sd.vol()->fatType() == 0) {
      cout << F("Can't find a valid FAT16/FAT32 partition.\n");
      reformatMsg();
      return;
    }
    cout << F("begin failed, can't determine error type\n");
    return;
  }
  cout << F("\nCard successfully initialized.\n");
  cout << endl;

  uint32_t size = sd.card()->cardSize();
  if (size == 0) {
    cout << F("Can't determine the card size.\n");
    cardOrSpeed();
    return;
  }
  uint32_t sizeMB = 0.000512 * size + 0.5;
  cout << F("Card size: ") << sizeMB;
  cout << F(" MB (MB = 1,000,000 bytes)\n");
  cout << endl;
  cout << F("Volume is FAT") << int(sd.vol()->fatType());
  cout << F(", Cluster size (bytes): ") << 512L * sd.vol()->blocksPerCluster();
  cout << endl << endl;

  cout << F("Files found (date time size name):\n");
  sd.ls(LS_R | LS_DATE | LS_SIZE);

  if ((sizeMB > 1100 && sd.vol()->blocksPerCluster() < 64)
      || (sizeMB < 2200 && sd.vol()->fatType() == 32)) {
    cout << F("\nThis card should be reformatted for best performance.\n");
    cout << F("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
    cout << F("Only cards larger than 2 GB should be formatted FAT32.\n");
    reformatMsg();
    return;
  }
  // Read any extra Serial data.
  do {
    delay(10);
  } while (Serial.available() && Serial.read() >= 0);
  cout << F("\nSuccess!  Type any character to restart.\n");
  while (!Serial.available()) {
    SysCall::yield();
  }
}

Upon uploading the code, the serial monitor outputs this:

02:04:02.002 -> 
02:04:02.002 -> SPI pins:
02:04:02.002 -> MISO: 12
02:04:02.036 -> MOSI: 11
02:04:02.036 -> SCK:  13
02:04:02.036 -> SS:   10
02:04:02.071 -> 
02:04:02.071 -> Be sure to edit DISABLE_CHIP_SELECT if you have
02:04:02.106 -> a second SPI device.  For example, with the Ethernet
02:04:02.175 -> shield, DISABLE_CHIP_SELECT should be set to 10
02:04:02.209 -> to disable the Ethernet controller.
02:04:02.278 -> 
02:04:02.278 -> SD chip select is the key hardware option.
02:04:02.312 -> Common values are:
02:04:02.312 -> Arduino Ethernet shield, pin 4
02:04:02.347 -> Sparkfun SD shield, pin 8
02:04:02.380 -> Adafruit SD shields and modules, pin 10
02:04:02.448 -> 
02:04:02.448 -> Enter the chip select pin number: 4
02:04:27.206 -> 
02:04:27.206 -> Assuming the SD is the only SPI device.
02:04:27.241 -> Edit DISABLE_CHIP_SELECT to disable another device.
02:04:27.379 -> 
02:04:27.379 -> SD initialization failed.
02:04:27.412 -> Do not reformat the card!
02:04:27.445 -> Is the card correctly inserted?
02:04:27.479 -> Is chipSelect set to the correct value?
02:04:27.546 -> Does another SPI device need to be disabled?
02:04:27.579 -> Is there a wiring/soldering problem?
02:04:27.612 -> 
02:04:27.612 -> errorCode: 0x20, errorData: 0xff
02:04:27.646 -> 
02:04:27.646 -> Restarting
02:04:27.680 -> 
02:04:27.680 -> Enter the chip select pin number: 4
04:03:50.362 -> 
04:03:50.362 -> Assuming the SD is the only SPI device.
04:03:50.432 -> Edit DISABLE_CHIP_SELECT to disable another device.
04:03:52.411 -> 
04:03:52.411 -> SD initialization failed.
04:03:52.445 -> Do not reformat the card!
04:03:52.445 -> Is the card correctly inserted?
04:03:52.499 -> Is chipSelect set to the correct value?
04:03:52.540 -> Does another SPI device need to be disabled?
04:03:52.574 -> Is there a wiring/soldering problem?
04:03:52.628 -> 
04:03:52.628 -> errorCode: 0x43, errorData: 0xff
04:03:52.661 -> 
04:03:52.661 -> Restarting
04:03:52.661 -> 
04:03:52.696 -> Enter the chip select pin number: 4
04:04:04.359 -> 
04:04:04.359 -> Assuming the SD is the only SPI device.
04:04:04.427 -> Edit DISABLE_CHIP_SELECT to disable another device.
04:04:06.413 -> 
04:04:06.413 -> SD initialization failed.
04:04:06.446 -> Do not reformat the card!
04:04:06.479 -> Is the card correctly inserted?
04:04:06.479 -> Is chipSelect set to the correct value?
04:04:06.548 -> Does another SPI device need to be disabled?
04:04:06.582 -> Is there a wiring/soldering problem?
04:04:06.617 -> 
04:04:06.617 -> errorCode: 0x43, errorData: 0xff
04:04:06.651 -> 
04:04:06.651 -> Restarting
04:04:06.685 -> 
04:04:06.685 -> Enter the chip select pin number: 

If you look at the serial output, you'll see that at first I got:

errorCode: 0x20, errorData: 0xff

After this, I swapped out the MicroSD card for another 32GB MicroSD card and got this:

errorCode: 0x43, errorData: 0xff

Both cards have been formatted with the official formatting program from SD's website. External power is being used, so current limiting shouldn't be an issue. Not really sure what's going wrong here. Any help would be appreciated. Thanks in advance! Let me know if more info is needed.

\$\endgroup\$
0
\$\begingroup\$

Arduino UNO uses 5V logic on SPI pins and SD cards use 3.3V logic! For some reason you have only voltage divisor on MOSI but have connected 5V signals CS and SCK directly to 3.3V card. Stop and redo the card interface before you fry more of your cards, they might be dead by now. Also a 5V AVR needs at least 0.7xVCC or with 5V VCC at least 3.5V to properly detect logic high level.

Besides, high speed SPI lines divided with 12k impedances makes the signal edges most likely too slow to work at all, change the resistors to be much stronger or do the level shifting properly with a chip of some sort.

\$\endgroup\$
4
  • \$\begingroup\$ Only using voltage divider on MOSI to step down from 5V to 3.3V so the card doesn't get fried. Don't need one on MISO because Arduino Uno can detect 3.3V as digital high, I figure this will work as a temporarily solution. Correct me if I'm wrong, but increasing resistance value would make the signal edges slower, wouldn't it? Don't I need to decrease the pull-up resistors? Thanks for the answer \$\endgroup\$ – Zach_1919 Nov 2 '19 at 2:19
  • \$\begingroup\$ But you haven't divided SCK and CS so they are still 5V signals to SD card. So cards might be broken now. And 5V AVR needs minimum of 3.5 volts on input pins ( says 0.7 x VCC ) so as it is not within specs it is not guaranteed to work. Stronger load means less resistance, yes you would need to decrease resistance values. \$\endgroup\$ – Justme Nov 2 '19 at 8:57
  • \$\begingroup\$ I fixed the circuit using a proper level shifter. Tested SD cards in computer and they are still fully functional. Still getting errors. Any ideas? \$\endgroup\$ – Zach_1919 Nov 5 '19 at 9:02
  • \$\begingroup\$ Please start a new question. I also can't know what is a proper level shifter and how you have connected it, so describe them in the new question also. \$\endgroup\$ – Justme Nov 5 '19 at 12:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.