SD card fails to open file to write after a day of use

Dear all,

I am sorry that this topic may be discussed a million times already, but i cant still make mine working. so please bear with me.
i have attached my code in the attachment. A pretty long one. Basically i want to "real time logging temperature and voltage in a room" for a week. I am currently using kingston SD card (4GB, FAT32). I have done an overnight run with the arduino and the data logger. The program actually still works but the logger has stopped working after 2 hours. Having done some searching on Google reveals the problem may due to memory leakage. Is there any way that i could done to solve this? Please kindly advise. Thank you very much guys!

Use the sdfat library instead of the Arduino sd library. Faster and does not leak memory.

Thank you for the advice! But i have another issue when using the SdFat library. I tested the library with the ReadWriteSdFat example. In the Serial Com, it showed "Writing to test.txt...done.", "error: opening test.txt for read failed", "SD errorCode: 0x13,0x0". When i used another SD card, same error pops up with a different error code as 0x6,0x1. Does anyone know what is the meaning about this?

Try using the utilities in the examples for sdfat to format the sd card.

Thank you for your help and replies, Marco_C! I have used Sdfat.lib while the card can now be used. However, this time when i run the program for like 24 hours with a 5 second time interval between logging, the card has stopped after 14 hours of operations, recording about 28281 data. Is this happening still related to memory leak? Or my program is too long and there isn't any memory left for the data logging stuff? Thank you guys in advice!

Hard to tell unless you post your code :wink:

Hello! The code is too long to be quoted in the message box. Marco_C, i have attached the code.txt in the first post. Would you mind to check that out? Thank you very much for your help! :smiley:

None of your code for reading from the serial port is worth anything. You test that there is at least one byte to read, and then proceed to read as much as you want, assuming that the stupid delay() call will somehow make serial data appear in time.

There are plenty of resources about for reading serial data properly (always test there there is data, stopping when the end of a packet arrives, etc.). You need to find them, and fix your code.

I don't understand the memory leakage problem. If you feed the stuff direct to the SD, I can't see where there could be a memory problem. Here is what I have been using of late and it has been working continuously for days. The daily output is about 400k. Some of it is abit messy but the SD stuff might be useful.

/*
//  This Arduino sketch reads DS18B20 "1-Wire" digital
 //  temperature sensors.
 //  Copyright (c) 2010 Mark McComb, hacktronics LLC
 //  License: http://www.opensource.org/licenses/mit-license.php (Go crazy)
 //  Tutorial:
 //  http://www.hacktronics.com/Tutorials/arduino-1-wire-tutorial.html
 //  modernised, compacted, and metricated by Nick Pyner
 //  code uses Arduino LCD stuff, for shield on Freetronics EtherTen.
 //  Serial print commands are for PLX-DAQ
 
 From cosm library example and lifts from a lot of others
 particularly from Stanley in Kuala Lumpur.
 Use your own DS18B20 addresses, keys etc.
 Note that the feed id is in line 42, or somewhere nearby...
 */
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SPI.h>                  
#include <Ethernet.h>            // Ethernet 
#include <HttpClient.h>          // Cosm lib
#include <Cosm.h>                // Cosm lib
#include <PCD8544.h>             // Nokia 5110
#include <SD.h>                  // SD card
#include <string.h>              // from Date As Filename 
#include "RTClib.h"              // from Date As Filename
#include "Wire.h"                // Original RTC lib for LCD disp, SD card, and serial

#define DS1307_ADDRESS 0x68

RTC_DS1307 RTC;
static PCD8544 lcd;

File myFile;
char filename[] = "00000000.CSV";


// Custom symbols
static const byte DEGREES_CHAR = 1;
static const byte degrees_glyph[] = { 0x00, 0x07, 0x05, 0x07, 0x00 };
static const byte SLASH_CHAR = 2;
static const byte slash_glyph[] = {0x00,0x20,0x10,0x08};

byte InThermo[8] =  {
  0x28, 0x69, 0xC2, 0xB0, 0x03, 0x00, 0x00, 0X9F};
