Hello everyone,
I have a FSM that is designed to record two samples to a file on the SdCard at 20-Hz. For the most part the program runs without any issues except I occasionally get some outliers of +200ms in post processing review. It is random and can show up in sample sizes ranging from 500 samples to 28,000 samples. I am sure it is something in my code but I don’t know where I should focus. This is my first time using SdCards so I thought it would be best to post here.
Some information on the project:
- Board: Arduino Uno
- SdCard Shield: Adafruit Datalogging Shield
- SdCard: Toshiba 2GB SD-C02G JAPAN
File Structure Format:
millis(), ADC Value 1, ADC Value 2
I am checking the frequency by performing millis()n+1-millis()n in post processing and this is where I am finding the anomalies.
Am I misunderstanding the buffer therefore causing the issue? Or is it something unrelated to SdCard use in general?
// Libraries
#include <SdFat.h>
#include <RTClib.h>
RTC_PCF8523 rtc;
enum state {
_readState,
_displayState,
_createState,
_bufferState,
_writeState,
_errorState
};
state _currentState;
// Declare Variables
struct sample {
char* _name;
const int pin; // Input pin
unsigned int raw; // Raw value
float value; // Calculated value
};
sample Val1 = {"Val1", 2, 0, 0}; // Voltage range 0.5 - 4.5 VDC
sample Val2 = {"Val2", 3, 0, 0}; // Voltage range 0.0 - 5.0 VDC
const int ledRecord = 6;
const int pinSwitch = 7;
const int ledRead = 8;
const int ledError = 9;
const int pinSD = 10;
unsigned long currentMillis; // Used for storing the latest time
unsigned long previousMillis = 0; // Store the last time the program ran
const unsigned long interval = 50; // Sample frequency (milliseconds)
int pinState;
String filename;
char _header[20];
SdFat SD;
File dataFile; // SD Card
String buffer; // String to buffer output
void setup() {
// Start serial
Serial.begin(57600);
while (!Serial);
pinMode(ledError, OUTPUT);
pinMode(pinSwitch, INPUT_PULLUP);
pinMode(ledRecord, OUTPUT);
pinMode(ledRead, OUTPUT);
pinMode(pinSD, OUTPUT);
// Start RTC
Serial.print("\n\nStarting RTC...");
rtc.begin();
// Show all lights as part of boot sequence
digitalWrite(ledRecord, HIGH);
digitalWrite(ledRead, HIGH);
digitalWrite(ledError, HIGH);
// Throw away analog read
pinState = digitalRead(pinSwitch);
Val1.raw = analogRead(Val1.pin);
Val2.raw = analogRead(Val2.pin);
delay(500);
digitalWrite(ledRecord, LOW);
digitalWrite(ledRead, LOW);
digitalWrite(ledError, LOW);
Serial.println(" RTC started!");
Serial.print("Initializing SD card...");
if (!SD.begin(pinSD)) {
Serial.println("Card failed, or not present");
digitalWrite(ledError, HIGH);
_currentState = _errorState;
return;
}
Serial.println(" SD card initialized!");
// Test Sd Card before continuing
filename = "TEST.txt";
dataFile = SD.open(filename, O_WRITE | O_CREAT);
if (!dataFile){
Serial.println("Unable to write to Sd Card.");
digitalWrite(ledError, HIGH);
_currentState = _errorState;
return;
}
dataFile.remove();
filename = "";
// Create header for files
sprintf(_header, "Time(ms),%s,%s",Val1._name,Val2._name);
// Print header for serial logging
Serial.println("Program ready.");
}
void loop() {
pinState = digitalRead(pinSwitch);
digitalWrite(ledRead, HIGH);
digitalWrite(ledRecord, LOW);
currentMillis = millis();
if ((currentMillis - previousMillis) >= interval) {
switch (_currentState) {
case _readState:
_currentState = _readState;
digitalWrite(ledRead, LOW); // Green LED OFF
//Read Values
Val1.raw = analogRead(Val1.pin);
Val2.raw = analogRead(Val2.pin);
case _displayState:
_currentState = _displayState;
previousMillis = currentMillis;
if (pinState != LOW) {
if (filename != ""){
dataFile.close();
filename = "";
buffer.remove(0);
}
_currentState = _readState;
break;
};
case _bufferState:
_currentState = _bufferState;
buffer += millis();
buffer += ",";
buffer += Val1.raw;
buffer += ",";
buffer += Val2.raw;
buffer += "\r\n";
case _createState:
_currentState = _createState;
if (filename == "") {
DateTime now = rtc.now();
filename = String(now.unixtime(), DEC);
filename = filename + ".txt";
Serial.print(filename);
Serial.println(" created!");
dataFile = SD.open(filename, O_CREAT | O_APPEND | O_WRITE); // Open filename.txt
dataFile.println(_header);
};
case _writeState:
_currentState = _writeState;
digitalWrite(ledRecord, HIGH);
if (buffer.length() >= 312) {
dataFile.write(buffer.c_str());
buffer.remove(0);
dataFile.flush();
}
_currentState = _readState;
previousMillis = currentMillis;
break;
case _errorState:
Serial.println("Current State: _errorState");
digitalWrite(ledError, HIGH);
_currentState = _errorState;
}
}
}
Here is SdInfo information from the SdFat Examples
init time: 76 ms
Card type: SD2
Manufacturer ID: 0X2
OEM ID: TM
Product: SD02G
Version: 3.8
Serial number: 0X934F70A9
Manufacturing date: 6/2009
cardSize: 1967.13 MB (MB = 1,000,000 bytes)
flashEraseSize: 128 blocks
eraseSingleBlock: true
OCR: 0X80FF8000
SD Partition Table
part,boot,type,start,length
1,0X0,0XC,137,3841911
2,0X0,0X0,0,0
3,0X0,0X0,0,0
4,0X0,0X0,0,0
Volume is FAT32
blocksPerCluster: 8
clusterCount: 479296
freeClusters: 479110
freeSpace: 1962.43 MB (MB = 1,000,000 bytes)
fatStartBlock: 169
fatCount: 2
blocksPerFat: 3752
rootDirStart: 2
dataStartBlock: 7673
Data area is not aligned on flash erase boundaries!
Download and use formatter from www.sdcard.org!
Also the output from StdioBench
Starting test
uint8_t 0 to 255, 100 times
fileSize: 116500
print millis: 7685
stdio millis: 3813
ratio: 2.02
uint16_t 0 to 20000
fileSize: 128890
print millis: 8436
stdio millis: 4173
ratio: 2.02
uint32_t 0 to 20000
fileSize: 128890
print millis: 8522
stdio millis: 4287
ratio: 1.99
uint32_t 1000000000 to 1000010000
fileSize: 120000
print millis: 8013
stdio millis: 4054
ratio: 1.98
float nnn.ffff, 10000 times
fileSize: 100000
print millis: 10683
stdio millis: 4069
ratio: 2.63
Done
Please let me know if I have left any information out, this is always a learning process for me. Thank you!