SD Card - MISO doesn't release [Bad MISO, Bad MISO!!]

I [was] having the same problem as described in this old thread by MarkT [from 15 Sept 2011]. Why hasn't this problem been resolved in the IDE SD library?

http://forum.arduino.cc/index.php?topic=72446.0

For reference, all of the example sketches in the SD library run fine, so the SD Card is formatted ok, and has files on it to be read, my Arduinos work, the CS pins are set appropriately, D10 is set to OUTPUT, &etc, &etc, &etc.

Notes: - IDE v.1.0.5 - SanDisk Micro SD card, 4GB and 8GB - tried on 2 different UNO boards, one board with SD socket built-in, and also using Sparkfu SD shield

.

I finally fixed the problem by tracking down the 3-YO thread, and following MarkT's comments, by adding the following commands at the end of the example sketch, eg CardInfo,
[code]  
  digitalWrite(8,HIGH);
  SPI.transfer(0xAA);[/code] 

Why hasn't this problem been resolved in the IDE SD library?

Why isn't there a note on the Arduino SD pages telling how to fix it?

I use the SD card with the ethernet shield and the wifi shield. Both work without that "fix".

SurferTim: I use the SD card with the ethernet shield and the wifi shield. Both work without that "fix".

I was hoping someone would point that out. Why there, but not for this case? Can you test an SD card without ethernet present?

What do you mean "without the ethernet present"? I tested the SD cards by disabling the ethernet or wifi SPI and they worked ok. I don't have a SD module or shield without any other function.

I hear of a lot of people here having trouble with SD modules that do not have a logic level converter.

edit: If the MISO line was going to be a problem, it would be when working with another SPI device like the w5100 or HDG104.

Why hasn't this problem been resolved in the IDE SD library?

This problem impacts few devices since few send data to the master on the first byte of a transaction. The SD MISO goes high-Z after the first transfer.

Also, the old version of SdFat in SD.h has many other unfixed bugs. This is why I added an SD.h compatible API to SdFat http://forum.arduino.cc/index.php?topic=274784.0.

I fixed SdFat just after MarkT's post.

This problem impacts few devices since few send data to the master on the first byte of a transaction.

Hmm, I should think this would have affected pretty much everyone who's ever tried using the IDE SD library with an SD card. They probably just didn't know MISO was breaking bad.

But thanks for the updated files - will take a [very LONGGGGG] while to go through them. Is there a chance the IDE libraries will be fixed one day?

fat16lib: This problem impacts few devices since few send data to the master on the first byte of a transaction. The SD MISO goes high-Z after the first transfer.

That is only during a SD transfer, correct? If the SD SPI slave select is HIGH, the MISO line should stay high-Z during another device SPI transfer. It does (apparently) when working with the w5100 and HDG104.

edit: Just ran a test with my web server code. It reads 64 bytes at a time from the SD card before sending the array to the w5100. I checked the level of the SD slave select (D4) after every call to myFile.read(), and it was always HIGH. That means if the MISO line is malfunctioning, it would be a hardware problem with the SD card itself, not the SD library.

That test was using IDE v1.0.5.

I checked the level of the SD slave select (D4) after every call to myFile.read(), and it was always HIGH. That means if the MISO line is malfunctioning, it would be a hardware problem with the SD card itself, not the SD library.

No, SD.h has a bug. I wrote the bug and fixed it in newer versions of SdFat.

