Writing to SD card, 0 bytes written

Hello,

I am helping my daughter with her high school project. Reading data from a sensor and logging to a text file on a micro-SD card. Logging starts when a push button is pressed and released. I am using an Arduino Uno and a Hiletgo micro-SD card reader and a micro center 64 GB card.

When I tested this setup over small periods of time, it works - writes SD card with expected data. When I let this setup run for more than about 30 min, everything appears to work - on-board LED blinks every second to indicate writing int he loop. But the test.txt file has 0 bytes. All subsequent operations for any duration, appear to fail writing. Below is the code.

I am formatting the SD card on my Mac using disk utility in FAT32 format. When I used the SD association software, it forced exFAT formatting, which appears to not work for me - file open fails.

Notable - this data is collected from athletes in the field, so no PC is involved, so I connected a 9 V power supply and don't use serial debug.

So far, reading other forum entries - I will try SDFat/SDformatter as the way to format. Also, I believe I should use SD.end() at the end. Also, not sure what's the best way to close out operation - i.e. go quiescent after the button is pressed second time. My daughter researched it and included an exit() call. I would much prefer to deterministically hang in the loop on a while(1) {}. Any advice would be greatly appreciated. My daughter is getting pretty disheartened with this experience and honestly, so am I at this point after 4-5 days of heavy work.

Regards,
Vijaykam

#include <SD.h>
#include <SPI.h>
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;  // the number of the pushbutton pin
const int ledPin = 8;  // the number of the LED pin
const long interval = 1000;  // interval at which to blink (milliseconds)const int buttonPin = 2;  // the number of the pushbutton pin
// variables will change:
bool startProcess = false;
int ledState = LOW;  // ledState used to set the LED
unsigned long previousMillis = 0;  // will store last time LED was updated
int buttonState = 0;  // variable for reading the pushbutton status
File myFile;
const int GSR=A0;
int sensorValue=0;
int gsr_average=0;

void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  if (!SD.begin(4)) {
    digitalWrite(ledPin, HIGH);
    while (1);
  }
}

void loop() {
  if (!startProcess && buttonPressAndRelease())
  {
    startProcess = true; 
    digitalWrite(ledPin, LOW);
    myFile = SD.open("test.txt", FILE_WRITE);
    if (!myFile) {
      digitalWrite(ledPin, HIGH);
      while (1);
    }  
    unsigned long mi = millis();
    myFile.print("Start: ");
    myFile.println(mi);   
  }
  else if (startProcess && buttonPressAndRelease())
  {
    startProcess = false;
    unsigned long mi = millis();
    myFile.print("Finish: ");
    myFile.println(mi);
    digitalWrite(ledPin, LOW);
    myFile.close();
    exit(0);
  }
  if (startProcess)
  {
    toggleLED();
    int data = gsrGetData();
    myFile.println(data);
  }
}

bool buttonPressAndRelease(){
  buttonState = digitalRead(buttonPin);
  // check if the pushbutton is pressed. If it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    // Confirm button is pressed - debounce
    delay(50);
    buttonState = digitalRead(buttonPin);
    if (buttonState == HIGH) {
      // Confirmed - button pressed - now wait for release
      while ((buttonState = digitalRead(buttonPin)) == HIGH) {
        delay(50);
      }
      // For now, not debouncing on release
      return true;
    }
    else {
      // Glitch - return - will catch it again
      return false;
    }
    // Should not come here
    return false;
  } 
  else {
    // Not pressed
    return false;
  }
}

