Unable to open file to write on a SD card

Hi all,

I am trying to write to an SD card every second to store an array of data from sensors, however, my code has a bug where the file cannot even be opened.

In my main.ino loop, I call the function reportSD() which runs a program in SD.cpp to check to see if one second has passed, if so, then it runs the function saveToSD() in SD.cpp.

Here is my main.ino code:

#include "command_parser.h"
#include <Wire.h>
#include "RTC.h"
#include "SDCard.h"

void setup() {

  //Begin serial communications
  Serial.begin(SERIAL_BAUD);
  //Call setup funcs
  setupSerialParser();
  initRTC();
  Serial.println(F("Parser ready"));
}

void loop() {

    //check for new serial data and parse if necessary
  checkSerial();
  //handle atSci requests
  checkRequests();
  reportRTC();
  reportSD();
}

Here is my SD.cpp code, I am aware that I am not writing anything to the card using myFile.print(), but it fails at the if(myFile) line the first iteration, and then I receive "initialization failed" after the first iteration :

#include <Wire.h>
#include "Arduino.h"
#include <SPI.h>
#include <SD.h>
#include "RTC.h"

File myFile;

unsigned long SDTimer = 0;

void reportSD(){
  //if we should report temps, check timers and update.
    if(millis() - SDTimer > 1000){
      saveToSD();
      SDTimer = millis();
    }
  return;
}

void saveToSD(){
    const int chipSelect = 10;
    if (!SD.begin(chipSelect)) {
    Serial.println("initialization failed!");
    return;
  }
  Serial.println("initialization done.");
  
// open the file. note that only one file can be open at a time,
  // so you have to close this one before opening another.
  myFile = SD.open("test.txt", FILE_WRITE);

  // if the file opened okay, write to it:
  if (myFile) {
    for (int i = 0; i < 3; i++) {
      Serial.print(int(serial_results[i]));
      if(i != 2){
        Serial.print(":");
    }  
  }

  Serial.print("\t");

  for(int i = 3; i < 10; i++){
    Serial.print(serial_results[i]);
    Serial.print(", ");
  }
  Serial.println("");
  myFile.close();
  Serial.println("done.");
  } else {
    // if the file didn't open, print an error:
    Serial.println("error opening test.txt");
  }
}

This is what my Serial monitor output shows...real strange how it initializes properly the first time around, then it fails at if(myFile) and the next loop it cannot even initialize...any thoughts?

Parser ready
 | 
initialization done.
error opening test.txt
 | 
initialization failed!
 | 
initialization failed!
 | 
initialization failed!

I can run the saveToSD code in a separate .ino file just fine.

#include "SDCard.h"

Is this a library for SD card? I only ask because I have never heard of it.

Nick_Pyner:

#include "SDCard.h"

Is this a library for SD card? I only ask because I have never heard of it.

No, it's my custom library. The actual SD library is called where I'm using it #include <SD.h> in the second code snippet. That code snippet is my SDCard.cpp file (with its header file being SDCard.h).

At this point i think it's because I'm calling to write to it every 1 second, I'm starting to believe that since I'm trying to open it so fast, that the card doesnt have time to open, write, and close all in that time period.

I'm away from my work computer, but that seems the most logical reasoning. What do you think?

jlewallen18:
What do you think?

Since you ask, I think you are struggling to re-invent the wheel, for no good purpose, and are well on the way to getting a square one.

For starters, as I understand it, the SD library is a minimal subset of the SDFat library. If you want to do this just as an intellectual exercise, and nobody will argue about that, you a probably better off looking at the parent rather than the child, and thereby possibly find some better purpose to what you are doing.

Further, one second is one hell of a long time to deal with the amount of data you seem to be handling. It should be the least of your problems,there is no logic in it whatsoever, and blaming the system is absurd..

Nick_Pyner:
Since you ask, I think you are struggling to re-invent the wheel, for no good purpose, and are well on the way to getting a square one.

For starters, as I understand it, the SD library is a minimal subset of the SDFat library. If you want to do this just as an intellectual exercise, and nobody will argue about that, you a probably better off looking at the parent rather than the child, and thereby possibly find some better purpose to what you are doing.

Further, one second is one hell of a long time to deal with the amount of data you seem to be handling. It should be the least of your problems,there is no logic in it whatsoever, and blaming the system is absurd..