byte OutThermo[8] = {
  0x28, 0x7A, 0x8B, 0xC0, 0x03, 0x00, 0x00, 0x2F};
byte DrainThermo[8] = {
  0x28, 0x09, 0xA9, 0xC0, 0x03, 0x00, 0x00, 0x95}; 

#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

byte mac[] = { 
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

char cosmKey[] = "l6 tralala Zz0g";

int  second, minute, hour, weekDay, monthDay, month, year;

int k=0;
float InTemp, OutTemp, DrainTemp;    // used for SD write only

// Define the strings for our datastream IDs
char sensorId0[] = "InThermo";
char sensorId1[] = "OutThermo";
char sensorId2[] = "DrainThermo";
char calcId1[] = "diff";

const int bufferSize = 140;
char bufferValue[bufferSize]; // enough space to store the string we're going to send
CosmDatastream datastreams[] = {
  CosmDatastream(sensorId0, strlen(sensorId0), DATASTREAM_FLOAT),
  CosmDatastream(sensorId1, strlen(sensorId1), DATASTREAM_FLOAT),
  CosmDatastream(sensorId2, strlen(sensorId2), DATASTREAM_FLOAT),
  CosmDatastream(calcId1, strlen(calcId1), DATASTREAM_FLOAT),
};
// Finally, wrap the datastreams into a feed
CosmFeed feed(83153, datastreams, 4                                   /*put your number here */);

EthernetClient client;
CosmClient cosmclient(client);

void setup() {
   lcd.begin(84, 48);
     // Register the custom symbols...
  lcd.createChar(DEGREES_CHAR, degrees_glyph);
  lcd.createChar(SLASH_CHAR, slash_glyph);
  Wire.begin();
  Serial.begin(9600);
  Serial.print("    filename   ");
  delay(300);//Wait for newly restarted system to stabilize
  lcd.setCursor (0,0);
  lcd.print("Initializing");
  delay(2000);
  lcd.setCursor (0,1);

  pinMode(10, OUTPUT);

  if (!SD.begin(4)) 
  {
    lcd.print("failed!");
    delay (2000);
    return;
  }
  lcd.print("init. OK!");
  delay(2000);
      getFileName();
      Serial.println(filename);
  lcd.clear();

  Serial.println("LABEL,Time,InTemp,OutTemp,diff,DrainTemp");

  sensors.setResolution(InThermo, 12);
  sensors.setResolution(OutThermo, 12);
  sensors.setResolution(DrainThermo, 12);

  Serial.println("Starting multiple datastream upload to Cosm...");
  Serial.println();

  while (Ethernet.begin(mac) != 1)
  {
    Serial.println("Error getting IP address via DHCP, trying again...");
    delay(10000);
  }
}

void loop() {
   running();
  GetClock();
  if (hour == 0 && minute == 0 && second <2)
  {
    getFileName();
  }
 Serial.print("DATA,TIME,       "); 
  int ret=0;
  //get the values from the DS8B20's 
  sensors.requestTemperatures();

  float InTemp = (sensorValue(InThermo));
  float OutTemp = (sensorValue(OutThermo));  
  float DrainTemp = (sensorValue(DrainThermo)); 

  float diff = OutTemp - InTemp;

  datastreams[0].setFloat(InTemp);
  datastreams[1].setFloat(OutTemp);
  datastreams[2].setFloat(DrainTemp);
  datastreams[3].setFloat(diff);
  Serial.print(InTemp);
  Serial.print(" ,  ");
  Serial.print(OutTemp);
  Serial.print(" ,  ");
  Serial.print(DrainTemp);
  Serial.println(" ,  ");

  lcd.setCursor(49,0);
  lcd.print(InTemp);
  lcd.setCursor(49,1);
  lcd.print (OutTemp);
  lcd.setCursor(49,2);
  lcd.print(DrainTemp);

  k=k+1;  

  if (k>9 )
  {   
      ret = cosmclient.put(feed, cosmKey);    // SEND FEED TO COSM
      
      myFile = SD.open(filename, FILE_WRITE);//<<<<<<<<<<<<< OPEN
  myFile.print(hour);
  myFile.print(":");
  myFile.print(minute);
  myFile.print(":");
  myFile.print(second);
  myFile.print(",");

  myFile.print(InTemp);
  myFile.print(",");
  myFile.print(OutTemp);
  myFile.print(",");
  myFile.print(DrainTemp);
  myFile.print(",");
  myFile.println();
       myFile.close();//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>CLOSE
       
      k=0;
  }
  delay(850);
}  // loop ends here

//sensorValue function
float sensorValue (byte deviceAddress[])
{
  float tempC = sensors.getTempC (deviceAddress);
  return tempC;
}

byte bcdToDec(byte val)  {
  // Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void GetClock(){
  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);
  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDRESS, 7);

  second = bcdToDec(Wire.read());
  minute = bcdToDec(Wire.read());
  hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  monthDay = bcdToDec(Wire.read());
  month = bcdToDec(Wire.read());
  year = bcdToDec(Wire.read());
}

