Data Refresh Rate of different sensors and Sample Time

Hey Guys,

first of all: Sorry for my bad english.

Im new to working with arduino and sensors. For an university project i have to measure vibrations and force of a vibration experiment.

For that i am using a Adafruit MMA8451 Accelerationsensor and a ADS1115 ADC, which gets the voltage from my force sensor.

I have problems understanding the meaning of the Data Refresh Rate of my Chips and the sample Rate. I allready searched for this topic but i cant understand it.

i found out that i should use the blink blink without delay method to get a constant sample rate. And Serial.print slows the whole programm.

My code for now:

//Librarys
#include <Wire.h>
#include <Adafruit_MMA8451.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_MCP4725.h>
#include <Adafruit_ADS1015.h>
#include <arduino.h> 
//Variablen
uint32_t vmot = 0;
String cmd;
int16_t adc0, adc1, adc2, adc3;
//Modulobjekte
Adafruit_MMA8451 mma = Adafruit_MMA8451();//Acceleration_Sensor
Adafruit_MCP4725 dac;//Digital_Analog_Converter
Adafruit_ADS1115 ads; //Analog_Digital_Converter
//SamplingRate
#define INTERVAL 1250 //800Hz Sampling Rate
unsigned long lastMicros = 0;
unsigned long Micros;
//Funktionen
void readsensors();
void serialtransmitData();

void setup() {
  Serial.begin(115200);
  /******************************************************************/
  //Setup MMA8451
  Serial.println("Adafruit MMA8451 test!");
  if (! mma.begin()) {
    Serial.println("Couldnt start");
    while (1);
  }
  Serial.println("MMA8451 found!");
  mma.setRange(MMA8451_RANGE_8_G);
  mma.setDataRate(MMA8451_DATARATE_400_HZ);
  Serial.print("Range = "); Serial.print(2 << mma.getRange());  
  Serial.println("G");
  /******************************************************************/
  /******************************************************************/
  //Setup DAC MCP4725
  Serial.println("Connecting DAC...");
  dac.begin(0x62);
  Serial.println("DAC connected.");
  /******************************************************************/
  /******************************************************************/
  //Setup ADC ADS1115
  //                                                                ADS1015  ADS1115
  //                                                                -------  ------
  ads.setGain(GAIN_TWOTHIRDS);  // 2/3x gain +/- 6.144V  1 bit =    3mV      0.1875mV (default)
  // ads.setGain(GAIN_ONE);        // 1x gain   +/- 4.096V  1 bit = 2mV      0.125mV
  // ads.setGain(GAIN_TWO);        // 2x gain   +/- 2.048V  1 bit = 1mV      0.0625mV
  // ads.setGain(GAIN_FOUR);       // 4x gain   +/- 1.024V  1 bit = 0.5mV    0.03125mV
  // ads.setGain(GAIN_EIGHT);      // 8x gain   +/- 0.512V  1 bit = 0.25mV   0.015625mV
  // ads.setGain(GAIN_SIXTEEN);    // 16x gain  +/- 0.256V  1 bit = 0.125mV  0.0078125mV
  Serial.println("Connecting ADS1115");
  ads.begin();
  Serial.println("ADC ADS1115 connected.");
}

void loop() {
  // put your main code here, to run repeatedly:
if (micros() - lastMicros > INTERVAL) {
    lastMicros = micros(); // do this first or your interval is too long!
    readsensors();
    serialtransmitData();
  }
}

void readsensors(){
 mma.read();//Read raw data Acceleration: stored mma.x, mma.y,mma.z
 adc0 = ads.readADC_SingleEnded(0); //Read ADC Pin0
 adc1 = ads.readADC_SingleEnded(1); //Read ADC Pin1
 adc2 = ads.readADC_SingleEnded(2); //Read ADC Pin2
 adc3 = ads.readADC_SingleEnded(3); //Read ADC Pin3
}
void serialtransmitData(){
  //Transmitting Data
  Serial.print("D:");
  Serial.print(mma.x);  Serial.print("/t");
  Serial.print(mma.y);  Serial.print("/t");
  Serial.print(mma.z);  Serial.print("/t");
  Serial.print(adc0);   Serial.print("/t");
  Serial.print(adc2);   Serial.print("/t");
  Serial.print(vmot);   Serial.print("/t");
  Serial.print(lastMicros); Serial.println();
 
}

