Ethernet shield SD card initialization failed

I'm trying to use the microsd card slot on my ethernet shield and it is not working. I'm not even trying to run ethernet stuff yet, just SD card examples. I've tried the code in this thread and a few others with no luck. I've formatted the card several times with windows and the official SD formatting tool.

Now I am reading that the ethernet library messes with the SD library, but if I'm not even trying the ethernet library should there be any reason for the SD card to not work? Do I have a different problem in this case?

What hardware are you using? The sd card and the Ethernet stuff run completely independently and do not affect each other on my Uno.

Do I have a different problem in this case?

Yes, no, maybe.

Some code?

The sd card and the Ethernet stuff run completely independently and do not affect each other on my Uno.

They do not run independently on my mega2560. They are both SPI devices, and if not disabled or initialized correctly, they will cause failures in the other device.

Have you tried the ethernet part of the shield to check the SPI connection? Try this sketch. Does it show 192.168.2.2 on the serial monitor? Or does it show 0.0.0.0?

#include <SPI.h>
#include <Ethernet.h>

byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,2,2);

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

  // disable SD card if one in the slot
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);

  Serial.println("Starting w5100");
  Ethernet.begin(mac,ip);

  Serial.println(Ethernet.localIP());
}

void loop() {
}

You should be able to leave the SD card in the slot for this test. Note the SD disable in the setup.

But on the shield they are supposed to be independent. What I'm saying is, I can't even get the SD card to work when I completely ignore the Ethernet stuff. I have no problem with the Ethernet stuff. And I am aware that there is some conflict when using both. But I am running code as if it were just the SD card and it doesn't work.

For instance the cardinfo sketch:

/*
  SD card test 
   
 This example shows how use the utility libraries on which the'
 SD library is based in order to get info about your SD card.
 Very useful for testing a card when you're not sure whether its working or not.
 	
 The circuit:
  * SD card attached to SPI bus as follows:
 ** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
 ** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
 ** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
 ** CS - depends on your SD card shield or module. 
 		Pin 4 used here for consistency with other Arduino examples

 
 created  28 Mar 2011
 by Limor Fried 
 modified 9 Apr 2012
 by Tom Igoe
 */
 // include the SD library:
#include <SD.h>

// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
const int chipSelect = 4;    

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }


  Serial.print("\nInitializing SD card...");
  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
  pinMode(10, OUTPUT);     // change this to 53 on a mega


  // we'll use the initialization code from the utility libraries
  // since we're just testing if the card is working!
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
   Serial.println("Wiring is correct and a card is present."); 
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
  
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

  
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
  
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);
}


void loop(void) {
  
}

returns:

Initializing SD card...initialization failed. Things to check:

  • is a card is inserted?
  • Is your wiring correct?
  • did you change the chipSelect pin to match your shield or module?

I've tried all of the example sketches for the SD card and they all fail to initialize the card.

But on the shield they are supposed to be independent.

How can they be independent when both use SPI? They use different SS pins, so you should be able to talk to each without interference from the other, but that is not the same as independent.

I've tried all of the example sketches for the SD card and they all fail to initialize the card.

Perhaps the problem is the card. Not all cards play well with all SD readers.

As PaulS said, they are never independent because they share the SPI bus. You can use either separately, but you MUST disable the other device to do so. Otherwise, you will have problems. This should be able to initialize and use the SD ok.