void toggleLED(){ //method for blinking the LED
  if (millis() - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = millis();

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}

int gsrGetData()
{
  long sum=0;
  for(int i=0;i<10;i++)           //Average the 10 measurements to remove the glitch
  {
    sensorValue=analogRead(GSR);
    sum += sensorValue;
    delay(5);
  }
  gsr_average = sum/10;
  return gsr_average;
}

That is a clear indication that the file was not properly closed.

Instead of writing the line below to the SD card, write it to the serial monitor instead, so you have some confirmation that the close() action was at least attempted.

 myFile.print("Finish: ");

Another safety measure is to issue myFile.flush() every few minutes or hours, which updates the file pointers. That way if myFile.close() fails, you lose only the last incomplete data buffer.

Hello jremington,
Thank you for the suggestion. I am thinking of adding a flush() every few seconds. Appreciate your input. I can't debug over serial, as this is a standalone unit int eh field. But the indicator LED does go low, which is "some" sign that close() was called on file.

vijaykam

That would be a waste of time, as well as increase the SD card current consumption and error rate.

It is basically the same mistake made by most beginners, which is to open the file, write one line of data, and close it again.

Needless to say, thoroughly test and debug your SD card code before trying to collect valuable data in the field.

so I connected a 9 V power supply

Hopefully, not a 9V PP3 smoke alarm battery! That will also end in a field tragedy.

Hello!

That's exactly what I have - 9V smoke alarm battery. Can you suggest alternatives? I cannot connect an actual power supply, since kids will be running around a track with this gizmo in their hands.

vijaykam

... and a micro center 64 GB card.
Card is too big. 32gb is max.

A fresh smoke alarm battery won't last more than a few tens of minutes with many setups, especially something as power hungry as an SD card.

Some people use 5V rechargeable power banks, powering the Arduino through the 5V pin. However, many of those power banks have a minimum current draw requirement and shut down.

2x18650 Li batteries provide 7.4 V, which is enough for the Vin barrel jack of an Arduino Uno.

Hello madmark2150,

Are you saying that the Arduino is not capable of writing to a card that big? Can you clarify? If this is the main issue, I should be able to fix easily - hopefully!

vijaykam

Yep. Driver is FAT32 8.3 filenames only too. Use an 4/8/16/32 gb card.

Also sd card current demand can be over 100mA during write. 9V batt not going to cut it.

9vbatt

According to this post, the SD library can handle up to 32Gb cards.

Thanks for the suggestion. Looking at this further, I found this ...

The 9V battery will power the Arduino for about 10 hours. The AA batteries would probably power the Arduino for 40 hours, but the voltage of the batteries will start to drain before that, so it might be less than 40 hours for 4 AA batteries.

I am only looking for the battery to last up to 1.5 hours. I imagine the SD card is not a huge drain - it does not get warm. Will put an ammeter on it at work.

Cheers,
vijaykam

Not a chance.

I imagine the SD card is not a huge drain

In fact, SD cards can draw up to a couple hundred mA during buffer write. You have a common misconception.

Good luck with your project!

Look at 9v load discharge graph (above).
1/2 of 9v power is lost by vregulator down converting to +5v.
Times shown in your referrnce is with NO LOAD running Arduino only - no I/O devices.
Like I said, sd card pulls over 100mA during write!

Okay, okay I get it. So I should be able to gang up a 4xAA batteries to get this done right? If I understand correctly, it will have 1.5x4=6 V and not loose too much power regulating down to 5 V. That should be able to get me 1.5 hours of SD card capture, hopefully?

vijaykam

7805 vreg needs ~1.5v to operate so 6v is marginal ... use 9v, but in AAx6 or AAAx6.

Hello jremington,

Going back to
2x18650 Li batteries provide 7.4 V, which is enough for the Vin barrel jack of an Arduino Uno.

I don't see anything online that offers a barrel jack for UNO. They are all USB - I guess I need to pick one that is intelligent enough to know when to act as a power source and when to act as power drain? Please educate me. I should be able to connect to the USB jack of UNO.

Thanks,

vijaykam

Only collect data in the field while leaving the SD unpowered until you insert a jumper and press a button to dump the data to file.

It is the black cylinder on the Uno R3, also called the "Power Jack". The input is "Vin" on all Arduinos. Allowed input voltage is 7-12V, the closer to 7 the better.

Hello jremington,

Thanks for your continued - patient - explanations! I meant to say, I didn't see any 18650 battery holder arrangements that had a barrel jack connector output. After doing more digging I did find something that would plug into the USB connector and apparently is good for powering the UNO.

I figured I would use a simpler arrangement. I am getting a 6xaa holder with a barrel jack connector. I am aiming to populate it with AA sized NiMH rechargeable batteries. At 1.25 volts each, they will gang up to 7.5 V. Their ratings are over 2000mAh. Hopefully this will get us over the finish line. Would appreciate your and other experts' feedback on this.

vijaykam

Of course not. You buy the barrel jack plug (or cut one from a discarded charger cable) and solder a pair of wires between it and the battery holder, or directly to the batteries themselves, if they have solder tabs. It is at most a 10 minute operation.

Discarded laptop battery packs almost always have several good 18650 batteries, with solder tabs, free for the harvesting.

This is a DIY technical forum!