Wondering if you could give me a hand. I've built a testing rig that records the time it takes to extend and retract a pneumatic cylinder. I'm running into issues logging the data. When I tested the system out for 4 hours, it logged the data no problem. After an 8 hour run I had an SD with that appeared to stop logging after 3-4 minutes. I couldn't get the system to log any data to the SD card. I troubleshooted, reformatted the SD card, and reset and reloaded the sketch, it appeared to fix the issue. Let it run over night and no data, not even a CSV file this time. I'm a bit at a loss. I checked the HiLetgo spec, its 5V in on VCC, the specs say it had a converter for 3.3 for the SD card itself. CS is wired to P10. I have a wiring diagram but I'm not allowed to upload yet.
#include <Arduino.h>
#include <SD.h>
#include <SPI.h>
const int relayPin = 8; //Relay for Control Solenoid
const int ExtPin = A3; //Extension Switch Signal
const int RetPin = A1; //Retraction Switch Signal (home)
const int StSpPin = 7; //Start Stop Button
const int chipSelect = 10; //SD Module CS line
bool isRunning = false; //Flag system running
bool stopRequested = false; //Flag stop request
unsigned long startTime; //Start time
unsigned long extensionTime; //Cyl ext. time
unsigned long retractionTime; //Cyl ret. time
enum CylinderState { IDLE, EXTENDING, RETRACTING, RETURN_TO_HOME };
CylinderState state = IDLE; //Initial state to idle
//Initial Pins and SD card
void setup() {
pinMode(relayPin, OUTPUT);
pinMode(ExtPin, INPUT); //4-5V input on trigger
pinMode(RetPin, INPUT); //4-5V input on trigger
pinMode(StSpPin, INPUT_PULLUP); //Switch to ground
Serial.begin(9600);
if (!SD.begin(chipSelect)) {
Serial.println("SD Card Missing or Error");
isRunning = false;
while (1); //Stop if SD card missing or issue
}
Serial.println("System Ready");
}
void loop() {
// Start top button handling
if (digitalRead(StSpPin) == LOW) {
delay(500); //Deadbounce delay
if (isRunning) {
stopRequested = true; //Set stop flag if system is running
Serial.println("Stop Requested");
} else {
isRunning = true; //Start system if not running
Serial.println("Starting System");
state = digitalRead(RetPin) == HIGH ? IDLE : RETURN_TO_HOME; //Check if cylinder is at home position. Pin 4 high
delay(2000); // Delay before starting cycle
}
while(digitalRead(StSpPin) == LOW);
}
//States of cylinder control
if (isRunning) {
switch (state) {
case RETURN_TO_HOME:
Serial.println("Returning to Home");
// Checking if cylinder is at home position
if (digitalRead(RetPin) == HIGH) {
state = IDLE; //Switch to idle if cylinder is at home position
Serial.println("Reached Home: IDLE State");
}
break;
case IDLE:
//Check if stop is requested
if (stopRequested) {
isRunning = false; //Stop
stopRequested = false;
Serial.println("System Stopped");
} else {
state = EXTENDING; //Switch to Ext state
digitalWrite(relayPin, HIGH); //Trigger relay on for pneumatic solenoid
Serial.println("Extending Cylinder");
startTime = millis(); //Record start time of extensions
}
break;
case EXTENDING:
if (digitalRead(ExtPin) == HIGH) {
extensionTime = millis() - startTime; //Calc extension time
Serial.print("Extension Time: ");
Serial.println(extensionTime);
delay(2000); //Pause between cycle
state = RETRACTING; //Switch to retracting state
digitalWrite(relayPin, LOW); //Trigger relay off for pneumatin sold
Serial.println("Retracting Cylinder");
startTime = millis(); //Record time of retraction
}
break;
case RETRACTING:
if (digitalRead(RetPin) == HIGH) {
retractionTime = millis() - startTime; //Calculte traction time
Serial.print("Retraction Time: ");
Serial.println(retractionTime);
logData(extensionTime, retractionTime); //Record data to SD
delay(2000); //Pause Between cycle
state = stopRequested ? RETURN_TO_HOME : IDLE;
if (stopRequested) {
Serial.println("Returning to Home after Stop Request");
}
}
break;
}
} else {
digitalWrite(relayPin, LOW); //Relay off when not running
if(state != IDLE) {
Serial.println("System Idle - Cylinder Stopped");
}
}
}
//Log data to SD
void logData(unsigned long extTime, unsigned long retrTime) {
File dataFile = SD.open("datalog.csv", FILE_WRITE);
if (dataFile) {
dataFile.print(millis());
dataFile.print(",");
dataFile.print(extTime);
dataFile.print(",");
dataFile.println(retrTime);
dataFile.close();
Serial.println("Data Logged to SD Card");
} else {
Serial.println("Error with SD Card");
}
}
The relay and SD VCC are sharing the same 5V. I wouldn't suspected a voltage drop issue on the VCC since the test it run of 4 hours had no problem. I can try and split them apart.
Strange! I see code that opens the file each time you want to log. Always the same file name. Always open the write. BUT NEVER CLOSE the file. So that would seem to indicate only the last block of data is what is on the file.
In your analysis, did you find the beginning data of your test or did you find the last data of the test? Why do you NEVER close the file?
I'm assuming you mean the CS, SCK, MOSI, and MISO on the SD card. No they are each individually wires to the the Pin 10, 11, 12, 13 respectively. I also have that group of wires separate for the 5V VCC.
I do have a dataFile.close() right above the SD.println. Heres how I tested it. My bench testing I ran one cycle, extending and retracting then checked the card. It logged both times. Leaving the old file, i ran 3 more cycles, and it logged the additional cycles after the first cycles. Deleted the file, and let it run for about a minutes and counted the cycles. It had the correct amount of cycles in the file. Then cleared the data and let it run for 4 hours. Logged 1149 cycles.
Then deleted the file and did my first 8 hour run. When I went to collect the data that's when I first encountered the missing data. It only logged 87 cycles. I connected to the UNO and using the serial monitor I was getting Error with SD Card messages. Checked the wiring for loose connections, ended up reformatting the card and wiping and re-uploading the same sketch. Did some of the same test I did above running a few times and checking, had data again.
Let the machine run over night about 15 hours. No datafile this time. Just a blank folder.
Reading through some other threads they mention using no larger than a 32GB SD card. Since I'm running a 256GB could this be the issue? It seems FAT32 when larger formats as a SDXC, and this can cause an issue. I didnt see any mention of this in any of the SD library documents.
Yes, I did miss the closing of the file. However when you open and write and close the file, you NEVER get more that 512 bytes of data. You need to open ONE TIME in setup() and design your code so you CLOSE the file at the end of your recording period. Perhaps a push button.
Really, why is that. I thought it would be best to open and close the file after every write to keep. That way if there is an issue power loss or something else the file wouldn't be lost. What cause the maximum byte limit, UNO memory size?
it's OK to open - print - close but it's not optimal in terms of timing.
the SD interface writes in 512 bytes chunks. so if you open, write, write, write, .... every time you reach 512 bytes in the buffer, it issues a write to the SD. and then you close and it issues a fine write for whatever is in the buffer and closes the file.
if you just open, write and close, then you dump only a few maeaninful bytes to the SD card but you still send 512 bytes. so it's take longer than needed.
the good thing about opening, writing, closing is that if you get a crash for whatever reason, you don't loose many samples that would have been in the 512 bytes buffer and not written.
I would suggest to use the SDFat library it's more robust (the SD library is a quite old extract from the SDFat library that got stuck in time. SDFat has been evolving)
Ok I think I get what Paul and you are saying now. Each write send 512 bytes regardless. For optimization you can store than write to reduce instances. But you risk loss from a crash.
Method I'm doing is less optimal, but can be safer with data.
For this things case I'm not worried about speed with the system, latency isn't a concern, the testing rig is already cycling more frequently than the real world application. But if it was a concern it would be better to buffer then write.
flushing the data is what close() does before releasing the handle. so with flushing you would save the time it takes to open and close the file every time but you would still send 512 bytes with every flush
I'm not sure what those are. Can you explain what the examples are?
BTW so far the 32GB SDHC is logging fine. I have my laptop hooked up and using sketch monitor its writing the data. And the card has a CSV file with data in it.