Finding Error in Interfacing Sd card on Ethernet/Sd shield from Adafruit

Hi,
I am trying to run some basic library examples.
I am using a custom made board having an atmega8 programmed with USBasp application to program a target device and till now I have never faced any real problem with the board.

I am trying to make an ethernet based data logger ,but since I am not able to run even a SD card on the board i have posted this topic.

Target device : Atmega168 16 PI.
Crystal : 16 Mhz
For 5.0 Volts (7805)
For 3.3 Volts (h1117s 3.3)

I have powered the Ethernet/Sd Shield board through 5V supply.
3.3 Volts ,Vin and Aref pins are unconnected on Ethernet/SD shield.

Now i connect my board to Ethernet/SD shield from Adafruit Arduino Ethernet shield R3 with micro SD connector - Assembled : ID 201 : $45.00 : Adafruit Industries, Unique & fun DIY electronics and kits.

Port Pins
PORTC.4
PORTC.5
PORTB.2 (SS)
PORTB.3(MOSI)
PORTB.4(MISO)
PORTB.5(SCK)
PORTD.4
PORTC.6(Reset)

Ethernet/Sd sheild
18(A4)
19(A5)
10
11
12
13
4
reset

Rx and Tx connection are working fine.

Software Library : sdfatlib20110902
Example : SDfat > SDInfo

/*
 * This sketch attempts to initialize an SD card and analyze its structure.
 */
#include <SdFat.h>
#include <NewSoftSerial.h>

NewSoftSerial mySerial(2, 3);
/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */
//const uint8_t SdChipSelect = 4;
const uint8_t SdChipSelect = SS_PIN;

Sd2Card card;
SdVolume vol;

// serial output steam
ArduinoOutStream cout(mySerial);

