Hi,
I'm trying to log data from three sensors at a high sampling rate at an SD card. However, if I increase the sampling rate above 250Hz then no data is logged at all. Any help would be greatly appreciated.
The sensors are:
- An MPU-6050
- A Pressure transducer (analogue signal)
- An inductive proximity sensor (digital signal)
The proximity sensor detects holes in a spinning disc at up to 500Hz so (by the nyquist sampling theorem) I need to sample at 1KHz.
To log data to the SD card at high frequency I'm using a cyclic buffer method - where buffer1 is filled at regular intervals (by means of an interrupt routine) whilst buffer2 up logged to the SD card and visa versa. I'm using the SdFat library to do this.
The problem I have is that if I decrease SAMPLE_INTERVAL_MUS to 4000 microSec or lower, no data is logged to the SD card at all. However, clearly my sampling interval needs to be 1000 microSec or lower.
I'm aware that high frequency sampling libraries do exist that probably solve my problem, but I couldn't get them to work when I downloaded them.
If anyone could tell me why I can't go bellow 4000 microSec, or suggest a way I could improve my code that would be great.
Thanks!
Here is my code:
#include <SPI.h>
#include "SdFat.h"
#include<Wire.h>
#include "TimerOne.h"
// Pins to collect data from
const int proximityPin = 3; // Digital pin for proximity sensor
int tranducerPin = 3; // Analog pin for transducer
const int MPU_addr=0x68; // I2C address of the MPU-6050
const int bufferSize = 20;
const int colNum = 8;
// Define the two buffers for the cyclic buffer
int buffer0[bufferSize][colNum];
int buffer1[bufferSize][colNum];
long logTime0[bufferSize];
long logTime1[bufferSize];
/*
buffer[0][x] is transducerVal
buffer[1:3][x] is AcX:AcZ
buffer[4:6][x] is GcX:GcZ
buffer[7][x] is priximityData
*/
// Various counters
int recInd = 0;
int logInd = 0;
int bufferID = 0;
const uint8_t chipSelect = 4;
const long SAMPLE_INTERVAL_MUS = 5000;
// Log file base name. Must be six characters or less.
#define FILE_BASE_NAME "Data"
// File system object alias.
SdFat sd;
// Log file.
SdFile file;
// Error messages stored in flash.
#define error(msg) sd.errorHalt(F(msg))
//==============================================================================
// Functions defined bellow
//------------------------------------------------------------------------------
// Write data header.
void writeHeader() {
file.println("AcX,AcY,AcZ,GyX,GyY,GyZ,Pressure Signal,Proximity Signal,Run Time (micro sec), buffer no");
}
//------------------------------------------------------------------------------
// Log a data the CSV
void logData() {
// Note here that we use the compliment of the buffer id as we just changed the buffer ID
if(bufferID){
for(int row=0; row<bufferSize; row++){
for(int col=0; col<colNum; col++){
file.print(buffer0[row][col]); file.write(",");
//Serial.print(buffer0[row][col]); Serial.print(",");
}
file.print(logTime0[row]);file.println(",0");
//Serial.println(logTime0[row]);
}
}else{
for(int row=0; row<bufferSize; row++){
for(int col=0; col<colNum; col++){
file.print(buffer1[row][col]); file.write(",");
//Serial.print(buffer1[row][col]); Serial.print(",");
}
file.print(logTime1[row]);file.println(",1");
//Serial.println(logTime1[row]);
}
}
}
//------------------------------------------------------------------------------
void recordData(){
sei(); // Enable interupts for the I2C
if(bufferID){
// Use buffer1
//Serial.println("Recording to buffer1");
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers
for(int col=0; col<=5; col++){
buffer1[recInd][col]=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
}
// Get transducer signal
buffer1[recInd][6] = analogRead(tranducerPin);
// Get the proximity sensor signal
buffer1[recInd][7] = digitalRead(proximityPin);
// Record logTime
logTime1[recInd] = micros();
}else{
// Use buffer0
//Serial.println("Recording to buffer0");
Wire.beginTransmission(MPU_addr);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers
for(int col=0; col<=5; col++){
buffer0[recInd][col]=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
}
// Get transducer signal
buffer0[recInd][6] = analogRead(tranducerPin);
// Get the proximity sensor signal
buffer0[recInd][7] = digitalRead(proximityPin);
// Record logTime
logTime0[recInd] = micros();
}
// increment buffer index
recInd++;
}
//------------------------------------------------------------------------------
void interuptTriggered(){
recordData();
if(recInd >= bufferSize){
// Reset the recording index
recInd = 0;
// Change the state of the buffer to redord to
bufferID = !bufferID;
// Log the data
logData();
}
//Serial.print(micros()); Serial.println("Triggered");
}
//------------------------------------------------------------------------------
void setup() {
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
char fileName[13] = FILE_BASE_NAME "00.csv";
// The input pin for the proximity sensor
pinMode(proximityPin, INPUT);
// Wake up the MPU-6050
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (wakes up the MPU-6050)
Wire.endTransmission(true);
Serial.begin(9600);
// Wait for USB Serial
while (!Serial) {
SysCall::yield();
}
// Initialize at the highest speed supported by the board that is
// not over 50 MHz. Try a lower speed if SPI errors occur.
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
sd.initErrorHalt();
}
// Find an unused file name.
if (BASE_NAME_SIZE > 6) {
error("FILE_BASE_NAME too long");
}
while (sd.exists(fileName)) {
if (fileName[BASE_NAME_SIZE + 1] != '9') {
fileName[BASE_NAME_SIZE + 1]++;
} else if (fileName[BASE_NAME_SIZE] != '9') {
fileName[BASE_NAME_SIZE + 1] = '0';
fileName[BASE_NAME_SIZE]++;
} else {
error("Can't create file name");
}
}
if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) {
error("file.open");
}
Serial.print(F("Logging to: "));
Serial.println(fileName);
Serial.println(F("Type any character to stop"));
// Write data header.
writeHeader();
// Set a timer of lentgh SAMPLE_INTERVAL_MUS
Timer1.initialize(SAMPLE_INTERVAL_MUS);
Timer1.attachInterrupt(interuptTriggered); // Attach the interupt routine
}
//------------------------------------------------------------------------------
void loop() {
// Force data to SD and update the directory entry to avoid data loss.
if (!file.sync() || file.getWriteError()) {
error("write error");
}
if (Serial.available()) {
// Close file and stop.
file.close();
Timer1.detachInterrupt();
Serial.println(F("Done"));
SysCall::halt();
}
}