How to terminate dataloggin for lowlatencylogger example

I am currently data loggin MPU6050 by using lowlatencylogger from SDFat and it can give me very good sampling rate. My only problem is whenever I want to stop data logging I need to key in any character on serial monitor to stop which is not applicable since during data logging my arduino is not connected to pc.

If I just switch off the power there is only temporary file inside the sd card, i guess it means it has not truncate and convert to bin file. So the method i am using now is change the FILE_BLOCK_COUNT to a smaller number and stop logging earlier. But this is not a practical way.

So how can I truncate the temporary file after I switch off the arduino?

the code as follow:

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"

#include "UserDataType.h"  // Edit this include file to change data_t.
MPU6050 mpu;
MPU6050 mpu_69 (0x69);



void setupData() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();
  // set I2C 400 kHz
  TWBR = (F_CPU/400000 - 16)/2;
  Serial.println(F("Using Wire"));
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
  Serial.println(F("Using Fastwire"));
#endif  
mpu.initialize();
mpu_69.initialize();
 
  
}


// Acquire a data record.
void acquireData(data_t* data) {
  
  data->time = micros();
  mpu.getMotion6(&data->axr, &data->ayr, &data->azr, 
                 &data->gxr, &data->gyr, &data->gzr);
  
  mpu_69.getMotion6(&data->axl, &data->ayl, &data->azl, 
                 &data->gxl, &data->gyl, &data->gzl);
                 

}

// setup AVR I2C


// Print a data record.
void printData(Print* pr, data_t* data) {
  pr->print(data->time);
  pr->write(',');
  pr->print(data->axr);
  pr->write(',');
  pr->print(data->ayr);
  pr->write(',');
  pr->print(data->azr);
  pr->write(',');
  pr->print(data->gxr);
  pr->write(',');
  pr->print(data->gyr);
  pr->write(',');
  pr->print(data->gzr);
  
  pr->write(',');
  pr->print(data->axl);
  pr->write(',');
  pr->print(data->ayl);
  pr->write(',');
  pr->print(data->azl);
  pr->write(',');
  pr->print(data->gxl);
  pr->write(',');
  pr->print(data->gyl);
  pr->write(',');
  pr->println(data->gzl);
  

}

// Print data header.
void printHeader(Print* pr) {
  pr->println(F("micros,axr,ayr,azr,gxr,gyr,gzr,axl,ayl,azl,gxl,gyl,gzl"));
}
//==============================================================================
// Start of configuration constants.
//==============================================================================
//Interval between data records in microseconds.
const uint32_t LOG_INTERVAL_USEC = 10000;
//------------------------------------------------------------------------------
// Pin definitions.
//
// SD chip select pin.
const uint8_t SD_CS_PIN = 8;
//
// Digital pin to indicate an error, set to -1 if not used.
// The led blinks for fatal errors. The led goes on solid for SD write
// overrun errors and logging continues.
const int8_t ERROR_LED_PIN = -1;
//------------------------------------------------------------------------------
// File definitions.
//
// Maxrimum file size in blocks.
// The program creates a contiguous file with FILE_BLOCK_COUNT 512 byte blocks.
// This file is flash erased using special SD commands.  The file will be
// truncated if logging is stopped early.
const uint32_t FILE_BLOCK_COUNT = 100;
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
void setup(void) {
  if (ERROR_LED_PIN >= 0) {
    pinMode(ERROR_LED_PIN, OUTPUT);
  }
  Serial.begin(38400);
  sd.begin(38400);
  while (!Serial) {}

  Serial.print(F("FreeRam: "));
  Serial.println(FreeRam());
  Serial.print(F("Records/block: "));
  Serial.println(DATA_DIM);
  if (sizeof(block_t) != 512) {
    error("Invalid block size");
  }
  setupData();
  // initialize file system.
  if (!sd.begin(SD_CS_PIN, SPI_FULL_SPEED)) {
    sd.initErrorPrint();
    fatalBlink();
  }
}
//------------------------------------------------------------------------------
void loop(void) {

  
    logData();
    binaryToCsv();
}

And I guess SDfat owner will be so mad on my ignorance but I really not familiar this. So please help?