void getFileName(){

  DateTime now = RTC.now();

  filename[0] = (now.year()/1000)%10 + '0'; //To get 1st digit from year()
  filename[1] = (now.year()/100)%10 + '0'; //To get 2nd digit from year()
  filename[2] = (now.year()/10)%10 + '0'; //To get 3rd digit from year()
  filename[3] = now.year()%10 + '0'; //To get 4th digit from year()
  filename[4] = now.month()/10 + '0'; //To get 1st digit from month()
  filename[5] = now.month()%10 + '0'; //To get 2nd digit from month()
  filename[6] = now.day()/10 + '0'; //To get 1st digit from day()
  filename[7] = now.day()%10 + '0'; //To get 2nd digit from day()

  myFile = SD.open(filename, FILE_WRITE);
  myFile.close();
}
void running(){
  
  lcd.setCursor(0,0);
  lcd.print("In");
  lcd.setCursor(31,0);
  lcd.print("\001C ");
  lcd.setCursor(0,1);
  lcd.print("Out");
  lcd.setCursor(31,1);
  lcd.print("\001C ");
  lcd.setCursor(0,2);
  lcd.print("Drain");
  lcd.setCursor(31,2);
  lcd.print("\001C ");
  lcd.setCursor(0,3);
  lcd.print("F");
  lcd.setCursor(5,3);
  lcd.print("l");
  lcd.setCursor(10,3);
  lcd.print("ow");
  lcd.setCursor(24,3);
  lcd.print("l");
  lcd.setCursor(28,3);
  lcd.print("\002");
  lcd.print("m");
  lcd.setCursor(39,3);
  lcd.print("i");  
  lcd.setCursor(44,3);
  lcd.print("n");
  lcd.setCursor(14,4);
  lcd.print("Conv %");
  lcd.setCursor(21,5);
  lcd.print("kW");

}

void standing(){
 lcd.setCursor(10, 0);
  lcd.print("kWh");
  lcd.setCursor(6,1);
  lcd.print("PREVIOUS DAY");
  lcd.setCursor(0,2);
  lcd.print("kWh");
  lcd.setCursor(0,3);
  lcd.print("kW max");
  lcd.setCursor(0,4);
  lcd.print("max flow");
    lcd.setCursor(0,5);
  lcd.print("max rise");
  lcd.setCursor(66,5);
  lcd.print("54");
  lcd.setCursor(77,5);
  lcd.print(".");
  lcd.setCursor(79,5);
  lcd.print("9");
 }

Thank you Nick for the code you posted.It helped me in a project of mine.Cheers :slight_smile:

Hi all,

I am sorry for the late reply. I have been troubleshooting the SD shield lately and it has continued to work for a week. I am no programming or Arduino expert. But here is what i have done in the code to solve it. I hope it helps even if it may not make sense. :smiley:

myFile=SD.open("test.txt");
if(myFile){
Serial.println("test.txt:");
if(myFile.available()){
Serial.write(myFile.read());
}
myFile.close();
}
else {Serial.println("error opening test.txt");}

The code does nothing new but after each write, it reads the SD card. In doing so, the SD card seems to be able to communicate with Arduino without problems. Thank you for everyone's inputs!