LowLatencyLogger with adxl accelerometer

Hi.
I'm working in a project to make a data logger with a SDcard and a ADXL345 accelerometer. I tried communicate in I2c mode at 400hz with the adxl and write the samples in the SDcard. But I missed a lot of samples, the reason is the high latency of the SDcard. Searching in the forum I saw the example of the LowLatencyLogger and it seemed perfect for my needs, but all the examples in the forum are from analog sensors. Please, anybody can help me?
Is possible change the code for use digital sensors like the ADXL?
Thanks a lot.

I tried communicate in I2c mode at 400hz

The I2C Wire library uses a 100 kHz clock. The ADXL345 datasheet suggests you won't get 400 hz even if you solve the SD latency problem.

Due to communication speed limitations, the maximum output data rate when using 400 kHz I2C is 800 Hz and scales linearly with a change in the I2C communication speed. For example, using I2C at 100 kHz would limit the maximum ODR to 200 Hz.

To use LowLatencyLogger do the following:

Modify this version of UserDataType.h to define your data record:

#ifndef UserDataType_h
#define UserDataType_h
const uint8_t ADC_DIM = 4;
struct data_t {
  unsigned long time;
  unsigned short adc[ADC_DIM];
};
#endif  // UserDataType_h

Modify these functions in LowLatencyLogger.ino for your sensor:

// User data functions.  Modify these functions for your data items.
#include "UserDataType.h"  // Edit this include file to change data_t.

// Acquire a data record.
void acquireData(data_t* data) {
  data->time = micros();
  for (int i = 0; i < ADC_DIM; i++) {
    data->adc[i] = analogRead(i);
  }
}

// Print a data record.
void printData(Print* pr, data_t* data) {
  pr->print(data->time);
  for (int i = 0; i < ADC_DIM; i++) {
    pr->write(',');
    pr->print(data->adc[i]);
  }
  pr->println();
}

// Print data header.
void printHeader(Print* pr) {
  pr->print(F("time"));
  for (int i = 0; i < ADC_DIM; i++) {
    pr->print(F(",adc"));
    pr->print(i);
  }
  pr->println();
}

First thanks for answering.

Due this particularity of I2C wire library, I will try to modify the communication for SPI.

Once I have some results I post here.

Thanks.

Hello.

I modified my communication to SPI and it worked . But now I'm having trouble converting the codes. I believe the BIN file is correct , but when converting to .csv all samples I receive are wrong. The ADXL345 uses two bytes to form an axis sample, and I can't separate these bytes correctly. Follow the places that changed the library code and also a sample of the types of signs I'm getting.

UserDataType.h

#ifndef UserDataType_h
#define UserDataType_h
//const uint8_t ADC_DIM = 10;
const uint8_t values_DIM=3; // Dimension of the accelerometer axes 
struct data_t {
 unsigned long time;
//  unsigned short adc[ADC_DIM];
 unsigned short values[values_DIM];
};
#endif  // UserDataType_h

This is the modified version of the LowLatencyLogger, basicaly I put the functions to read and write in the ADXL345 and modified the functions of acquire and print the data records.

#include <SdFat.h>
#include <SdFatUtil.h>

#include <SPI.h>

//------------------------------------------------------------------------------
// User data functions.  Modify these functions for your data items.
#include "UserDataType.h"  // Edit this include file to change data_t.

//=================================================================
//Assign the Chip Select signal to pin 10.
int CS=10;

//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char BW_RATE = 0x2C;       // Taxa de amostragem
char POWER_CTL = 0x2D;   //Power Control Register
char DATA_FORMAT = 0x31;   // Sensibilidade
char DATAX0 = 0x32;    //X-Axis Data 0
char DATAX1 = 0x33;  //X-Axis Data 1
char DATAY0 = 0x34;  //Y-Axis Data 0
char DATAY1 = 0x35;  //Y-Axis Data 1
char DATAZ0 = 0x36;  //Z-Axis Data 0
char DATAZ1 = 0x37;  //Z-Axis Data 1

//This buffer will hold values read from the ADXL345 registers.
char values[6];


//////////////////////////////////////////////////////////////////////////////