// global for card erase size
uint32_t eraseSize;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sdErrorMsg_P(PSTR(msg));
void sdErrorMsg_P(const char* str) {
  cout << pgm(str) << endl;
  if (card.errorCode()) {
    cout << pstr("SD errorCode: ");
    cout << hex << int(card.errorCode()) << endl;
    cout << pstr("SD errorData: ");
    cout << int(card.errorData()) << dec << endl;
  }
}
//------------------------------------------------------------------------------
uint8_t cidDmp() {
  cid_t cid;
  if (!card.readCID(&cid)) {
    sdErrorMsg("readCID failed");
    return false;
  }
  cout << pstr("\nManufacturer ID: ");
  cout << hex << int(cid.mid) << dec << endl;
  cout << pstr("OEM ID: ") << cid.oid[0] << cid.oid[1] << endl;
  cout << pstr("Product: ");
  for (uint8_t i = 0; i < 5; i++) {
    cout << cid.pnm[i];
  }
  cout << pstr("\nVersion: ");
  cout << int(cid.prv_n) << '.' << int(cid.prv_m) << endl;
  cout << pstr("Serial number: ") << cid.psn << endl;
  cout << pstr("Manufacturing date: ");
  cout << int(cid.mdt_month) << '/';
  cout << (2000 + cid.mdt_year_low + 10 * cid.mdt_year_high) << endl;
  cout << endl;
  return true;
}
//------------------------------------------------------------------------------
uint8_t csdDmp() {
  csd_t csd;
  uint8_t eraseSingleBlock;
  uint32_t cardSize = card.cardSize();
  if (cardSize == 0 || !card.readCSD(&csd)) {
    sdErrorMsg("readCSD failed");
    return false;
  }
  if (csd.v1.csd_ver == 0) {
    eraseSingleBlock = csd.v1.erase_blk_en;
    eraseSize = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
  } else if (csd.v2.csd_ver == 1) {
    eraseSingleBlock = csd.v2.erase_blk_en;
    eraseSize = (csd.v2.sector_size_high << 1) | csd.v2.sector_size_low;
  } else {
    cout << pstr("csd version error\n");
    return false;
  }
  eraseSize++;
  cout << pstr("cardSize: ") << cardSize << pstr(" (512 byte blocks)\n");
  cout << pstr("flashEraseSize: ") << int(eraseSize) << pstr(" blocks\n");
  cout << pstr("eraseSingleBlock: ");
  if (eraseSingleBlock) {
    cout << pstr("true\n");
  } else {
    cout << pstr("false\n");
  }
  return true;
}
//------------------------------------------------------------------------------
// print partition table
uint8_t partDmp() {
  cache_t *p = vol.cacheClear();
  if (!card.readBlock(0, p->data)) {
      sdErrorMsg("read MBR failed");
      return false;
  }
  cout << pstr("\nSD Partition Table\n");
  cout << pstr("part,boot,type,start,length\n");
  for (uint8_t ip = 1; ip < 5; ip++) {
    part_t *pt = &p->mbr.part[ip - 1];
    cout << int(ip) << ',' << hex << int(pt->boot) << ',' << int(pt->type);
    cout << dec << ',' << pt->firstSector <<',' << pt->totalSectors << endl;
  }
  return true;
}
//------------------------------------------------------------------------------
void volDmp() {
  cout << pstr("\nVolume is FAT") << int(vol.fatType()) << endl;
  cout << pstr("blocksPerCluster: ") << int(vol.blocksPerCluster()) << endl;
  cout << pstr("clusterCount: ") << vol.clusterCount() << endl;
  cout << pstr("freeClusters: ") << vol.freeClusterCount() << endl;
  cout << pstr("fatStartBlock: ") << vol.fatStartBlock() << endl;
  cout << pstr("fatCount: ") << int(vol.fatCount()) << endl;
  cout << pstr("blocksPerFat: ") << vol.blocksPerFat() << endl;
  cout << pstr("rootDirStart: ") << vol.rootDirStart() << endl;
  cout << pstr("dataStartBlock: ") << vol.dataStartBlock() << endl;
  if (vol.dataStartBlock() % eraseSize) {
    cout << pstr("Data area is not aligned on flash erase boundaries!\n");
    cout << pstr("Download and use formatter from www.sdcard.org/consumer!\n");
  }
}
//------------------------------------------------------------------------------
void setup() {
  mySerial.begin(9600);
// pinMode(10, OUTPUT);                       // set the SS pin as an output (necessary!)
//  digitalWrite(10, HIGH);                    // but turn off the W5100 chip!
//  uint8_t r = card.init(SPI_HALF_SPEED, 4);  // Use digital 4 as the SD SS line

  // use uppercase in hex and use 0X base prefix
  cout << uppercase << showbase << endl;
//  cout<<"SD PIN On"<<SdChipSelect;
  cout<<pstr("SS PIN")<<'0'+SdChipSelect;
  // pstr stores strings in flash to save RAM
  cout << pstr("SdFat version: ") << SD_FAT_VERSION << endl;
}
//------------------------------------------------------------------------------
void loop() {
  // read any existing Serial data
  while (mySerial.read() >= 0) {}
  
  // pstr stores strings in flash to save RAM
  cout << pstr("\ntype any character to start\n");
  while (mySerial.read() < 0) {}

  uint32_t t = millis();
  // initialize the SD card at SPI_HALF_SPEED to avoid bus errors with
  // breadboards.  use SPI_FULL_SPEED for better performance.
  if (!card.init(SPI_HALF_SPEED, SdChipSelect)) {
    sdErrorMsg("\ncard.init failed");
    return;
  }
  t = millis() - t;
  cout << pstr("\ninit time: ") << t << " ms" << endl;
  cout << pstr("\nCard type: ");
  switch (card.type()) {
    case SD_CARD_TYPE_SD1:
      cout << pstr("SD1\n");
      break;

    case SD_CARD_TYPE_SD2:
      cout << pstr("SD2\n");
      break;

    case SD_CARD_TYPE_SDHC:
      cout << pstr("SDHC\n");
      break;

    default:
      cout << pstr("Unknown\n");
  }
  if (!cidDmp()) return;
  if (!csdDmp()) return;
  if (!partDmp()) return;
  if (!vol.init(&card)) {
    sdErrorMsg("\nvol.init failed");
    return;
  }
  volDmp();
}

Software Compiled Successfully

COM Output Screen

SS PIN58
SdFat version: 20110902
type any character to start
card.init failed
SD errorCode: 0X1
SD errorData: 0XFF
type any character to start

I have tried

  • Changing the SdChipSelect to 4.
  • Declaring PIN 10 as pinMode(10, OUTPUT);
  • Tried connection with 3.3 Volts power connected to Ethernet/Sd shield board.

But none of the above tries have worked till now.

Please note I am not using any arduino board which makes problem finding a little bit more difficult,but i am thinking positive and ready to work on suggestion given by members and moderators here.
Please ask for any other information that you may think will be useful in diagnosing the error.
Thanks

Do you have a regular Arduino on which the Ethernet/SD card shield do work? If not, you should get one to test with.

Have you tried different cards? Not all cards are compatible, unfortunately.

I have tested some typical examples like PS2 mouse/Keyboard with Stepper motor and LCD and some more with EEprom's on Atmega8 and Atmega88 everything seems to be working quite well there.

Have you tried different cards? Not all cards are compatible, unfortunately.

I am using a 2GB card from SanDisk will try with others soon.I also suspect the mfd company of SD card and will try to change it soon.
Do you suspect any other problem apart this ??

Thanks for your early reply.

divyansh:
I am using a custom made board having an atmega8 programmed with USBasp application to program a target device and till now I have never faced any real problem with the board.

