SD card readiness ...

I have a small code to get a file from PC via Serial port , write it to SD card and later display it on Serial monitor when a START button is pressed. Working fine generally.

I have a peculiar problem though - at times when I press the START button immediately after the Serial monitor read completes, or immediately on boot up , I get a error “No GRPLAN.CSV” though it is very much there in the SD card. I give some time and then press START, it displays fine. This kind of is a random behaviour.

Is there a specific time to be given after every read for the SD card before I can read again ? Otherwise is there any way that I can query for readiness of the SD card before I do some operation on it ?

/*
  CODE to read from Serial port and write a GRPLAN.CSV file

  Hardware is EtherTen Board / UNO board. SD card attached to SPI bus as follows:

 ** MOSI - pin 11
 ** MISO - pin 12
 ** CLK  - pin 13  ( So this pin cannot be used for the LED connected to it.)
 ** CS   - pin 4
*/

#include <SPI.h>
#include <SD.h>
#include <phi_interfaces.h>


const int chipSelect = 4;                                   // SD card select on shield

// Define the Machine Digital Inputs and Outputs
#define StartPB 12                                          // EtherTen mapping
#define IncrPB 14
#define DecrPB 6
#define EnterPB 7
#define total_buttons 4
char mapDIN[] = {'S', 'I', 'D', 'E'};                      // This is a list of names for each button.
byte pinDIN[] = { StartPB, IncrPB, DecrPB, EnterPB};       // The digital pins connected to the 4 buttons.
phi_button_groups MyDIN(mapDIN, pinDIN, total_buttons);

char ValidDIN = '0';
const int num1Char = 150;
char receivedChars1[num1Char];
boolean writeToSD = false;

unsigned long scanMs = 10;


// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//                        SETUP
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void setup()
{
  Serial.begin(9600);
  Serial.println(F("Initializing SD card..."));           // Check if the card is present and can be initialized:

  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present"));
    return;                                               // No card .. just return..
  }
  Serial.println(F("SD Card initialized."));
  Serial.println(F("SerialToSD program ready "));
  pinMode(chipSelect, OUTPUT);

}

// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//                      MAIN LOOP
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&


void loop()
{

  ValidDIN = MyDIN.getKey();
  static int checknum = 0;
  if ( ValidDIN == 'S' )
  {
    ValidDIN = '0';
    readPlanFile();
  }

  recvWithStartEndMarkers();                        // Read data from Serial port and store to SD card..
  processNewData();

}

// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//                       FUNCTIONS
// &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

// Function to Read data in Serial buffer and load in a variable..
void recvWithStartEndMarkers()
{
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '[';
  char endMarker = ']';
  char inChar;

  if (Serial.available() > 0)
  { // Data available in In buffer ?
    while (Serial.available() > 0 && writeToSD == false )
    { // As long as there is data...
      inChar = Serial.read();                                     // Read the data and add to char array
      if (recvInProgress == true)
      {
        if (inChar != endMarker)
        { // Upon StartMarker Read char and add to Char array
          receivedChars1[ndx] = inChar;                            // till the EndMarker arrives
          ndx++;
          if (ndx >= num1Char)
          {
            ndx = num1Char - 1;                                   // To maintian fixed length records.
          }
        }
        else
        {
          recvInProgress = false;                                 // reset variable for next read..
          ndx = 0;
          writeToSD = true;
        }
      }
      if ( inChar == startMarker) recvInProgress = true ;         // Await the start marker..
    }
  }
}

// **********************************************************

// Function to write stored data in variable to SD card file..
void processNewData() {
  if ( writeToSD == true) {
    File dataFile = SD.open("GRPLAN.CSV", FILE_WRITE);       // Open the file and write to it..
    if (dataFile) {
      dataFile.println(receivedChars1);
      dataFile.close();
      Serial.println("OK");
      writeToSD = false;
    }
    else {
      Serial.println(F("Error opening GRPLAN.CSV"));
    }
  }
}
//&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

void readPlanFile()
{
  File dataFile = SD.open("GRPLAN.CSV");
  if ( dataFile )
  {
    while (dataFile.available())
    {
      Serial.write(dataFile.read());
    }
  }
  else
  {
    Serial.print( "No GRPLAN.CSV");
  }
  dataFile.close();
}

Mogaraghu:
Is there a specific time to be given after every read for the SD card before I can read again ? Otherwise is there any way that I can query for readiness of the SD card before I do some operation on it ?

First you need a correct initialization code.

In your case you seem to use a different chipselect pin with the SD card than the SPI hardware chipselect pin of the Arduino board used..

Hardware chipselect pin on your Arduino board seems to be pin-10, but you connect the SD card to:
const int chipSelect = 4; // SD card select on shield

You can do that easily. But in that case you MUST set the hardware chipselect to OUTPUT before(!) initializing your library for a different device with a different chipselect pin.

Fixed setup code:

[code]void setup()
{
  Serial.begin(9600);
  pinMode(SS, OUTPUT); // set hardware Slaveselect/chipselect to OUTPUT!
  Serial.println(F("Initializing SD card..."));           // Check if the card is present and can be initialized:

  if (!SD.begin(chipSelect)) {
    Serial.println(F("Card failed, or not present"));
    return;                                               // No card .. just return..
  }
  Serial.println(F("SD Card initialized."));
  Serial.println(F("SerialToSD program ready "));
}