Is this Code working with my sample rate of 800Hz ?
I can adjust the Datarefreshrate of my MMA8451 chip ( 800Hz-1,56Hz). What is the actuall meaning of the Datafrefreshrate and how does it affect my Data ?
The ADS1115 has different RefreshRates (860-8Hz).
I think i just need a higher Data RefreshRate than my Sample Rate, right?

In order to transmit my data to Matlab:
Is there a better option for seperating my data than "Serial.print("/t")?
And do i need to save my Data in a Array and transmit it after the Measurement is done ? Or does my method work?

I'm pretty confused at the moment. I hope these arent too many questions :o :confused:
Dominik

Data refresh rate and sample rate are the same. I got the impression that you confuse the sample rate with the read out rate. As you failed to tell us what model of Arduino you're using I cannot tell if a read out rate of 800Hz is even feasible.
Anyway transferring the read data serially to the PC at 115200 baud limits the maximum rate you get at the PC to about 230Hz, given that the sensor read out is fast enough.

Thanks for your reply,

im using an Arduino Uno. I testet the time my loop takes to read the Data:
Just reading my Accelerometer Data, micros() and sending the value of MIcros() takes me 2,7 ms.
Reading out the ADC Value of the ADS1115 in the same manner takes 18 ms.
So for know i am trying to use the integrated ADC of my Arduino to get the Value from my Force Sensors.

In order to get my 800Hz Sample rate, i will try to speed up the I2C Connection. I found a manual to change the twi.h File for that. Hopefully this will boost up the speed of my Accelerometer Reading a littlle bit.

If my Data Transfer rate is really that slow, how can i improve my code there ? If my Sample rate is about 800HZ and my transfer Data Rate ios about 230Hz my Serial buffer will be full after some time and the whole loop waits for the Buffer to clear or ?

Is it possible to save the Measurement data local and transmit it after or is the Storage in my Arduino uno to small ?

The https://www.nxp.com/docs/en/data-sheet/MMA8451Q.pdf can do a data ready interrupt. By using the dataready interrupt you can program so that when the device has data you can read the device and do the thing instead of trying to get data and hoping there is data read for you to read.

You can try running the uno at a higher baud rate. IIRC, people have had success running it at 300000 baud, but that's still not enough for 800Hz because yes, once the serial output buffer is full your code will block.

I doubt that you can store results in RAM, unless the period you're running this test for is incredibly short - the Uno just doesn't have the memory for it. Other Arduino like devices have a lot more though.

You might try using an SD card, store the data locally and then send it to Matlab at your leisure afterwards.

so should i buy something like this ?

Is a data logger shield even written faster than the serial communication ?
Or are there any other options transmitting the data quickly to the PC ?

Edit:
If i run the measurement for about 30sec for each motor frequenz is there enough buffer ?
Atm i only have 370 Hz running.
I could just measure 30 sec and than wait until the buffer is empty. Does this work ?

Is a data logger shield even written faster than the serial communication ?

No.

Are your force sensors fast enough to provide new values at 800Hz? If not it might be a good idea only read them at a speed they provide new data.

I found a manual to change the twi.h File for that.

There an official method for that:

Wire.setClock()

400000 should work for the UNO.

It might be a good idea to change to an ARM based Arduino if you need more speed. As you still failed to provide links to the used hardware (not the chips, the actual breakout boards or better their schematics) it's up to you to check if they are compatible.

As always, we strongly advise to get your project working once piece at a time.