// Acquire a data record.
void acquireData(data_t* data) {
  data->time = micros();
  
  digitalWrite(4, HIGH);          //Sets the CS pin for the SPI sd card reader high to "disconnect" it
  digitalWrite(10, LOW);            //Sets the CS pin for 
/*  for (int i = 0; i < ADC_DIM; i++) {
    data->adc[i] = analogRead(i);   
      }*/
      
      readRegister(DATAX0, 6, values);
      
      digitalWrite(10, HIGH);          //Sets the CS pin for the SPI sd card reader high to "disconnect" it
  digitalWrite(4, LOW);            //Sets the CS pin for 
}

// Print a data record.
void printData(Print* pr, data_t* data) {
 // pr->print(data->time);
 // for (int i = 0; i < ADC_DIM; i++) {
 //   pr->write(',');  
//    pr->print(data->adc[i]);
//  }
//  pr->println();
  //================================================
 for (int i = 0; i < values_DIM; i++) {
 // pr->write(',');
   
  pr->print(data->values[i]);
 pr->write(',');
 }
 
pr->println(); 
}

// Print data header.
void printHeader(Print* pr) {
  pr->print(F("time"));
 /* for (int i = 0; i < ADC_DIM; i++) {
    pr->print(F(",adc"));
    pr->print(i);*/
    
    for (int i = 0; i < values_DIM; i++) {
    pr->print(F(",axel"));
    pr->print(i);
  }
  pr->println();
}

//------------------------------------------------------------------------------
void setup(void) {
   //Initiate an SPI communication instance.
  SPI.begin();
  //Configure the SPI connection for the ADXL345.
  SPI.setDataMode(SPI_MODE3);
  //Create a serial connection to display the data on the terminal.
  Serial.begin(9600);

  //Set up the Chip Select pin to be an output from the Arduino.
  pinMode(CS, OUTPUT);
  //Before communication starts, the Chip Select pin needs to be set high.
  digitalWrite(CS, HIGH);
  
   //Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
   writeRegister(DATA_FORMAT, 0x01);
  //Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
  writeRegister(POWER_CTL, 0x08);  //Measurement mode  
  
   writeRegister(BW_RATE, 13);   // Sets the accelerometer works at 800Hz output



//=========================================================

//------------------------------------------------------------------------------

//This function will write a value to a register on the ADXL345.
//Parameters:
//  char registerAddress - The register to write a value to
//  char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
  //Set Chip Select pin low to signal the beginning of an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the register address over SPI.
  SPI.transfer(registerAddress);
  //Transfer the desired register value over SPI.
  SPI.transfer(value);
  //Set the Chip Select pin high to signal the end of an SPI packet.
  digitalWrite(CS, HIGH);
}

//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
//  char registerAddress - The register addresse to start the read sequence from.
//  int numBytes - The number of registers that should be read.
//  char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
  //Since we're performing a read operation, the most significant bit of the register address should be set.
  char address = 0x80 | registerAddress;
  //If we're doing a multi-byte read, bit 6 needs to be set as well.
  if(numBytes > 1)address = address | 0x40;

  //Set the Chip select pin low to start an SPI packet.
  digitalWrite(CS, LOW);
  //Transfer the starting register address that needs to be read.
  SPI.transfer(address);
  //Continue to read registers until we've read the number specified, storing the results to the input buffer.
  for(int j=0; j<numBytes; j++){
    values[j] = SPI.transfer(0x00);
  }
  //Set the Chips Select pin high to end the SPI packet.
  digitalWrite(CS, HIGH);
}

And there is a sample of the signs I'm getting.

Thanks for your time.

DATA1.txt (115 KB)

I tried, but I can't solve the problem.
Anybody can help me to fix it?

Thanks.

For a start, I can't see where values_DIM is defined. I'm guessing that it might be the value 6, since you are reading 6 bytes from the accelerometer.

This code:

 for (int i = 0; i < values_DIM; i++) {
  pr->print(data->values[i]);
 pr->write(',');
 }

will write some number (6?) bytes to the output, seperated by commas. But the data you have from the accelerometer is 3 integers, not 6 bytes. Have another look at the ADXL345 examples to see how they get 6 bytes transmitted over SPI/I2C and turn that back into 3 integers.

Firstly thanks for your time.
In the specifications for the ADXL345 in full resolution I have 13 bits data, divided in 2 bytes, no an integer. My problem is that in the Low Latency Logger example the samples have 1 byte each and are stored in the .BIN file in the SD card. After that, the BIN file is converted to CSV file and the samples are separated, but I no have idea how separate this bytes correctly to mount my response.
You can help me?