Ok so. I'm not blaming the system, I'm blaming my code because I thought I was improperly handling how SD card writing would work. (aka I'm blaming myself)

Next, I am basically, copy-pasting the exact SD card read/write example they provide in their own library. I can get it working by itself but just not in my entire project code. So I don't know how I'm re-inventing the wheel.

How would you approach this?

I have sensors that are updating information to the serial monitor every second and I would also like to save this exact data to an SD card as well. This was not something I'm doing just for an exercise, this was the project requirement I have been assigned to for work.

jlewallen18:
How would you approach this?

I have sensors that are updating information to the serial monitor every second and I would also like to save this exact data to an SD card as well. This was not something I'm doing just for an exercise, this was the project requirement I have been assigned to for work.

I would approach this by by first appreciating that what I want to do is absolutely normal, and developing a custom library for this is absolutely the height of absurdity. I would then learn to use the SD library graciously provided by the powers-that-be at Arduino, just like everybody else does, and ditch all that other junk. There would have to be bazillion examples of datalogging to terminal and SD around, including the examples in the IDE.
One example is
http://homepages.ihug.com.au/~npyner/Arduino/Basic_3x_DS18B20.ino

Nick_Pyner:
I would approach this by by first appreciating that what I want to do is absolutely normal, and developing a custom library for this is absolutely the height of absurdity. I would then learn to use the SD library graciously provided by the powers-that-be at Arduino, just like everybody else does, and ditch all that other junk. There would have to be bazillion examples of datalogging to terminal and SD around, including the examples in the IDE.
One example is
http://homepages.ihug.com.au/~npyner/Arduino/Basic_3x_DS18B20.ino

I'm not re-creating a whole new library, I should mention. I am using an example straight from the guys that created the SD.h library. It's literally word for word, just in my code. We're clearly on different wavelengths here.

In my loop, I simply call to the reportSD() function contains the SAME exact code from the SD.h example (which by itself works fine). I'm not developing a brand new library or anything of that sense at all! The only difference is that the data that im receiving is updated every 1 second, so I wrote a little function that only saves the data to SD card every 1 second so I dont get duplicate data.

You can not make multiple calls to SD.begin(). See http://forum.arduino.cc/index.php/topic,66415.0.html

I don't know why your file won't open the first time, but the later "initialization failed" is due to the multiple calls to SD.begin() in the function. The working library example code, calls it only once in setup().

jlewallen18:
I'm not re-creating a whole new library, We're clearly on different wavelengths here.

Possibly explained by this

No, it's my custom library.

and this

Here is my SD.cpp code

and possibly even this

#include "command_parser.h"

which I have never seen before, but may be just archaic, and most certainly by this

#include "SDCard.h"

which emphatically calls for a new library, for which you have already claimed authorship.

Your intentions are still rather incoherent but, if you want to record data to SD or anything on the second but irrespective of the rate of aquisition, all you need do is check for change of second, and do it if it has.

  GetClock();
  if (pip != second)
  {
   pip = second;
   SDprint();

Another option is to simply compare new data against old, which would be irrespective of the time it is aquired, using the same method as above. Both control methods are in the loop, and the SD library remains virgo intacto. The whole idea of libraries is that they stay in that state. It may be that your real problem is simply one of improper loop timing.

Nick_Pyner:
Possibly explained by thisand thisand possibly even this which I have never seen before, but may be just archaic, and most certainly by this which emphatically calls for a new library, for which you have already claimed authorship.

Your intentions are still rather incoherent but, if you want to record data to SD or anything on the second but irrespective of the rate of aquisition, all you need do is check for change of second, and do it if it has.

  GetClock();

if (pip != second)
  {
  pip = second;
  SDprint();



Another option is to simply compare new data against old, which would be irrespective of the time it is aquired, using the same method as above. Both control methods are in the loop, and the SD library remains virgo intacto. The whole idea of libraries is that they stay in that state. It may be that your real problem is simply one of improper loop timing.

Obviously the syntax I used was wrong, so I apologize for that. The project itself is very large so I thought the best decision would be to separate the code into smaller more "bite-sized" and easier to follow chunks. I simplified much of the code for the sake of this forum post which is proving to be difficult to explain now.

I am storing all data into a global array variable that I can access between all sensor cpp files. One thing I have not tried is to place the SD card write function within the arduino .ino file instead ( i tested it in a completely separate .ino successfully). So assuming I can access that variable, then maybe that will be my fix.

I'm sure there is no point in asking why you are storing data in a global array, I thought I understood that you were trying to store the data on an SD card. Equally, there is no point in asking why you insist on fartarsing with cpp files, thereby deserving all the grief you get. About the only sensible thing that has come out of this is that you at least recognise that

One thing I have not tried is to place the SD card write function within the arduino .ino file

and that doing so might be a good idea. I think you are probably right about that. It is, after all, exactly what everybody else does - as is amply demonstrated in the aforementioned examples.

In the example I directly alluded to, you probably haven't noticed that the data is fed to both serial and SD, and the procedures for doing so are more or less the same. I'm betting your biggest problem is explaining why those procedures should be different.

It's my understanding that OP is just splitting a bigger project into multiple cpp/h files; nothing wrong with that.

sterretje:
It's my understanding that OP is just splitting a bigger project into multiple cpp/h files; nothing wrong with that.

this is precisely what I am doing :slight_smile: Actually this was the state of the project that was given to me when I started the job and it works really well.

Nick, I'm storing the variables in a global array so that all I have to do is loop through the array and print each element in that array. This helps me format the output since I have so many different sensors and readings I need to display. What you are seeing in the current print loop would be something like this:

[10:23:54 74.6, 50, .....and so on]

First column being the time, second being temperature, third being humidity. This was just my thought process and it's printing to the screen just fine. I just am struggling with the SD card writing.

Did you fix the problem pointed out in reply#7 with saveToSD() calling begin() multiple times?

cattledog:
Did you fix the problem pointed out in reply#7 with saveToSD() calling begin() multiple times?

somehow missed your reply, thanks for the suggestion! I'll give this a shot when I show up to work tomorrow. Is it ok to SD.begin() in the setup loop of my main .ino and then open/close in a separate cpp?

Is it ok to SD.begin() in the setup loop of my main .ino and then open/close in a separate cpp?

I would think so, but there maybe something else wrong with your code you got an error opening the file on the very first call.

You have not posted the SDCard.h file which goes with the .cpp.

I agree with Nick_Pyner on this, and think that you are over encapsulating to the point at which you have made problems for your self.

You can functionalize what you want in the main line code, and I really do not see why you want to change the standard structure with the leading #includes, the File object creation, and then .begin() in setup() .

cattledog:
I would think so, but there maybe something else wrong with your code you got an error opening the file on the very first call.

You have not posted the SDCard.h file which goes with the .cpp.

I agree with Nick_Pyner on this, and think that you are over encapsulating to the point at which you have made problems for your self.

You can functionalize what you want in the main line code, and I really do not see why you want to change the standard structure with the leading #includes, the File object creation, and then .begin() in setup() .

Hey, the SDCard.h file only defines the functions like this:

void reportToSD(void);
void saveToSD(void);

that's it, there isn't any other code in there at the moment. Since the project is so large, I wanted to continue the trend of modularizing where I can and simplifying the main loop as much as possible. I can't say I'm too experienced with coding, but back in my Uni days my prof would always mention that keeping the main loop as simple as possible is the best way to go.

Really do appreciate the insight and I'll post back here tomorrow when I move the SD.begin() to the setup() loop of my main.ino

jlewallen18:
Nick, I'm storing the variables in a global array so that all I have to do is loop through the array and print each element in that array. This helps me format the output since I have so many different sensors and readings I need to display. What you are seeing in the current print loop would be something like this:

[10:23:54 74.6, 50, .....and so on]

First column being the time, second being temperature, third being humidity. This was just my thought process and it's printing to the screen just fine. I just am struggling with the SD card writing.

It may be OK to do that, but I can't see the point. It seems to me that you are simply running datalogger, and it is probably like any other datalogger. A typical pseudo code for which might be

loop(){
get time;
get data;
Serial.print(time);
Serial.println(data);
myFile = SD.open(filename, FILE_WRITE);
  myFile.print(time);
  myFile.println(data);
myFile.close();
}

interspersed with colons and commas as required, i.e. format as you print. I don't think it makes one jot of difference how many sensors you've got, the principle is the same - get it, print it - and what you show

10:23:54 74.6, 50, .....and so on

is absolutely normal, no matter how much the so is on.

cattledog:
I would think so, but there maybe something else wrong with your code you got an error opening the file on the very first call.

You have not posted the SDCard.h file which goes with the .cpp.

I agree with Nick_Pyner on this, and think that you are over encapsulating to the point at which you have made problems for your self.

You can functionalize what you want in the main line code, and I really do not see why you want to change the standard structure with the leading #includes, the File object creation, and then .begin() in setup() .

After your fix for moving SD.being to the setup(), I discovered that it was also a SRAM shortage issue. I've been adding the F() macro to Serial.print statements and have gained a considerable amount of SRAM. And lo and behold, we have a functioning SD card in the SDCard.cpp. Thanks for the help :slight_smile: