Plugging/unplugging SD card [solved]

Hello everyone!
Here is what I want. First, write something to SD card. Then, unplug it for viewing on PC, plug it back in and be able to write to it again, without resetting the MCU. I have tried this:

#include <SD.h>
const byte pinSDCS= 8;//pin connected to SD's chip select
const byte pinHardwareSS=12;//ss pin of the mcu

File myFile;

void setup()
{
  Serial.begin(9035);//this stands for 9600, because I have 17 MHz crystal instead of 16

  pinMode(pinHardwareSS, OUTPUT);//ss pin must be output, otherwise spi will not work as master    
  
  Serial.println(F("type anything for a try..."));
  Wait();

  if (!SD.begin(pinSDCS)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
}

void loop()
{

  static byte cnt;
  cnt++;
  Serial.print(F("Accessing SD card... attempt "));  Serial.println(cnt,DEC);
  
  myFile = SD.open("test1.txt", FILE_WRITE);
  
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  };
  
  Serial.println(F("type anything for another try..."));
  Wait();
}

void Wait(){
  //purge input
  while(Serial.available()){Serial.read();};
  //wait for input
  while (!Serial.available());  
};

That is: wait, SD.begin, open-write-close, wait, open-write-close, wait, open-write-close, and so on.
While apparently working, it loses connection to sd card after a replug. See:
Serial log:

type anything for a try...
initialization done.
Accessing SD card... attempt 1
Writing to test.txt...done.
type anything for another try...
Accessing SD card... attempt 2
Writing to test.txt...done.
type anything for another try...
Accessing SD card... attempt 3
Writing to test.txt...done.
type anything for another try...
Accessing SD card... attempt 4
Writing to test.txt...done.
type anything for another try...

contents of test1.txt:

testing 1, 2, 3.
testing 1, 2, 3.

The card was reinserted between attempts 2 and 3. The file has 2 lines of text while it should have 4 of them.

I have also tried to reinitialize the SD for every attempt (that is, put SD.begin(...) into the loop), but that causes the initialization to fail and/or the sketch to crash on second attempt regardless of whether I reinserted the card or not.

So, what should I do to gain access to SD card after a replug?
Thanks in advance!

It will need reinitialising. That's one of the things SD.begin(...) does.

An SD card starts off at power-up in the proprietary 4-bit SD interface mode. Special commands set it into the easier to use SPI mode. This is the first thing the initialisation routine does.

When you unplug the card and plug it back in again it will have reset itself into the 4-bit SD mode, so will no longer be able to communicate.

You can try calling SD.begin(...) again before you open the file and see if that helps. Of course, if the SD card hasn't been removed in the mean time, then the second SD.begin() may fail.

Ideally you would use an SD socket with a presence detect switch and only do the reinitialisation once you detect that the card has been removed and reinserted.

Thanks for a reply!
I have tried to reinitialize after a replug, but it still fails.
I do have a presence switch, and I can and do use it (this is a simplified sketch, only used for testing purposes). Here, I can emulate this switch by typing into serial at correct moments, but no, it doesn't help.

The code with reinitialization:

#include <SD.h>
const byte pinSDCS= 8;//pin connected to SD's chip select
const byte pinHardwareSS=12;//ss pin of the mcu

File myFile;

void setup()
{
  Serial.begin(9035);//this stands for 9600, because I have 17 MHz crystal instead of 16

  pinMode(pinHardwareSS, OUTPUT);//ss pin must be output, otherwise spi will not work as master    
  
  Serial.println(F("type anything for a try..."));
  Wait();

}

void loop()
{

  if (!SD.begin(pinSDCS)) {
    Serial.println("initialization failed!");
    Wait();
    return;//the loop will repeat
  }
  Serial.println("initialization done.");

  static byte cnt;
  cnt++;
  Serial.print(F("Accessing SD card... attempt "));  Serial.println(cnt,DEC);
  
  myFile = SD.open("test1.txt", FILE_WRITE);
  
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  };
  
  Serial.println(F("type anything for another try..."));
  Wait();
}

void Wait(){
  //purge input
  while(Serial.available()){Serial.read();};
  //wait for input
  while (!Serial.available());  
};

By the way, I forgot to mention. I have my very own board that is not an Arduino. It's atmega644pa. It's not even a Sanguino, I have defined my own pin mapping. In order to make SD library work, I had to modify it: I changed the pin map file arduino-1.0.3\libraries\SD\utility\Sd2PinMap.h . I wonder, maybe there is some other place I have to update... I would greatly appreciate if someone tests it on real Arduino (I don't own one :frowning: )

Is it the reinitialisation that fails (Serial.println("initialization failed!"):wink: or the writing to the card after initialisation?

type anything for a try...
initialization done.
Accessing SD card... attempt 1
Writing to test.txt...done.
type anything for another try...
initialization failed!
initialization failed!
initialization failed!
initialization failed!
initialization failed!
initialization failed!
initialization failed!

Then there is probably something in the begin() routine that can only be done once - any subsequent calls will fail. What that could be is anyone's guess.

What is needed is an SD.end() function that undoes everything that's been done in SD.begin()...

I did it! I've made it!
I had to modify SD library code again.
The recipe:

  1. in SD.h, delete the line:
    extern SDClass SD
  2. in SD.cpp, find all "SD." and replace with "this->" (there is just one occurence)
    2.2)u[/u] in SD.cpp, delete the line "SDClass SD;"
  3. modify my code, since there is no global SD object anymore:
#include <SD.h>
const byte pinSDCS= 8;//pin connected to SD's chip select
const byte pinHardwareSS=12;//ss pin of the mcu

File myFile;

void setup()
{
  Serial.begin(9035);//this stands for 9600, because I have 17 MHz crystal instead of 16

  pinMode(pinHardwareSS, OUTPUT);//ss pin must be output, otherwise spi will not work as master    
  
  Serial.println(F("type anything for a try..."));
  Wait();

}

void loop()
{
  SDClass SD; //modification!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  if (!SD.begin(pinSDCS)) {
    Serial.println("initialization failed!");
    Wait();
    return;//the loop will repeat
  }
  Serial.println("initialization done.");

  static byte cnt;
  cnt++;
  Serial.print(F("Accessing SD card... attempt "));  Serial.println(cnt,DEC);
  
  myFile = SD.open("test1.txt", FILE_WRITE);
  
  if (myFile) {
    Serial.print("Writing to test.txt...");
    myFile.println("testing 1, 2, 3.");
    myFile.close();
    Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  };
  
  Serial.println(F("type anything for another try..."));
  Wait();
}

void Wait(){
  //purge input
  while(Serial.available()){Serial.read();};
  //wait for input
  while (!Serial.available());  
};

It looks like destroying the old SD object helps. Now I am going to c++ tutorials to find out if I can destroy-and-recreate the global SD, since this will help me return the SD library to its initial form.(apart from this, I have to have a global SD object in my real sketch anyway).

(edit) By the way, it works even if I leave the SD inserted, so I don't even need to monitor the card presence.

Hi Friend,

Could you send me your modified library?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.