The MMA8451 accelerometer is digital and has a maximum data rate of 800 Hz. There should be no problem to transmit the data at that rate to a PC over the serial port. Start with that alone, and learn how to use it properly.

Then get the mysterious "force sensor" working separately, before combining the projects. Why are you using a separate ADC? That just adds to the complexity.

The mysterious force sensor is not important for my question.
Its a very good force sensor from a small german company. The Force Sensor is working.

I already work without the extra ADC because the ads1115 slows thinks down and getting the data fromk 2 different pins takes about 18ms, way too long.

I'm now using the internal adc from the arduino uno board.

The Adafruit MMA8451 is working with 800Hz aswell as the force sensor. Im just trying to get the 800 Hz Sample Rate and to send my informations via serial.

@pylon: thank you for the method. I didnt know that.

For my experiment i need to send atleast these informations to Matlab: voltage motor(int), z acceleration , 2x voltage from analog input pins from my arduino and the micros() for the time of the data.
At the moment i have a sample rate of 400 Hz. I hope updating the I2C clock will speed up the time my arduino takes to get the acceleration data to 800 Hz. I dont know if my serial buffer will get full or not.

Can somebody tell me if this works or not ?
Changing the Arduino to a faster model like the Arduino due will not speed up my serial speed. So this is the only breaking point in my experiment.

Is their a SPI device you can use?

I dont know if my serial buffer will get full or not.

The beauty of Arduino is that you can try things and see what works.

However, a little thought goes a long, long way.

Your program currently sets the serial Baud rate to 115200, which means you can transmit 11520 characters per second.

If you break that into 800 packets per second, each packet can have 14 characters, counting possible line feed/carriage returns/commas etc.

Can you guess where I'm going with this?

Idahowalker:
Is their a SPI device you can use?

I would like to go with the Acceleration Sensor i got. It should work. If not, i can give a SPI Chip a try.

jremington:
The beauty of Arduino is that you can try things and see what works.

However, a little thought goes a long, long way.

Your program currently sets the serial Baud rate to 115200, which means you can transmit 11520 characters per second.

If you break that into 800 packets per second, each packet can have 14 characters, counting possible line feed/carriage returns/commas etc.

Can you guess where I'm going with this?

14 characters = 14 Byte a 8 Bit.
Micros() is a var of unsigned Long = 4 Byte
2 X Analog Read() = 2x 2 Byte = 4 Byte
Acceleration MMA8451 Raw Data = 14 bits -> 2 Byte
Voltage Mot = int = 2 Byte
New Line in case of a Serial.println() = 1 Byte
In total = 13 Byte
Than i am missing 3 Byte for a comma. So this is not working....
Is there an option to seperate the data without kommas ?

If you are sending binary data through the serial port, there is no point in using newline, commas or other separators, as the records are all the same size. At 115200 Baud, you can send 14 byte records of raw data at 800 Hz.

Double the serial port data rate to get twice the data transmission rate, so 28 byte records at 800 Hz.

However, the accelerometer has 3 axes, so 6 bytes are required to transmit the X, Y and Z axis data at 14 bit resolution.

jremington:
If you are sending binary data through the serial port, there is no point in using newline, commas or other separators, as the records are all the same size. At 115200 Baud, you can send 14 byte records of raw data at 800 Hz.

Double the serial port data rate to get twice the data transmission rate, so 28 byte records at 800 Hz.

However, the accelerometer has 3 axes, so 6 bytes are required to transmit the X, Y and Z axis data at 14 bit resolution.

I'm just interested in the Z axis. Can i double the Baudrate, where are the limits for my PC and the Arduino Uno?

where are the limits for my PC and the Arduino Uno?

Try the various options and let us know.

Even with Wire.setClock(400000); i cant get below 2,5-2,6 ms reading out the Acceleration Sensor.

Im using the Adafruit MMA8451 Board. Without the comand for reading the rawdata of the Acceleration sensor my loop can easily serial.print my micros()-time in under 1 ms. So still the sensor slows things down.

