Go Down

Topic: SD Card - MISO doesn't release [Bad MISO, Bad MISO!!] (Read 16733 times) previous topic - next topic

fat16lib

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:

Code: [Select]

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


At about line 222 make this change:
Code: [Select]

 // 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:
Code: [Select]

#include <SdFat.h>
SdFat SD;

SurferTim

#16
Nov 02, 2014, 02:37 pm Last Edit: Nov 02, 2014, 03:32 pm by SurferTim
@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).
Code: [Select]
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:
Code: [Select]
void SPIClass::toggleDataMode(void)
{
  SPCR = (SPCR & ~SPI_MODE_MASK) | 0x0C; // set mode 3
  nop;
  SPCR = (SPCR & ~SPI_MODE_MASK) | 0x00; // set mode 0
}

fat16lib

Quote
@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.

Quote
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.

Code: [Select]

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


There were about ten changes like these:

Code: [Select]

< #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);

SurferTim

#18
Nov 02, 2014, 03:39 pm Last Edit: Nov 02, 2014, 04:14 pm by SurferTim
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.

fat16lib

#19
Nov 02, 2014, 05:32 pm Last Edit: Nov 02, 2014, 06:02 pm by fat16lib
Quote
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.

oric_dan

If what fat16lib posted is true, then all that would be needed is this:
Code: [Select]
digitalWrite(SCK,HIGH);
digitalWrite(SCK,LOW);

I'll try this first.

edit: That didn't work. Your fix worked, and this worked:
Code: [Select]
SPI.setDataMode(SPI_MODE3);
SPI.setDataMode(SPI_MODE0);

I don't know which is faster.
Good, now you see - it helps to try it for yourself. I had also previously tried your first fix as shown, in a loop of 8, and it also didn't work. It appears that once the SPI peripheral is enabled, it doesn't allow digitalWrite() to control the pins. So, onward, see if I can get the SD card and RFM12 radio working without conflict.

oric_dan

#21
Nov 02, 2014, 07:24 pm Last Edit: Nov 02, 2014, 07:43 pm by oric_dan
Bill, thanks for all the info, will take a while to sort through it all, plus your updated library. Thanks again.

I find that, just for the simple IDE example sketches, the SD.h parts using the IDE library add 6KB to 10KB to the executable size. Do you have any idea how much code size your library will add, in general?

I'm wanting to keep my program able to fit in the mega328 chip with 32KB Flash, since the board I have [Seeed Stalker v1.0] has SD slot, DS1307 RTC, CR2032 cell, plus mounting for the radio, and the program is currently at 18.6KB without the SD stuff. It's getting tight.

EDIT: BTW, what's your overall impression of using Free RTOS with Arduino chips? I might try it with my main board that has a mega1284 chip [certainly not the one mentioned above].

https://github.com/greiman/FreeRTOS-Arduino

SurferTim

#22
Nov 02, 2014, 08:13 pm Last Edit: Nov 02, 2014, 08:14 pm by SurferTim
Quote
Good, now you see - it helps to try it for yourself. I had also previously tried your first fix as shown, in a loop of 8, and it also didn't work. It appears that once the SPI peripheral is enabled, it doesn't allow digitalWrite() to control the pins.
That is exactly what I tried. :) That is why my second attempt was with changing the SPI mode. I knew that would invert the clock signal.

Of course, if you look at my record here on the forum, and everywhere else, you will find I will try about anything once! Click here and read some of these. "The My Hero Project" is one of my favs. The Carnegie Hero award was my parent's fav. Personally, I don't care much about awards, only what others think of me.

fat16lib

Quote
Do you have any idea how much code size your library will add, in general?
During development of the SD.h API, I tested size using SD.h examples.

The only change to these examples was to replace the SD.h include with these two lines:
Code: [Select]

#include <SdFat.h>
SdFat SD;


Here are the results for three examples for an Uno with Arduino 1.06.  SdFat is about 1,500-2,500 smaller for flash use.  SRAM use is about the same, the 512 byte block cache dominates SRAM use.

Quote
ReadWrite.ino
SD.h:  Binary sketch size: 13,676 bytes (of a 32,256 byte maximum)
SdFat: Binary sketch size: 11,700 bytes (of a 32,256 byte maximum)

