Writing to SD Card after removing and replacing it

I have a Uno R3 with an Adafruit data logger shield running an on/off time equipment monitor. The program (using SD.h) works well, but requires a restart when the card is removed to be read in a computer and then reinstalled in the shield. I would like to remove,read and replace the card when my equipment is in a predictable state of not logging any change.

I followed this previous thread

(http://forum.arduino.cc/index.php?topic=209794.0)

and believed that I could do what I wanted using SdFat.h. I can run the SdFat example “bench” on my hardware, and indeed can remove and replace the SD card with the new test appended to the end of the old after replacing O_TRUNC with O_AT_END in the open/write command in the sketch.

I successfully ported my existing code to SdFat from SD but have not been successful in getting the restart behavior of the bench test with SdFat.

I have written a simple test program to log some intervals, and if I can get this working, I should be OK with my actual program. I would appreciate some guidance as to how to get this sketch to append new data to the end of the file after a removal, read, and replace.

#include <SdFat.h>;
SdFat sd;
SdFile myFile;


unsigned long start_time; 
unsigned long current_time; 
unsigned long delta_time; 

int delta_hours; 
int delta_minutes; 
int delta_seconds; 

//set pin for data logger and UnoR3 

const int chipSelect = 10;

// set pin number for contact input
const int contactPin = 2;// the number of the switched pin

// Initialize variables for contacts open, inverted logic from PULLUP

int reading = HIGH;
int contactState= HIGH;       
int lastContactState = HIGH;   

//debounce variables
unsigned long lastDebounceTime = 0;  
long debounceDelay = 200;    

void setup () {


  pinMode(contactPin, INPUT_PULLUP);

  pinMode(chipSelect, OUTPUT);

  sd.begin(chipSelect);

  start_time=millis()/1000;

  //Setup data for first line of SD card file
  
  myFile.open("ST_log.csv",O_RDWR|O_CREAT|O_AT_END);  
  myFile.println();//line break on setup
  myFile.println("IS , WAS , DELTA_HR , DELTA_MIN , DELTA_SEC");

  //will read OPEN OPEN and 0:0:0 elapsed time on setup

  write_card(); //call function to write SD card

  // close the file:
  myFile.close();


}


void loop ()
{


  current_time= millis()/1000;

  delta_time=current_time - start_time;

  delta_hours=delta_time/3600;

  delta_minutes=(delta_time % 3600)/60;

  delta_seconds=delta_time % 60;


  // check contact state and debounce interval

  reading = digitalRead(contactPin);

  // If the state has changed
  if (reading != lastContactState) {
    // reset the debounce timer
    lastDebounceTime = millis();

  } 

  if ((millis() - lastDebounceTime) > debounceDelay ) {

    // if longer than the debounce delay 
    // if the reading has changed

    if (reading != contactState) {

      //open the file
      
      myFile.open("ST_log.csv",O_RDWR|O_CREAT|O_AT_END); 

      write_card();

      // close the file:
      myFile.close();

      contactState = reading;//assign changed reading to contactState


      //reset the elapsed time for new state
      start_time=current_time;


    } 

  } 


  lastContactState = reading;


}


void write_card (){

  //contact state and transitions

  if (reading==1) {
    myFile.print("OPEN");
    myFile.print(" , ");
  }
  if (reading==0){
    myFile.print("CLOSED");
    myFile.print(" , ");
  } 
  if (contactState==1){
    myFile.print("OPEN");
    myFile.print(" , ");
  }
  if (contactState==0){
    myFile.print("CLOSED");
    myFile.print(" , ");
  }

  myFile.print(delta_hours);
  myFile.print(" , ");
  myFile.print(delta_minutes);
  myFile.print(" , ");
  myFile.println(delta_seconds);



}

Thank you

You must close all files before removing the card. This causes buffers to be flushed and directories to be updated.

You must call sd.begin() when the card is replaced. SD cards require a sequence of initialization commands when power is applied.

You can then reopen files at end-of-file.

Thank you for your reply.

I close the file at the end of each write, so that should not be an issue.

I will wire the card detect pad on the shield to an input pin, and look for in/out/in (gnd/open/gnd). I will call sd.begin() when I detect the removal and replacement of the card.

If anyone has tried this approach and has any advice I'd appreciate the feedback.

I close the file at the end of each write, so that should not be an issue.

The write process for closing a file can take up to 200 ms so just pulling the card can corrupt the file system.

The bench and sdInfo examples work because I close the files and then write the final messages. It is then totally safe to remove the card.

I will call sd.begin() when I detect the removal and replacement of the card.

This can also fail since the switch often bounces when you insert a card.

The bench and sdInfo examples work since the user inserts the card and then types a character so there is no problem.

Thank you fat16lib.

Based on your advice I decided to make the recall of sd.begin() dependent upon a button press rather than track card removal and reinsertion. It was close as I could get to "press any key". I have used a good quality tactile feedback button with a long (200ms) software debounce delay. I have set the logic to call sd.begin() only when the switch opens after being closed.

All works well, and I can write to the end of my existing file after the card is removed and replaced and the push button is pressed and released. The shield has a nice R/W status led which gives feed back that sd.begin() took place.

I have gotten the same procedure to work with the SD library after adding a root.close to the SDClass begin in SD.cpp (http://forum.arduino.cc/index.php?topic=46969.msg339113#msg339113), but I will stick with SdFat because it is faster and uses less memory.

Thanks again for your assistance. It is a tribute to the Arduino community that an SD guru is willing to spend some time with a newbie.