mechanical_guy:
I am currently data loggin MPU6050 by using lowlatencylogger from SDFat and it can give me very good sampling rate. My only problem is whenever I want to stop data logging I need to key in any character on serial monitor to stop which is not applicable since during data logging my arduino is not connected to pc.

If I just switch off the power there is only temporary file inside the sd card, i guess it means it has not truncate and convert to bin file. So the method i am using now is change the FILE_BLOCK_COUNT to a smaller number and stop logging earlier. But this is not a practical way.

So how can I truncate the temporary file after I switch off the arduino?

the code as follow:

And I guess SDfat owner will be so mad on my ignorance but I really not familiar this. So please help?

Add a decision to the Loop() function.

connect a switch to a digital pin, read the value of the switch, terminate the data gather operation when the switch is detected.

chuck.

chucktodd:
Add a decision to the Loop() function.

connect a switch to a digital pin, read the value of the switch, terminate the data gather operation when the switch is detected.

chuck.

Hi, thanks for reply.

So far I do not have a switch but I am going to buy a switch soon. Before I get my switch, I modified the code again and can you please see whether it will work or not?

Let connect the switch to digital port 4...

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050.h"

#include "UserDataType.h"  
MPU6050 mpu;
MPU6050 mpu_69 (0x69);
int switchPin = 4;


void setupData() {
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
  Wire.begin();

  TWBR = (F_CPU/400000 - 16)/2;
  Serial.println(F("Using Wire"));
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
  Fastwire::setup(400, true);
  Serial.println(F("Using Fastwire"));
#endif  
mpu.initialize();
mpu_69.initialize();

pinMode(switchPin, INPUT);

  
}




// Acquire a data record.
void acquireData(data_t* data) {
  
  data->time = micros();
  mpu.getMotion6(&data->axr, &data->ayr, &data->azr, 
                 &data->gxr, &data->gyr, &data->gzr);
  
  mpu_69.getMotion6(&data->axl, &data->ayl, &data->azl, 
                 &data->gxl, &data->gyl, &data->gzl);
                 

}




// Print a data record.
void printData(Print* pr, data_t* data) {
  pr->print(data->time);
  pr->write(',');
  pr->print(data->axr);
  pr->write(',');
  pr->print(data->ayr);
  pr->write(',');
  pr->print(data->azr);
  pr->write(',');
  pr->print(data->gxr);
  pr->write(',');
  pr->print(data->gyr);
  pr->write(',');
  pr->print(data->gzr);
  
  pr->write(',');
  pr->print(data->axl);
  pr->write(',');
  pr->print(data->ayl);
  pr->write(',');
  pr->print(data->azl);
  pr->write(',');
  pr->print(data->gxl);
  pr->write(',');
  pr->print(data->gyl);
  pr->write(',');
  pr->println(data->gzl);
  

}

// Print data header.
void printHeader(Print* pr) {
  pr->println(F("micros,axr,ayr,azr,gxr,gyr,gzr,axl,ayl,azl,gxl,gyl,gzl"));
}
//==============================================================================
// Start of configuration constants.
//==============================================================================
//Interval between data records in microseconds.
const uint32_t LOG_INTERVAL_USEC = 10000;
//------------------------------------------------------------------------------
// Pin definitions.
//
// SD chip select pin.
const uint8_t SD_CS_PIN = 8;
//
// Digital pin to indicate an error, set to -1 if not used.
// The led blinks for fatal errors. The led goes on solid for SD write
// overrun errors and logging continues.
const int8_t ERROR_LED_PIN = -1;
//------------------------------------------------------------------------------
// File definitions.
//
// Maxrimum file size in blocks.
// The program creates a contiguous file with FILE_BLOCK_COUNT 512 byte blocks.
// This file is flash erased using special SD commands.  The file will be
// truncated if logging is stopped early.
const uint32_t FILE_BLOCK_COUNT = 274800;

////////////////////////
///////////////////////////////////////////////////////////////////////////
// log data
// maxr number of blocks to erase per erase call
uint32_t const ERASE_SIZE = 262144L;
void logData() {
 ................................
..............................
  // Truncate file if recording stopped early.
  if (digitalRead(switchPin) == HIGH && bn != FILE_BLOCK_COUNT) {
    Serial.println(F("Truncating file"));
    if (!binFile.truncate(512L * bn)) {
      error("Can't truncate file");
    }
  }
  if (!binFile.rename(sd.vwd(), binName)) {
    error("Can't rename file");
  }

}

