Go Down

Topic: SD lib:SD.exists() returns TRUE if SD is removed (Read 14399 times) previous topic - next topic

the-fallen

Hello, I really like the new SD library, but there is the following issue:

Code: [Select]
#include <SD.h>
File myFile;
void setup() {
 Serial.begin(9600);
 Serial.print("Initializing SD card...");
 pinMode(10, OUTPUT);
 if (!SD.begin(4)) {
   Serial.println("initialization failed!");
   return;
 }
 Serial.println("initialization done.");
}

void loop() {
 if(SD.exists("testfile.txt")) Serial.println("Fiel Exists so SD seems to be in");
 else Serial.println("Fiel does NOT exists or SD is not in socket");
 delay(1000);
}


SD.exists() does return true or false, depending if the file could be found or not. But if you pull out the SD while the loop() is running, SD.exists() still returns TRUE.

Basically I like to use SD.exists() to check if a certain file is there to detect if my SD is in the socket or not because there is no other function within the SD library.

Is there any other way to make sure the SD is in the socket?
How ever, SD.exists() should not return TRUE if the file is not there for sure :)

fat16lib

The file may be found in a cached directory block.  The only sure way to detect removal of the SD is to use the SD detect switch on the SD socket.

robtillaart

Quote
The only sure way to detect removal of the SD is to use the SD detect switch on the SD socket.


Sample code?
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

fat16lib

If card detect is connected to a digital pin you enable the pull up and do a digitalRead.  You get low if the card is in the socket.

Making your app work is not so easy.  The app must know the card is going to be removed and close any files open for write.

The app then tells the user it is ok to remove the card.

If a new card is inserted, it must be initialized by calling begin().

This is no different than using removable storage with a PC or Mac.  You can't just pull a card from the socket while an app is accessing it.

the-fallen

Thanks for your suggestion.
But the SD socket I use does not have a Pin to detect that the card is present.
How ever, I think such a pin/switch is optional so shouldn't the Library be able to detect the availability of the SD itself?

But even if you think that it is unnecessary, how can I now detect that the card is present?
I am not familiar with SPI, but my idea would be to send a "test"-signal to the SD.  Googling for Arduino+SD+SPI+returned many results but until now I did not find a sample.
Any Ideas?

Thanks a lot in advance.

fat16lib

#5
Jan 10, 2011, 03:27 pm Last Edit: Jan 10, 2011, 04:43 pm by fat16lib Reason: 1
All sockets that I have seen have a card detect switch and write lock switch.  There are 11 pins on the socket.  nine go to the SD and the outside two on the side with narrow spacing are the switches.

There is no simple reliable SPI command to detect the SD card.

Card removal must be handled by the app as I stated above.  Card present is just digitalRead(CD_PIN) is low.  

Shields have no uniform connection to the switches so it is easier for the app to handle them since it is so simple.

Why have an extra begin() parameter for the CD_PIN, allocate RAM to remember the pin number so the library can return digitalRead(CD_PIN)?

MicroSD sockets also have a CD switch.  I have tested CD on the Gravitech and Adafruit micoSD breakouts.

I have not been able to make CD work on the new Arduino Enet shield.  CD and WP are connected to analog 0 and 1 with pullups.  My shield may be defective.

the-fallen

Thanks for the answer.
My CardSocket does not have this Card Detect because I had to make it myself using a mSD-to-SD adapter.
But I guess this is my problem, not a general one.
How ever, the original reason to post this Thread was the behavior of exists() ( and begin() in some way )

Let's assume I have a socket with the CardDetect pin, I pull the card out and insert it/another one again. I still need a way to detect if a File exists after that, and that is not possible if exists() reads the available files from a buffer.
And calling begin() again seems to fail. It returns FALSE because it thinks it is already initialized I guess (it would return TRUE if initialisation was successful). But there is no end() or something to destroy the object.

Digger450

That's still something that is better handled by your application.  If needed you could attach an interrupt to the CD pin and handle it that way.  But as was mentioned, if the card is pulled while an action is in process you may still have problems.

robtillaart

#8
Jan 10, 2011, 08:40 pm Last Edit: Jan 10, 2011, 08:40 pm by robtillaart Reason: 1
@fat16lib, thanx for explaining,
Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

fat16lib

You should contact the author of the SD library wrapper about SD.begin(), the lack of SD.end() and the behavior of SD.exists().

I believe the SD wrapper is a sensible way to simplify the use of SdFat.  I don't think this simplicity should be sacrificed for more features.

SD is a wrapper for my SdFat library.  If you need more features like SdVolume::cacheFlush() you can use SdFat without the wrapper.

To always flush the cache makes no sense.  the SD wrapper has already sacrificed a great deal of performance for simplicity.

See http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293975555

the-fallen

I will try to find the author. But there is no email or name written in the wrapper's files. Only the copyright points to SparkFun. Maybe I have luck on IRC.

I got a new SD socket now with the CardDetect switch/pin (finally it was in stock again). Still the wrapper is unusable if you want to remove the card from the socket because you can not de-initialize the SD object to initialize it again later.

jgc

The reason you cannot call begin repeatedly is the the root file object is still open. If you add a root.close() to the begin routine in SD.cpp then you can use begin repeatedly and verify the presence of a card.

Code: [Select]
boolean SDClass::begin(uint8_t csPin) {
 /*

   Performs the initialisation required by the sdfatlib library.

   Return true if initialization succeeds, false otherwise.

  */
 if (root.isOpen()) root.close();      // allows repeated calls
 return card.init(SPI_HALF_SPEED, csPin) &&
        volume.init(card) &&
        root.openRoot(volume);
}

Go Up