Increase of sampling rate of accelerometer and save the data on SD card

Hi there,

I am using Arduino MKR 1010 Wifi connected to an SD card and 400g accelerometer (Sparkfun H3LIS331DL Accelerometer) with SPI and I2C protocol, respectively. Technically, the maximum data rate of the accelerometer is 1000Hz, but I was only able to save data at 350Hz. I'm willing to improve my sampling rate to 1000Hz. If you can help me achieve this, it would be greatly appreciated. Here is the code:

#include <SPI.h>
#include <SD.h>
#include <WiFiNINA.h>
#include <ArduinoOTA.h>
#include <SDU.h>
#include "SparkFun_LIS331.h"
#include <Wire.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
/////// Wifi Settings ///////
char ssid[] = SECRET_SSID;      // your network SSID (name)
char pass[] = SECRET_PASS;   // your network password

float accel_z;          //Collected accelerometer on z axis
const int chipselect = 4; //digital pin with SD card
int ax;
char buf[30];
int timeend = 299999999;
static long loopTimer = 0;

LIS331 xl;
int status = WL_IDLE_STATUS;
File AX1;

void setup() {

  pinMode(9,INPUT);       // Interrupt pin input
  xl.setI2CAddr(0x19);    // This MUST be called BEFORE .begin() so
                          //  .begin() can communicate with the chip

  xl.begin(LIS331::USE_I2C); // Selects the bus to be used and sets
  //  the power up bit on the accelerometer.
  //  Also zeroes out all accelerometer
  //  registers that are user writable.

  xl.setPowerMode(LIS331::NORMAL);        //Normal power mode
  xl.setODR(LIS331::DR_1000HZ);           // data rate is considered equal to 1000HZ
  xl.setFullScale(LIS331::HIGH_RANGE);    //+-400g is the acceleration range considered for the H3LIS331DH accelerometer
  // This next section configures an interrupt. It will cause pin
  //  INT1 on the accelerometer to go high when the absolute value
  //  of the reading on the Z-axis exceeds a certain level for a
  //  certain number of samples.
  xl.intSrcConfig(LIS331::INT_SRC, 1); // Select the source of the
                                       //  signal which appears on pin INT1. In
                                       //  this case, we want the corresponding
                                       //  interrupt's status to appear.
  xl.setIntDuration(50, 1);            // Number of samples a value must meet
                                       //  the interrupt condition before an
                                       //  interrupt signal is issued. At the
                                       //  default rate of 50Hz, this is one sec.
  xl.setIntThreshold(2, 1);            // Threshold for an interrupt. This is
                                       //  not actual counts, but rather, actual
                                       //  counts divided by 16.

  xl.enableInterrupt(LIS331::Z_AXIS, LIS331::TRIG_ON_HIGH, 1, false);
                                       // Enable the interrupt. Parameters indicate
                                       //  which axis to sample, when to trigger
                                       //  (in this case, when the absolute mag
                                       //  of the signal exceeds the threshold),
                                       //  which interrupt source we're configuring,
                                       //  and whether to enable (true) or disable
                                       //  (false) the interrupt.

  // setup SD card
  if (!SD.begin(SDCARD_SS_PIN)) {
    // don't continue:
    while (true);
  //Initialize serial:
  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    // don't continue:
    while (true);
  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
  // start the WiFi OTA library with internal (flash) based storage
  ArduinoOTA.begin(WiFi.localIP(), "Arduino", "pass", SDStorage);
  // you're connected now

  AX1 ="AX1.txt", FILE_WRITE);
  AX1.print("Time"); AX1.print("\t"); AX1.print("az"); AX1.print("\n");


void loop()
   ArduinoOTA.poll();            //check for WiFi OTA updates

   int16_t x, y, z;
   String dataString = "";
  if (micros() - loopTimer > 10)
    loopTimer = micros();
    xl.readAxes(x, y, z);       // The readAxes() function transfers the
                                // current axis readings into the three
                                // parameter variables passed to it.   

    dataString += String(accel_z = xl.convertToG(400,z));
    AX1.print(" ");
  if ((loopTimer % 500) == 0) AX1.flush();
  if (loopTimer > timeend) AX1.close();

I2C most likely your max data rate is 400Khz. Trying to get more then the idealized data rate of 400kHz will be tough. Use SPI if the need for speed exists.

Thank you very much for your reply.
Ok, but it seems that I am quite far from this limit, am I right?

Well that depends on the impact on CPU times of the other things being ran.

Other things, like the SD card which you are not doing right now.

Ok, thanks. if there is no solution, I'll change it to SPI. But other than that, do you have any other suggestions?

Start to solve this problem by simply reading the accelerometer, and measuring the read data rate.

Then measure the time it takes to write to the SD card. Let us know what you find.

  1. Why are you doing this, and how much time does that take?
   ArduinoOTA.poll();            //check for WiFi OTA updates
  1. There is no reason to use Strings.

Thank you, Paul,
Can you tell me which part of the SD card is wrong?

You asking for a higher sampling rate and then writing to an SD card. Any SD card calls are "BLOCKING". Your program code has to wait for the SD card to complete. The writing to an SD card is quite fast until the 512 byte buffer is filled and then the buffer must be physically written to the SD card. That takes a relatively long time. Even longer if an error occurs and the SD code has to find another place to write the buffer.
I understand there are other memory devices that can be added to the Arduino that can be used for storage, but they are not removable.

Many thanks for your response jremington.
I followed what you said and I've changed the string and it got better by 20Hz. ArduinoOTA.poll() does not take that much time and it was there just for updating, anyway, it was deleted.
I only read the accelerometer on the serial monitor without an SD card and the data rate was the same as the one with the SD card. So, it means that the writing on the SD card does not change the sampling rate, right?

What that means is that given your present code, writing to the SD card is not the limiting factor. So, work on the limiting factor.

OK, sure. Since this part of the code (readaxes for reading z and az) was from the Sparkfun website and they mentioned 1000 Hz for the data rate, I did not consider it as a limit.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.