[/code]

Then the SD card should be fully working afterwards. Give it a try!

jurs:
First you need a correct initialization code.

In your case you seem to use a different chipselect pin with the SD card than the SPI hardware chipselect pin of the Arduino board used…

Hardware chipselect pin on your Arduino board seems to be pin-10, but you connect the SD card to:
const int chipSelect = 4; // SD card select on shield

You can do that easily. But in that case you MUST set the hardware chipselect to OUTPUT before(!) initializing your library for a different device with a different chipselect pin.

Fixed setup code:

[code]void setup()

{
  Serial.begin(9600);
  pinMode(SS, OUTPUT); // set hardware Slaveselect/chipselect to OUTPUT!
  Serial.println(F(“Initializing SD card…”));          // Check if the card is present and can be initialized:

if (!SD.begin(chipSelect)) {
    Serial.println(F(“Card failed, or not present”));
    return;                                              // No card … just return…
  }
  Serial.println(F(“SD Card initialized.”));
  Serial.println(F("SerialToSD program ready "));
}


[/code]

Then the SD card should be fully working afterwards. Give it a try!

I understand what you are saying. And as advised moved the pinMode(chipSelect,OUTPUT) ahead of the SD card init. Does not seem to help . Look at the screen dump below. After printing the fileonce, I tired to repeat it and five times it responded with "No GRPLAN.CSV"before responding the sixth time :

See the attachment of the Serial port capture ( only the failed part ) ..

Mogaraghu:
I understand what you are saying. And as advised moved the pinMode(chipSelect,OUTPUT) ahead of the SD card init. Does not seem to help .[/code]

You don't need to set YOUR SD CARD chipselect pin to OUTPUT, but you must set the intrinsic SPI hardware chpselect pin of the Arduino board to OUTPUT. The built-in variable name for that pin is SS (accordingly to current board setting in the IDE) and when using SS the code is compatible with different Arduino boards in case you want to use a SPI device connected to a different chipselect pin than the intrinsic SPI hardware chipselect pin of the board.

pinMode(SS, OUTPUT); // set intrinsic SPI hardware Slaveselect/chipselect to OUTPUT!

Yes I agree and that’s a proper way to initialize. But my issue seems to be elsewhere. After I did the change in the init, I ran the program and intentionally held down the START button longer say for about 2 secs or more. And when I released it said No GRPLAN.CSV !! But when I just tapped the button, it printed. I can almost repeat this to happen. So now what ?

It seems to be more with something other than the SD card ? See the attachment - the number of No GRPLAN.CSV will tell the story !

Do you have any other SPI devices connected to the Arduino? Maybe an ethernet controller like a w5100?

edit: Which Arduino board are you using? Which SD card shield/module?

SurferTim:
Do you have any other SPI devices connected to the Arduino? Maybe an ethernet controller like a w5100?

edit: Which Arduino board are you using? Which SD card shield/module?

It's Etherten board from Freetronics. Basically a UNO and Ethernet Shield rolled into one.

I am right now not using the Ethernet section.

Mogaraghu:
I am right now not using the Ethernet section.

Yes, you are, whether you know it or not. Unless you disable the w5100, it is trashing up your SPI bus.

void setup() {
  // disable w5100 SPI
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

  // rest of your setup
}

Upload this code and then power down the Arduino for a few seconds to reset the SD card and w5100, then power it up. See if that doesn't help.

edit: If that doesn't solve the problem completely, you might need to slow up the SPI bus. The SD card slot on the etherten board does not use logic level converters. It uses voltage dividers instead. The capacitance of the SD card inputs may be preventing the card from working at full speed.

SurferTim:
Yes, you are, whether you know it or not. Unless you disable the w5100, it is trashing up your SPI bus.

void setup() {

// disable w5100 SPI
  pinMode(10,OUTPUT);
  digitalWrite(10,HIGH);

// rest of your setup
}



Upload this code and then power down the Arduino for a few seconds to reset the SD card and w5100, then power it up. See if that doesn't help.

Included the above. When that did not help just wanted to see the performance when the Read function called non stop. Surprisingly it was working very well - left it for more than 5 minutes and not once it reported NO GRPLAN.CSV !

Looks like it does not like the button ?? Here is the modified loop

void loop()
{

  ValidDIN = MyDIN.getKey();
  if ( ValidDIN == 'S' )
  {
    ValidDIN = '0';
    readPlanFile();
  }

  recvWithStartEndMarkers();                        // Read data from Serial port and store to SD card..
  processNewData();

  readPlanFile();                                   // For non stop repeated read ! Works fine..

}

What button? Do you have anything connected to D10 to D13? Those are SPI pins. If you are using SPI, which you are, you can't use those pins for anything else.

SurferTim:
What button? Do you have anything connected to D10 to D13? Those are SPI pins. If you are using SPI, which you are, you can't use those pins for anything else.

YES. That's it. I had connected the START push button to pin 12 :frowning:

Sorry to have wasted all your time with the stupid mistake. Too many board swaps between Mega / Uno and this thing just passed me.

Of course the moment I relieved the Pin 12 from START, the code works like magic :-)) And it is now confirmed that the SD card has no such latency after it has finished reading a file to read another file ! Good.

Thanks SurferTim .

You didn't waste my time. If it is working, it was worth it. I still make mistakes. Other users here help me find them now and then.