Datalogger.ino
SD.h:  Binary sketch size: 14,756 bytes (of a 32,256 byte maximum)
SdFat: Binary sketch size: 13,234 bytes (of a 32,256 byte maximum)

Files.ino
SD.h:  Binary sketch size: 14,290 bytes (of a 32,256 byte maximum)
SdFat: Binary sketch size: 11,742 bytes (of a 32,256 byte maximum)
SD.h is larger since it is a fairly complex wrapper for an old version of SdFat.

Quote
EDIT: BTW, what's your overall impression of using Free RTOS with Arduino chips? I might try it with my main board that has a mega1284 chip [certainly not the one mentioned above].
I did that port of FreeRTOS since it is very popular.  I like ChibiOS/RT a little better but FreeRTOS is a solid RTOS.

oric_dan

Quote
Of course, if you look at my record here on the forum, and everywhere else, you will find I will try about anything once! Click here and read some of these. "The My Hero Project" is one of my favs. The Carnegie Hero award was my parent's fav. Personally, I don't care much about awards, only what others think of me.
OOF! is about all I can say. Kayakers tended to carry knives to help cut themselves out of pinned kayaks [at least in the days of fiberglass boats], and nowadays backcountry skiers are starting to experiment with oxygen containers. Maybe surfers should try attaching ball peen hammers to their boards.

oric_dan

#25
Nov 02, 2014, 09:04 pm Last Edit: Nov 02, 2014, 11:56 pm by oric_dan
Bill, thanks for the additional SD info. I just tried adding SD to my mega328 RF Network program, and it's definitely toasted now. Before SD, it was 18.6KB code and 717 bytes of RAM left, but with SD added, it's about 26.5KB code and the RAM is overrun, and it hangs on bootup. Needs some wholescale dieting work now. The RFM12, RTC, SPI, and SD libraries co-opt a lot of space.

Offhand, do you know how much runtime malloc'ing will add, or is that included in your 512 byte figure?
---------------

EDIT: ok, I installed your new library, and changed the lines as indicated,
Code: [Select]
#include <SdFat.h>
SdFat SD;

The listfiles example program [changed slightly] runs fine, and the MISO line is released properly.

Stats for [modified] listfile example:
- IDE SD library: 15,986 bytes code, 1047 bytes RAM left.
- using new SdFat: 14,314 bytes code, 985 bytes RAM left.

So, all in all, just the basic SD card stuff, plus a few Serial.print() statements are eating over half the mega328 RAM.
--------------

SECOND EDIT: well, I tried putting everything together now, RFM12, DS1307 RTC, and SD card libraries, and the SD library sucks too much RAM [over 1 KB] to run the program. Back to the drawing board - probably go to my mega1284 board, and wire up SD card and RTC connections. Oh well.

rudi2014

Hello,

I am currently struggling to make work my Arduino Uno with RFID RC522 and a stand-alone micro SD card. They are both SPI, therefore share the same MISO, MOSI and SCK pins. I assigned pin 10 for SDA (Slave Select) RFID, pin 9 for RST RFID and pin 4 for CS (Slave Select) SD Card. Individually RFID and SD Card sketch work well, but when it is combined it does not work...
As per suggestion I used SdFat.h instead of SD.h and I made sure to disable RFID by making the SDA Pin High before enabling the micro SD CS pin. But the program is still not working. It stops after printing "Card Ready" on the monitor and it did not respond to any RFID Card.

Here I attach the sketch...

Any help would be appreciated
Thank you very much...

DesertEagle

#27
Dec 26, 2014, 01:39 pm Last Edit: Dec 26, 2014, 01:42 pm by DesertEagle
I think you are facing the same problem as I do. I have a RF24 module connected to nano also pin 9,10 and the SS of the SD card on pin 4. Same issue that as stand alone they are working but as soon as both MISO lines are connected the program stops.
I assume a circuit problem. I cant even measure the signal with an oszi without stopping the program. Will try an I2C communication for the sd card to fix the problem.

fat16lib

#28
Dec 26, 2014, 05:27 pm Last Edit: Dec 26, 2014, 05:31 pm by fat16lib
Quote
Will try an I2C communication for the sd card to fix the problem.
You can't connect I2C to the SD card.  The MFRC522 can communicate with I2C but the library I know about is SPI.