Instead of setting a condition in loop, I set the condition inside the function logData(). Under the truncate file condition, I set the conditions when I press the switch and if it still not the FILE_BLOCK_COUNT, then it will start truncate the file. So the loop is still the same

void loop(void) {
 logData();

    
    binaryToCsv();
}

Do you think this will work? I havent got my switch yet, but when I verify the sketch on arduino, no error pop out yet. Please comment on this method.

Thank you

And Chuck,

Sorry for my broken english.
:stuck_out_tongue:

mechanical_guy:
Hi, thanks for reply.

So far I do not have a switch but I am going to buy a switch soon. Before I get my switch, I modified the code again and can you please see whether it will work or not?

Let connect the switch to digital port 4...

Do you think this will work? I havent got my switch yet, but when I verify the sketch on arduino, no error pop out yet. Please comment on this method.

Thank you

I would wire the Switch between GND and your switchPin.

//Change the setup() 

pinMode(switchPin,INPUT_PULLUP);  //this will connect the weak (50k) internal pullup resistor.

void logData(){

unsigned long timeout =0;  
bool truncate=false;

do{ // data capture, logging loop


// at top of loop

  if(!digitalRead(switchPin)){
    if(millis()>timeout)){ // switchPin is low and has been low for 100ms
      truncate = true; // close the file, 
                            //  truncate at current record number, 
                            //  rename to  'binname'

     }
   }
  else { // switchPin High, not pressed
    timeout = millis() + 100;  // time that switch has to be pressed to be valid     
    }
  }

The truncate operation does not CLOSE the file, After the Truncate call, Close the file before you try to rename it.

if(truncate){
  // Truncate file if recording stopped early.
  if ( bn != FILE_BLOCK_COUNT) {
    Serial.println(F("Truncating file"));
    if (!binFile.truncate(512L * bn)) {
      error("Can't truncate file");
      }
    }
  }

binFile.close();
if (!binFile.rename(sd.vwd(), binName)) {
   error("Can't rename file");
   }

You don't need a 'switch', just use a piece of wire to simulate one. Connect one side of the wire to GND touch switchPin.

Chuck

chucktodd:
I would wire the Switch between GND and your switchPin.

You don't need a 'switch', just use a piece of wire to simulate one. Connect one side of the wire to GND touch switchPin.

Chuck

Hi Chuck,