You must send clocks to an SD with chips select high to cause the SD card to release MISO. SD cards release MISO quickly, after one or two clocks (I don't remember which) so even devices that send one or two don't care bits work OK, like some ADCs.

I think MMC cards need a whole byte of clocks.

You must send clocks to an SD with chips select high to cause the SD card to release MISO.

So you must send an additional byte to the SD to get it to release the MOSI line after the slave select goes HIGH? Is that one particular card, or all cards? Do you have a link to a reference covering that?

Is that one particular card, or all cards? Do you have a link to a reference covering that?

It is true for all cards. Here is a link http://elm-chan.org/docs/mmc/mmc_e.html.

See the section "Cosideration on Multi-slave Configuration"

The image shows release of MISO for SD and MMC cards. See the right side where CS is high. The SD releases after one clock and the MMC after eight.

The left side shows how clocks are needed after CS is low before checking MISO for busy.

I just found that same requirement on the SanDisk data sheet. Thanks!

That gets you karma +1

SurferTim: What do you mean "without the ethernet present"? I tested the SD cards by disabling the ethernet or wifi SPI and they worked ok. I don't have a SD module or shield without any other function.

What I was meant was to see if you couldn't repeat the problem on a board "without" ethernet on it.

edit: If the MISO line was going to be a problem, it would be when working with another SPI device like the w5100 or HDG104.

I imagine they found and patched the problem in the ethernet library when writing the code to control the W5100 chip. It would have been immediately apparent that the SD card was not releasing MISO. That's how I found it - by trying to operate the SD card and RFM radios off the same SPI port.

Bill [Greiman] definitely deserves a few karmas for building the entire SD card thing, but I'm also gonna give MarkT a few just for finding the problem and pointing out a fix for it ----> already 3 years ago.

I'm still totally PO'ed this hasn't been fixed in the IDE after all this time. Jeez Louise.

I imagine they found and patched the problem in the ethernet library when writing the code to control the W5100 chip.

I am pretty familiar with the w5100, and I do not believe it has the MISO problem. It's timing shows when the slave select goes HIGH, the MISO line is released (high-Z).

That is why I was surprised to see that with the SD card. I haven't seen any other devices that do not release the MISO when the slave select goes HIGH.

Seems like a waste of time to send another byte every time I want to write or read one byte. Is this the "fix"?

edit: I checked the SPI timing data for the w5100, and it does release the MISO line when the slave select goes HIGH. It requires no additional clock cycles.

Alright, I dug out my ethernet shield, plugged it into my UNO board, and compiled SD example CardInfo. The shield uses D10 for the W5100 CS and D4 for the SD card, and D10 is apparently not being exercised by the CardInfo sketch.

Lo and behold, MISO stays HIGH after running the sketch. And adding SPI.transfer(0xAA) at the end of the sketch fixes the problem. Try it yourself, and see what happens on your board.

If what fat16lib posted is true, then all that would be needed is this:

digitalWrite(SCK,HIGH);
digitalWrite(SCK,LOW);

I'll try this first.

edit: That didn't work. Your fix worked, and this worked:

SPI.setDataMode(SPI_MODE3);
SPI.setDataMode(SPI_MODE0);

I don't know which is faster.

It is easy to fix SD.h. Edit this file in the Arduino IDE folder: libraries/SD/utility/Sd2Card.cpp

At about line 145 make this change:

void Sd2Card::chipSelectHigh(void) {
  digitalWrite(chipSelectPin_, HIGH);
  spiSend(0XFF);  // <---------------ADD THIS LINE
}

At about line 222 make this change:

 // set pin modes
  pinMode(chipSelectPin_, OUTPUT);
  digitalWrite(chipSelectPin_, HIGH);  // <-------  was chipSelectHigh();
  pinMode(SPI_MISO_PIN, INPUT);
  pinMode(SPI_MOSI_PIN, OUTPUT);
  pinMode(SPI_SCK_PIN, OUTPUT);

You will still find other old bugs in SD.h. The latest SdFat beta supports the SD.h API. You only need to change the SD.h include to this:

#include <SdFat.h>
SdFat SD;
1 Like

@fat16lib: Does the SD or SdFat libraries support MMC cards? Or just SD?

How often is Sd2Card::chipSelectHigh() called? Will it be called after every myFile.read() call?

edit: The reason I ask is if MMC cards are not supported, only one clock pulse is required to release the MISO line. The SPI library will toggle the SCK line if you change the mode to 3 and back to 0.

This is from the SPI library (SPI.cpp).

void SPIClass::setDataMode(uint8_t mode)
{
  SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
}

This has to be faster than sending another byte. This toggles the SCK line HIGH, then LOW:

void SPIClass::toggleDataMode(void)
{
  SPCR = (SPCR & ~SPI_MODE_MASK) | 0x0C; // set mode 3
  nop;
  SPCR = (SPCR & ~SPI_MODE_MASK) | 0x00; // set mode 0
}

@fat16lib: Does the SD or SdFat libraries support MMC cards? Or just SD?

SdFat only supports SD. MMC has diverged from SD so I don’t plan to extend SdFat to MMC.

I have developed a new generic FAT library that can easily support any block device. This library can support 4-bit SDIO, USB flash drives, and other block devices. I will replace most of the code in SdFat with this base soon.

I will likely add a MMC driver to this library maybe for 8-bit MMC. I already get 20-30 MB/sec on STM32 chips with 4-bit SDIO.

How often is Sd2Card::chipSelectHigh() called? Will it be called after every myFile.read() call?

The extra byte is only sent when the SD is accessed so it adds at most one extra byte for a 512 byte transfer. It is far more efficient than digitalWrite on SCK. On AVR, digitalWrite takes 3-4 µs per call or 6-8 µs total. The spiSend() takes 1-2 µs.

I just did a compare of the version of SdFat currently in SD.h with the original written over four years ago. There have been no bug fixes to my code. A few simple changes were made to support the 1.0 IDE and this addition I made at the end of 2010.

digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin

There were about ten changes like these:

< #include <WProgram.h>
---
> #include <Arduino.h>

< void SdFile::write(uint8_t b) {
<   write(&b, 1);
---
> size_t SdFile::write(uint8_t b) {
>   return write(&b, 1);

If it is called for every 512 byte SD access, I’m good with that.

edit: I made the changes you suggested in reply #15, and it works like a champ! Thanks!
karma +1 again.

And karma +1 for oric_dan for bringing this to my attention.

This has to be faster than sending another byte. This toggles the SCK line HIGH, then LOW:

void SPIClass::toggleDataMode(void) { SPCR = (SPCR & ~SPI_MODE_MASK) | 0x0C; // set mode 3 nop; SPCR = (SPCR & ~SPI_MODE_MASK) | 0x00; // set mode 0 }

Yes it may be fast, but it is not at the requested speed. I found that when users select SPI speeds you must clock data at the speed they request. Also I now have SPI code for five chip types and don't want to maintain a trick for each, AVR, SAM3X, STM32, LPC, Kinetis K20, and more in the future.

Edit: You also must use low speed SPI during SD initialization, should be under 400 kHz.

For SD single block write on Arduino, it is useless to optimize at this level. Most SPI cycles are for busy wait while the previous write block is programmed. That's why write is so slow.

Modern SD cards program flash in blocks of 16 kB or larger. When you write a single 512 byte block, any data from the current block is moved to a big buffer and the new 512 bytes is added. This data is then programmed in a new big flash block. The card programs 32-64 times as much flash as the Arduino sends.

To achieve high speed, you must use multiple block transfers which is impossible with limited memory for file system writes. Multiple block transfers on SD cards pipeline the buffering and programming of flash so it is possible now to achieve write speeds of over 90 MB/sec on high end SD cards.

I do use multiple block writes for large transfers when possible. This is how I achieve 20-30 MB/sec on large STM32 chips. This is bus speed limited for STM32 SDIO.