I am trying to make an ethernet based data logger ,but since I am not able to run even a SD card on the board i have posted this topic.

When I was using the Data Logging Shield there was a warning on the SD library that the library required a lot of RAM and you would be lucky to get it working on anything smaller than an ATmega328 (2k of SRAM). Since the ATmega8 has only 1k of SRAM I think that might be your problem.

I have mentioned that Atmega8 is only being used as master to program a device further using USBasp application.
I am using Atmega168 as the target Device on this board and I checked that binary sketch size of SDfatinfo program using the latest version of Sdfat library is 11276 bytes out of 14336 bytes of ATmega168 , which means almost 20% of Code space is free.

divyansh:
20% of Code space is free.

How much SRAM space is free?
(That's something that Binary sketch size won't tell you.)

Did you format the SD card first? Sdfat library has a nice format too and a card check tool also. You could run the SDfat programs by themselves then go back to trying the Ethernet part.

Since card.init() failed this isn't a file system issue, its a SD interface thing.

I've seen the SD library reject a card that's perfectly valid, I suspect because it timed out on init (it was an old 32Meg card that takes a long time to init).
I'm currently investigating a different issue with the SD lib and I'll try and remember to see if its waiting long enough for init. I've already found its driving the SPI bus too slow and not releasing MISO correctly so I suspect you've just hit a bug in the SD library.

Check the card is readable on another system...

[edit: whoops, just noticed you're using SDfat, not SD lib, some of my comments aren't relevant]

Your error:

SD errorCode: 0X1
SD errorData: 0XFF

Means that your card did not accept the first command, CMD0, and timed out after two seconds. This means SdFat does not see the card on the SPI bus.

I don't think the SPI pins are connected to shield pins 11, 12, and 13. They are connected to the ICSP header so the Ethernet shield will work on either a 328 or Mega.

I don't know what MarkT means by

driving the SPI bus too slow and not releasing MISO

SD cards are initialized at a slow SPI speed and after initialization the spec allows a wide range of speeds.

On the Arduino, the state of MISO is controlled by the SPI hardware and the devices/shields connected to MISO. There are no software options to control MISO. MISO is an input.

SD/MMC cards don't release the MISO line until 8 clocks are sent with the chip select HIGH (ie not active). If you want another device on the same SPI bus you have to send those 8 clocks before trying to talk to the other device, otherwise both the SD card and the other device will drive MISO simultaneously (since SD is 3V3 I have a 2k2 resistor in series so that protects the hardware, but the data gets garbled)

Also the specs say that the initial clock speed must be 380 to 420kHz, which simply isn't possible with hardware SPI with 16MHz crystal, but I am fairly confident 250kHz will work OK on any card, I'm just saying that 125kHz is unnecessarily slow (hogging the SPI bus, more likely to be a problem with picky SD/MMC cards).

Did you tell the SDfat library which pin you are using for SS for the SD card?

fat16lib helped me to understand how to do that to get my Bobuino SD card interface working.

markT,

The SD Physical Layer Spec does not say the initial clock must be 380 to 420kHz. It suggests a clock rate of 100 - 400 kHz. Modern SD cards can be initialized at much higher SPI speeds.

The reason is that this allows you to identify MMC cards. I have experimented with about 20 old cards and use F_CPU/64 which is 250 kHz. The clock divisor for card initialization is an option that can be set in the SdFatConfig.h file from F_CPU/128 to F_CPU/2.

I now understand what you mean by the state of MISO. In past versions of SdFat I tried to do the right thing for each operation to insure I read enough data so MISO would be released. This is not very reliable since there are still cases where at least one more clock is required. MMC cards can require eight clocks but I don't support them, only identify them and give an error code.

I now have a chipSelectHigh() routine and will write a byte after setting CS high. This version of SdFat will be released after Arduino 1.0 is released.

Ah, I may be conflating MMC/Transflash and SD specs (the former I have good docs for, the latter less so). Is there a safe maximum SPI speed that can be used after initialization?

Thanks for the fast response to this bug report 8) - I'm sure it will prevent a lot of complaints in the future when people try to use multiple SPI devices, can't believe I'm the first to be bitten by this though...

There is one more issue that I've encountered when sharing the SPI bus - different devices may use different speeds and CPOL/CPHA settings and there ought to be a nice packaged way to auto-switch the settings as different devices are accessed via different "SPI instances". The existing Arduino SPI library is should we say "limited"... (The issue of accessing the SPI bus in interrupt routines I'll leave till later!)

I don't use the SPI library. I setup the bus before every access.

Most devices don't have problems since many New SD cards release the bus. Most SPI devices don't use the first MISO bit on the leading edge of clock.

You are wrong about 8 clocks for SD cards. MMC cards require 8. SD cards release on the edge of the first clock. That's why many devices share o.k.

You are the first to notice the problem. What device are you using?