void setup()
{
 // Open serial communications and wait for port to open:
  Serial.begin(9600);
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // disable w5100 SPI
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  Serial.print("\nInitializing SD card...");
  // rest of your setup stuff

I am having the same problem. Is there any way to debug exactly why the SD card initialization step is failing?

Thanks.

What I have since found is that the SPI library will use the SS defined in the libraries even though you may be using a different SS for your device. For example, if the Ethernet is on SS pin N and the SD card uses pin M, and N is the same as the SS defined in the library, when you use the SD card (pin M) the library will also set N, in the library code. This is not what you expect or want to happen.

My way around this is that if I have one device then I will just use SS, if I have more than one device then I cannot use SS (ie it is lost to me as a valid pin) and I need to use two other pins and manage it myself. This assume that the pins are not hard wired, like on a shield.

An alternative is to hack the libraries to not use the SS pin the way it does.

Is there any way to debug exactly why the SD card initialization step is failing?

This sketch will give more information. The most common error code is 0X01. This means the card does not respond to the first command to go into SPI mode. Other error codes are defined in \arduino\libraries\SD\utility\Sd2Card.h.

Set sdCsPin and sharedCsPin for you configuration.

#include <SD.h>
#include <SPI.h>
Sd2Card card;
SdVolume vol;
SdFile root;

// Chip select pin for SD card.
const int sdCsPin = 8;

// Replace the -1 with the CS pin number of any shared SPI device.
const int sharedCsPin = -1;

void setup() {
  Serial.begin(9600);
  
  // Disable any other SPI devices
  if (sharedCsPin >= 0) {
    pinMode(sharedCsPin, OUTPUT);
    digitalWrite(sharedCsPin, HIGH);
  }
  
  // Try to initialize the SD card
  if (card.init(SPI_HALF_SPEED, sdCsPin)) {
    Serial.println("card init OK");
  } else {
    Serial.print("errorCode: ");
    Serial.println(card.errorCode(), HEX);
    Serial.print("errorData: ");
    Serial.println(card.errorData(), HEX);
    return;
  }
  
  // Try to initialize the FAT volume.
  if (vol.init(&card)) {
    Serial.println("vol init OK");
  } else {
    Serial.println("vol init failed");
    return;
  }
  
  // Try to open root.
  if (root.openRoot(&vol)) {
    Serial.println("open root OK");
  } else {
    Serial.println("open root failed");
  }
}
void loop() {}

An alternative is to hack the libraries to not use the SS pin the way it does.

If you use SS as an input, the library will no longer work. Here is a section of the AVR datasheet for the SPI controller.

If SS is configured as an output, the pin is a general output pin which does not affect the SPI system. Typically, the pin will be driving the SS pin of the SPI Slave.

If SS is configured as an input, it must be held high to ensure Master SPI operation. If the SS pin is driven low by peripheral circuitry when the SPI is configured as a Master with the SS pin defined as an input, the SPI system interprets this as another master selecting the SPI as a slave and starting to send data to it. To avoid bus contention, the SPI system takes the following actions:

  1. The MSTR bit in SPCR is cleared and the SPI system becomes a Slave. As a result of
    the SPI becoming a Slave, the MOSI and SCK pins become inputs.

  2. The SPIF Flag in SPSR is set, and if the SPI interrupt is enabled, and the I-bit in SREG is
    set, the interrupt routine will be executed.

What model Arduino are you using?

If you are using an Uno, the w5100 SPI will be disabled by accident when the SD.begin() call sets the default SPI slave select (D10) to OUTPUT and HIGH.

If you are using a Mega (SPI default SS is D53, not D10), then the w5100 SPI is left active, and this causes the SD.begin() function to fail on my Mega2560 if you do not set D10 as OUTPUT and HIGH.

If you are using an Uno, the w5100 SPI will be disabled by accident when the SD.begin() call sets the default SPI slave select (D10) to OUTPUT and HIGH.

This is not an accident. SS is set high to disable any device sharing SPI on 328 Arduinos and using D10 for chip select. This was done mainly to avoid problems with the Ethernet shield on Uno and other 328 boards. On 328 boards, D10 must be an output so setting it high avoids many problems.

In the above test sketch you should set sharedCsPin to 10 if you are using an Arduino Ethernet shield. It won't hurt if you are using an Uno and is necessary if you use a Mega.

In general, the safest procedure is to set chip select for all SPI devices to output mode and high in setup before initializing any SPI device.

Thanks, fat16lib. I say it is disabled by "accident" by most Uno/Ethernet shield users because they do not intentionally do that, and because most don't realize it is being done for them. They should set that w5100 SPI SS pin OUTPUT and HIGH. I know the SPI library does that intentionally. I agree with you that all SPI SS pins should be set as OUTPUT and HIGH before initializing any SPI device.

They should set that w5100 SPI SS pin OUTPUT and HIGH. I know the SPI library does that intentionally

This statement points out one of the many defects in Arduino. It is sad that users must worry about details at this level.

Why should users need to beg for help from "experts" for low level stuff like this?

The proper standards for hardware and libraries that use the SPI bus could avoid this type problem.

Hardware that uses the SPI bus should have a 50K pullup on chip select. SD cards have this pullup and the pullup can be disabled during initialization. Unfortunately most shields defeat this pullup with a level shifter and no pullup on the level shifter input.

Libraries should have a constructor with chip select as an argument. The constructors could make sure all devices are disabled before setup() is called.

I am using this type constructor on new libraries and will add it to SdFat.

I agree with the hardware solution. A weak pullup on the slave select would solve most of this. There will still be the occasional user that will try to use that slave select pin for another device.

I disagree with the library/software solution. How is each device supposed to know about every SPI device connected to the bus? And even if it did, some users connect the device without adding the library include to the code.

I disagree with the library/software solution

This provides help for legacy hardware. You mostly post in regard to the Ethernet shield where either the SD or Enet may not be used and this will still be a problem for current hardware. I get a lot of mail from users with libraries for all their SPI devices with initialization problems. The constructor solution would handle these cases.

Another problem that I now see more often is use of multiple SPI devices that conflict in mode and speed. Many libraries, including the old version of SdFat in SD.h, do not set all SPI options each time the SPI bus is used. These libraries need update since this problem is becoming more common.

The hardware solution is clearly best and I use it on all hardware I design. I have Arduino test systems with three or four shields stacked and never need to worry about what is being used.

The software solution works only if the user adds the include to the sketch. Look at the OP post in reply#4. The code is trying to use the SD card on the ethernet shield without adding "#include <Ethernet.h>" to the sketch. If this was used on a Mega, it would cause a failure of the SD startup. The w5100 SPI slave select (D10) is set as OUTPUT without changing the pin to HIGH and would corrupt the SD startup stuff.

I agree with the SPI mode and speed modifications to the SPI device libraries. Too many differences now.

Hardware solution is best.

The hardware solution would fail also.

  // On the Ethernet Shield, CS is pin 4. It's set as an output by default.
  // Note that even if it's not used as the CS pin, the hardware SS pin 
  // (10 on most Arduino boards, 53 on the Mega) must be left as an output 
  // or the SD library functions will not work. 
  pinMode(10, OUTPUT);     // change this to 53 on a mega

I tried to get Limor Fried to remove this but she wouldn't. Randomly setting pin 10 to output which pulls it low often causes problem on Mega and nothing fixes it. Any working library already handles setting SS to an output.

I tried to get Limor Fried to remove this but she wouldn't.

Wow! Even after being told it is wrong, she wouldn't change it? I can't believe she would refuse you. :astonished:

In general, the safest procedure is to set chip select for all SPI devices to output mode and high in setup before initializing any SPI device.

-->Including the hardware SS pin?

I had in mind that setting the SS pin to OUTPUT was meant to indicate to the card that there were some devices that were using SPI, does it still work when you set it up to HIGH?

To make my card work, i set the ethernet chip select and the ss pin to OUTPUT and HIGH.( i tried without putting the SS pin to HIGH and the initialisation failed)
Using the SD library, there is a function to read files on your SD card. I assume that to do that, the card must be put on a slave mode ( if i have understood well how SPI connection works ?) . How can i do that?