Is there someone, who can help me ?
Is it the Arduino Uno that needs so long to read out the I2c ? I mean, the fast mode I2C should work with faster rates than 800Hz.
Or is it the Adafruit library that is inefficient ?

Even with Wire.setClock(400000); i cant get below 2,5-2,6 ms reading out the Acceleration Sensor.

How did you time that? Using micros() calls in the sketch? Measuring on the PC is not accurate enough.
With 400kHz clock you should be able to transfer about 100 bytes in 2.5ms (in ideal conditions). At 100kHz that will be 25 bytes and the read() method transfers 13 bytes in the library's version.

The mma.read() call can be made faster by eliminating the getRange() call. Do that call once and store the result in the object.

Is it the Arduino Uno that needs so long to read out the I2c ? I mean, the fast mode I2C should work with faster rates than 800Hz.

Check the bus traffic with a logic analyzer. Maybe the chip is stretching the clock at some point or the Arduino isn't requesting fast enough.

pylon:
How did you time that? Using micros() calls in the sketch?

I measure with micros() and send it serial to my pc.
without mma.read my loop takes under 1ms for reading out 2 analog pins.
with mma.read() the loop takes 2,5ms.

pylon:
The mma.read() call can be made faster by eliminating the getRange() call. Do that call once and store the result in the object.

Check the bus traffic with a logic analyzer. Maybe the chip is stretching the clock at some point or the Arduino isn't requesting fast enough.
[/quote]

I absolutly dont know how to do that. I have an osziloscope at work is there a possibility to test the connection with it ?

I just looked at the MMA8451.cpp in the begin()-method:

bool Adafruit_MMA8451::begin(uint8_t i2caddr) {
  Wire.begin();
  _i2caddr = i2caddr;

  /* Check connection */
  uint8_t deviceid = readRegister8(MMA8451_REG_WHOAMI);
  if (deviceid != 0x1A)
  {
    /* No MMA8451 detected ... return false */
    //Serial.println(deviceid, HEX);
    return false;
  }

  writeRegister8(MMA8451_REG_CTRL_REG2, 0x40); // reset

  while (readRegister8(MMA8451_REG_CTRL_REG2) & 0x40);

  // enable 4G range
  writeRegister8(MMA8451_REG_XYZ_DATA_CFG, MMA8451_RANGE_4_G);
  // High res
  writeRegister8(MMA8451_REG_CTRL_REG2, 0x02);
  // DRDY on INT1
  writeRegister8(MMA8451_REG_CTRL_REG4, 0x01);
  writeRegister8(MMA8451_REG_CTRL_REG5, 0x01);

  // Turn on orientation config
  writeRegister8(MMA8451_REG_PL_CFG, 0x40);

  // Activate at max rate, low noise mode
  writeRegister8(MMA8451_REG_CTRL_REG1, 0x01 | 0x04);

  /*
  for (uint8_t i=0; i<0x30; i++) {
    Serial.print("$");
    Serial.print(i, HEX); Serial.print(" = 0x");
    Serial.println(readRegister8(i), HEX);
  }
  */

  return true;
}

// Activate at max rate, low noise mode: Does the low noise mode affect my reading speed?

Thank you for your Input!

I absolutly dont know how to do that. I have an osziloscope at work is there a possibility to test the connection with it ?

With a digital one you should be able to save one complete mma.read() call. Take a look at the traffic, does it have longer pauses? Is SCK pulled low during them?

Activate at max rate, low noise mode: Does the low noise mode affect my reading speed?

According to the datasheet it doesn't. It just limits the measurement range.

without mma.read my loop takes under 1ms for reading out 2 analog pins.
with mma.read() the loop takes 2,5ms.

So the MMA read needs about 1.5ms. With the modification I suggested you should get that below 1ms.
You might start think about making the analog reads faster. You should be able to get that to about 200µs.