IMU rate is too low

Hi there,

Yes I too ran into this issue some time ago, several have and there are posts about how to handle it. The most Obvious is “USE THE FIFO”

the Assistant breaks it down this way..
To achieve higher sampling rates for reading IMU data with the LSM6DS3 on the Xiao nRF52840 Sense, you can focus on optimizing the communication and processing of data. Here are a few key strategies to improve your sampling rate:

1. Utilize Direct FIFO Reading

The LSM6DS3 has a built-in FIFO (First-In, First-Out) buffer that allows for continuous sampling without waiting for data availability flags. By configuring the FIFO and reading data in batches, you can significantly reduce the overhead of individual read operations.

2. Optimize I2C Speed

You’ve already set the I2C clock to 400 kHz. If the hardware supports it, consider increasing the clock speed to 1 MHz (Fast Mode Plus). This reduces the time spent on I2C transactions.

Wire1.setClock(1000000UL); // Set I2C speed to 1 MHz

3. Configure the IMU for Maximum Output Data Rate

The LSM6DS3 supports an accelerometer output data rate (ODR) of up to 1.66 kHz. To utilize the highest rate:

  • Set CTRL1_XL to 0x80 (1.66 kHz).
  • Disable filters or unnecessary processing in the IMU.

4. Reduce String Formatting Overhead

String operations in Arduino are relatively slow. Instead of building strings in real-time, store raw values in a buffer and process them later.

5. Minimize Interruptions

Disable unnecessary interrupts and avoid using Serial.print inside the high-frequency sampling loop. Use a large buffer to store samples and print data after sampling is complete.

6. Use Interrupts for Data Availability

Instead of polling the status register (STATUS_REG), use the LSM6DS3’s data-ready interrupt pin. This reduces CPU time spent on checking for new data.

Optimized Code Example:

Below is a modified version of your code that incorporates these optimizations:

#include <Arduino.h>
#include <LSM6DS3.h>
#include <Wire.h>

#define SAMPLING_RATE 1660 // Maximum supported by LSM6DS3
#define BUFFER_SIZE 1024   // Adjust buffer size as needed
//#define IMU_INT_PIN 2      // Connect INT1 or INT2 to this pin

LSM6DS3 myIMU(I2C_MODE, 0x6A);
//#define int2Pin PIN_LSM6DS3TR_C_INT1
#define int2Pin P0_11
volatile bool dataReady = false;
float ax, ay, az;
int16_t accelData[BUFFER_SIZE][3];
int sampleIndex = 0;

// Interrupt handler for IMU
void imuInterruptHandler() {
  dataReady = true;
}

void setup() {
  Serial.begin(9600);
  while (!Serial);

  pinMode(int2Pin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(int2Pin), imuInterruptHandler, RISING);

  // Initialize IMU
  myIMU.settings.accelEnabled = 1;
  myIMU.settings.accelRange = 16; // Set range to ±16g for better resolution
  myIMU.settings.accelSampleRate = 1660; // 1.66 kHz
  if (myIMU.begin() != 0) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  // Configure IMU interrupts
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, 0x01); // Enable data-ready interrupt
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x80);  // 1.66 kHz, ±16g

  Serial.println("IMU initialized. Starting sampling...");
}

void loop() {
  if (dataReady) {
    dataReady = false;

    uint8_t dataBuff[6];
    myIMU.readRegisterRegion(dataBuff, LSM6DS3_ACC_GYRO_OUTX_L_XL, 6);

    accelData[sampleIndex][0] = (int16_t)(dataBuff[0] | (dataBuff[1] << 8));
    accelData[sampleIndex][1] = (int16_t)(dataBuff[2] | (dataBuff[3] << 8));
    accelData[sampleIndex][2] = (int16_t)(dataBuff[4] | (dataBuff[5] << 8));

    sampleIndex++;
    if (sampleIndex >= BUFFER_SIZE) {
      printData();
      sampleIndex = 0;
    }
  }
}

void printData() {
  for (int i = 0; i < BUFFER_SIZE; i++) {
    Serial.print(accelData[i][0]);
    Serial.print(",");
    Serial.print(accelData[i][1]);
    Serial.print(",");
    Serial.println(accelData[i][2]);
  }
}

Key Features:

  1. Interrupt-Driven Sampling:
  • Data-ready interrupts eliminate polling overhead.
  1. FIFO Buffering:
  • Use the BUFFER_SIZE to temporarily store samples and print them in bulk.
  1. Minimal Processing in the Loop:
  • Data is read directly and stored in a buffer without additional computation.
  1. I2C at Maximum Speed:
  • The Wire1.setClock(1000000UL); ensures fast communication.

With these optimizations, you should be able to get closer to the IMU’s maximum output rate of 1.66 kHz. Let US know how it does. :+1:

HTH
GL :slight_smile: PJ :v:

2 Likes