i had tried the method you suggest. First of all, the do loop in your code, there is a missing while loop?
So i deleted the do loop and straight go to if(!digitalRead(switchPin)){, but it still cannot truncate the file as i wish.

So is there anything I miss?

Sorry for keep bothering.

chucktodd:
I would wire the Switch between GND and your switchPin.

and base on my understanding, i made a brief modification.

 if(digitalRead(switchPin)){
    if(millis()>timeout){ // switchPin is low and has been low for 100ms
      truncate = true; // close the file, 
                            //  truncate at current record number, 
                            //  rename to  'binname'

     }
  }
  else { // switchPin High, not pressed
    timeout = millis() + 100;  // time that switch has to be pressed to be valid     
    }

Now what i am doing is if digitalRead the switch pin when i press it, then it will execute these lines to truncate the file.

if(millis()>timeout){
truncate = true;
}

if i dint press the button, the it will go to the else loop.

else { // switchPin High, not pressed
    timeout = millis() + 100;  // time that switch has to be pressed to be valid     
    }

This is based on my understanding. However, when I execute it, it still cant truncate the file when i press button. So may I know where did I get it wrong?

Hello,

I am really have no idea how to deal with it. The attached file is my complete code. Can anyone please help?

Thank you.

Left2.ino (14.4 KB)

If you haven't solved this already, try this:

In your "while (1)" loop, change "if (Serial.available())" to:
"if (Serial.available() || (digitalRead(switchPin)==LOW))"

Delete the "do{...}while(truncate=false)" loop.
delete the line "if(truncate == true){" and the associated '}'

That should make your switch have the same affect as entering a character.

Hi Roy,

Thank you so much for your advise. Unfortunately I am still unable to solve this problem even I modified my code according to your advise. The attached files are the modified one.

Can you show me where did I get wrong again?

Thank you.

Left2.ino (13.9 KB)

UserDataType.h (336 Bytes)

roy_s:
If you haven't solved this already, try this:

In your "while (1)" loop, change "if (Serial.available())" to:
"if (Serial.available() || (digitalRead(switchPin)==LOW))"

Delete the "do{...}while(truncate=false)" loop.
delete the line "if(truncate == true){" and the associated '}'

That should make your switch have the same affect as entering a character.

And btw, i should have told you about how I connect my switch. Like chucktodd suggested, one end of the switch I connected to ground, another end of the switch I connected to digital pin 6 as written in the code. So why is this still not working?

Add a decision to the Loop() function.

malajka:
Add a decision to the Loop() function.

malajka:
Add a decision to the Loop() function.

Hi there,

thanks for the advise. I actually tried to add a decision on the loop() function before, the code looks like this:

void loop(void){
logData();
if(digitalRead(switchPin) == LOW){
binFile.truncate();
}
binaryToCsv();
}

Somehow error came out when I tried to compile it saying "no matching function for call to 'SdBaseFile::truncate()' when there is clearly a truncate function in this SdBaseFile.

So where did I get wrong again?

Somehow error came out when I tried to compile it saying "no matching function for call to 'SdBaseFile::truncate()' when there is clearly a truncate function in this SdBaseFile.

You need an the argument for truncate() that specifies the new file size.

bool SdBaseFile::truncate(uint32_t length);

fat16lib:
You need an the argument for truncate() that specifies the new file size.

bool SdBaseFile::truncate(uint32_t length);

hi fat16lib,

Just realise it has been a long time since I last logged in.

So I took your advice and insert the code

bool SdBaseFile::truncate(uint32_t length);

However, I still get another error,

no 'bool SdBaseFile::truncate(unit32_t)' member function declared in class 'SdBaseFile'

My complete code is as shown in the attached file. So what do I do now?

And by using my current method, can I successfully terminate the data logging and truncate to the size I required?

Thank you so so much

Left2.zip (4.46 KB)

You don't need truncate for your code. Just add a test for switchPin LOW at about line 385.

Change this code to check for switchPin LOW.

   if (Serial.available()) {
      closeFile = true;
    }

You could check for just switchPin or both Serial and switchPin.

   if (Serial.available() || digitalRead(switchPin) == LOW) {
      closeFile = true;
    }

The file will be truncated here:

  // Truncate file if recording stopped early.
  if (bn != FILE_BLOCK_COUNT) {
    //Serial.println(F("Truncating file"));
    if (!binFile.truncate(512L * bn)) {
      error("Can't truncate file");
    }
  }

Remove these lines:

bool SdBaseFile::truncate(uint32_t length);

and

if(digitalRead(switchPin) == LOW){
binFile.truncate();
}

fat16lib:
You don't need truncate for your code. Just add a test for switchPin LOW at about line 385.

Change this code to check for switchPin LOW.

   if (Serial.available()) {

closeFile = true;
    }




You could check for just switchPin or both Serial and switchPin.


if (Serial.available() || digitalRead(switchPin) == LOW) {
      closeFile = true;
    }




The file will be truncated here:


// Truncate file if recording stopped early.
  if (bn != FILE_BLOCK_COUNT) {
    //Serial.println(F("Truncating file"));
    if (!binFile.truncate(512L * bn)) {
      error("Can't truncate file");
    }
  }



Remove these lines:


bool SdBaseFile::truncate(uint32_t length);



and


if(digitalRead(switchPin) == LOW){
binFile.truncate();
}

Hi fat16lib,
Again, you save my life with your wit. This work exactly how I imagine it is. I wish you can feel how much I appreciate your help.

THANK YOU fat16lib!!!!!

Hello everyone.

I am hoping to build a portable data logger using the ADXL345 accelerometer and the LowLatenyLogger.

I was wondering if a method, similar to the one described in this thread, could be used to stop the logging and put the board in a power-down mode when the sensor is not detecting motion, and continue the logging after receiving an interrupt from the accelerometer.

Thank you