SD.h does have a problem with MISO.  You can cause MISO to go high-Z with SD.h by sending a byte like this while SD chip select is high.  Any value will work since SD cards only need some clocks to release MISO.

Code: [Select]
SPI.transfer(0XFF);

SdFat causes MISO to go high-Z so that is not likely the problem.  There are SD modules that won't share the SPI bus properly. The modules have a level shifter that causes a problem with MISO.

The problem with SdFat may be SPI clock rate.  SdFat has a default clock rate of 8 MHz.  The MFRC522 has a max rate of 10 MHz but may be marginal at that speed with the SD card.  The default for the MFRC522 library will be 4 MHz.  The MFRC522 library does not set the SPI clock rate before accessing the SPI bus.

You could try reducing the rate to 4 MHz for SdFat like this so both the SD and MFRC522 use 4 MHz SPI clock.

Code: [Select]
sd.begin(CS_PIN, SPI_HALF_SPEED);

You should not assume the problem is MISO unless you have proof.  Just put a voltage divider on MISO using 10k or larger resistors, one to gnd and one to 5V.  Do SD operations and then measure the voltage on MISO.  With SdFat I get 2.5 volts as expected.  I get 3.3 V with SD.h which is MISO high for an SD card.

You can fix SD.h by editing Sd2Card.cpp at about line 145 and making this mod.  The file is located here:

arduino-1.0.6\libraries\SD\utility

Code: [Select]

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


You must also make this change at about line 222
Code: [Select]

  // 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);

KrisKasprzak

I'm trying to follow the steps above

and I added the fillowing to my SD.h file and I get tons of errors.

#include <SdFat.h>
SdFat SD;

What am I doing wrong?




In file included from D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino:75:0:

C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:67:3: error: 'SdVolume' does not name a type

   SdVolume volume;

   ^

C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:75:33: error: 'SD_CHIP_SELECT_PIN' was not declared in this scope

   boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN);

                                 ^

Datalogger_v1.0.3:151: error: reference to 'File' is ambiguous

 File dataFile;

 ^

In file included from C:\Program Files (x86)\Arduino\libraries\SdFat\src/FatLib/FatLib.h:22:0,

                 from C:\Program Files (x86)\Arduino\libraries\SdFat\src/SdFat.h:28,

                 from C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:21,

                 from D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino:75:

C:\Program Files (x86)\Arduino\libraries\SdFat\src/FatLib/ArduinoFiles.h:118:7: note: candidates are: class File

 class File : public FatFile, public Stream {

       ^

In file included from D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino:75:0:

C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:33:7: note:                 class SDLib::File

 class File : public Stream {

       ^

Datalogger_v1.0.3:151: error: 'File' does not name a type

 File dataFile;

 ^

D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino: In function 'void WriteHeader()':

Datalogger_v1.0.3:396: error: 'dataFile' was not declared in this scope

   dataFile = SD.open(filename.c_str(), FILE_WRITE);

   ^

Datalogger_v1.0.3:396: error: reference to 'SD' is ambiguous

   dataFile = SD.open(filename.c_str(), FILE_WRITE);

              ^

In file included from D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino:75:0:

C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:22:7: note: candidates are: SdFat SD

 SdFat SD;

       ^

In file included from D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino:75:0:

C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:112:16: note:                 SDLib::SDClass SDLib::SD

 extern SDClass SD;

                ^

D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino: In function 'void WriteData()':

Datalogger_v1.0.3:437: error: 'dataFile' was not declared in this scope

   dataFile = SD.open(filename.c_str(), FILE_WRITE);

   ^

Datalogger_v1.0.3:437: error: reference to 'SD' is ambiguous

   dataFile = SD.open(filename.c_str(), FILE_WRITE);

              ^

In file included from D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino:75:0:

C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:22:7: note: candidates are: SdFat SD

 SdFat SD;

       ^

In file included from D:\Arduino\Projects\Greenpower\Datalogger\Datalogger_v1.0.3\Datalogger_v1.0.3.ino:75:0:

C:\Program Files (x86)\Arduino\libraries\SD\src/SD.h:112:16: note:                 SDLib::SDClass SDLib::SD

 extern SDClass SD;

                ^

exit status 1
reference to 'File' is ambiguous
Thanks,

Kris

Go Up