Seeed xiao sense imu with data ready interrupt not working for high frequencies

I use the LowLevelExalmple as base and i add the interrupt for DataReady.
I would like to obtain higher sampleRates. At present 1 accel measurement is about 5ms (ODR = 208Hz)
when i increase the ODR to 416 or 833 , the interrupt routine goes corrupt.
It looks like the Interrupt is not latched. in the datasheet of the LSM6DS3TR-C they speak about a DRDY_PULSED bit in the DRDY_PULSE_CFG register.
In the driver LSM6DS.h these are not known. The address in the datasheet (0B)refers to a LSM6DS3_ACC_GYRO_ORIENT_CFG_G register in the driver.

Code:

/*****************************************************************************/
//  LowLevelExample.ino
//  Hardware:      Grove - 6-Axis Accelerometer&Gyroscope
//	Arduino IDE:   Arduino-1.65
//	Author:	       Lambor
//	Date: 	       Oct,2015
//	Version:       v1.0
//
//  Modified by:
//  Data:
//  Description:
//
//	by www.seeedstudio.com
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2.1 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
//
/*******************************************************************************/

#include "LSM6DS3.h"
#include "Wire.h"
#include "SPI.h"

volatile long interruptCount=0;
uint16_t errorsAndWarnings = 0;
uint8_t readingReg=0;
#define int1Pin PIN_LSM6DS3TR_C_INT1 
volatile bool interrupted=false;
volatile long prevInterruptCount = 0; // Interrupt Counter from last loop

//Create instance of LSM6DS3Core
LSM6DS3Core myIMU(I2C_MODE, 0x6A);    //I2C device address 0x6A
long millisOld=0;
static int count=0;
static long milllisOld=0;

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

    //Call .beginCore() to configure the IMU
    if (myIMU.beginCore() != 0) {
        Serial.print("\nDevice Error.\n");
    } else {
        Serial.print("\nDevice OK.\n");
    }

    uint8_t dataToWrite = 0;  //Temporary variable

    //Setup the accelerometer******************************
    dataToWrite = 0; //Start Fresh!
    dataToWrite |= LSM6DS3_ACC_GYRO_BW_XL_100Hz;
    dataToWrite |= LSM6DS3_ACC_GYRO_FS_XL_8g;
    dataToWrite |= LSM6DS3_ACC_GYRO_ODR_XL_208Hz;

    //Now, write the patched together data
    errorsAndWarnings += myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, dataToWrite);

    //Set the ODR bit
    errorsAndWarnings += myIMU.readRegister(&dataToWrite, LSM6DS3_ACC_GYRO_CTRL4_C);
    dataToWrite &= ~((uint8_t)LSM6DS3_ACC_GYRO_BW_SCAL_ODR_ENABLED);

    dataToWrite=0;
    dataToWrite |= LSM6DS3_ACC_GYRO_INT1_DRDY_XL_ENABLED;
    myIMU.writeRegister(LSM6DS3_ACC_GYRO_INT1_CTRL, dataToWrite);
    
    pinMode(int1Pin, INPUT);
    attachInterrupt(digitalPinToInterrupt(int1Pin), int1ISR, RISING);
    delay(2000);

    pinMode(LEDR, OUTPUT);
    pinMode(LEDG, OUTPUT);
    pinMode(LEDB, OUTPUT);
    setLedRGB(false, false, true); // set blue led
}

void int1ISR()
{
  interruptCount++;
}

void loop() {
if (interruptCount > prevInterruptCount) {
      long millisNew = millis();
      Serial.print(millisNew);
      Serial.print("  ");
      Serial.print(millisNew-millisOld);
      Serial.print("  ");
      Serial.print(interruptCount);
      millisOld=millisNew;
  
      setLedRGB(false, true, false); // set green only
       //Acelerometer axis X
       int16_t temp;
      if (myIMU.readRegisterInt16(&temp, LSM6DS3_ACC_GYRO_OUTX_L_XL) != 0) {
          errorsAndWarnings++;
      }
      Serial.print(" X = ");
      Serial.print(temp);
      if (myIMU.readRegisterInt16(&temp, LSM6DS3_ACC_GYRO_OUTY_L_XL) != 0) {
          errorsAndWarnings++;
      }
      Serial.print(" Y = ");
      Serial.print(temp);
      if (myIMU.readRegisterInt16(&temp, LSM6DS3_ACC_GYRO_OUTZ_L_XL) != 0) {
          errorsAndWarnings++;
      }
      Serial.print(" Z = ");
      Serial.println(temp);
      prevInterruptCount = interruptCount;
      if(errorsAndWarnings>0){
        Serial.println(errorsAndWarnings);
        delay(1000);
      }
      
    }

    
if (interruptCount >= 100) {
    // Trigger System OFF after 5 interrupts
    setLedRGB(true,false, false); // 
    
    prevInterruptCount=-1000;
    interruptCount=0;
    Serial.println("100 interrupts hold 2s");
    delay(2000);
}

return;

}

void setLedRGB(bool red, bool green, bool blue) {
  if (!blue) { digitalWrite(LEDB, HIGH); } else { digitalWrite(LEDB, LOW); }
  if (!green) { digitalWrite(LEDG, HIGH); } else { digitalWrite(LEDG, LOW); }
  if (!red) { digitalWrite(LEDR, HIGH); } else { digitalWrite(LEDR, LOW); }
}

Hi there, What BSP are you using?
Roll it back to 2.9.0 go again !
HTH
GL :slight_smile: PJ

i returned to 2.9.0 but no result.
if i use 208Hz, the interrupts get handled in sequence ( numbers are consecutive 95,96,97,…)
if i use 416Hz, the counter jumps 1 time extra meaning, the interrupt was called twice but processed once

9:15:38.135 -> 20866  5  87 X = 63 Y = -246 Z = 4228
09:15:38.135 -> 20871  5  89 X = 63 Y = -252 Z = 4243
09:15:38.135 -> 20876  5  91 X = 62 Y = -246 Z = 4231
09:15:38.170 -> 20881  5  93 X = 62 Y = -242 Z = 4236
09:15:38.170 -> 20885  4  95 X = 61 Y = -243 Z = 4243
09:15:38.170 -> 20890  5  97 X = 68 Y = -240 Z = 4233
09:15:38.170 -> 20895  5  99 X = 59 Y = -242 Z = 4242

at 833Hz the counter increases with 3 ( 91,94,97)

according to the datasheet the interrupt should be reset when all three are read???

Hi there, Ghisbo & welcome.
Yes the Library doesn’t recognize some of the registers you need to write them directly yourself.
Without testing the code , Hard to say the combination of ODR, FS settings, Accelerometer power mode? Are you setting High performance mode? any filters or fifo? something is missing.
Your close.
Even just catching interrupts, are the Latch mode set? You may need another SPI mode to sample on the falling clock MCU to IMU. When you change ODR do you change FS?
Interrupt routine looks like it needs more.? Give some additional info from your testing and other folks will comment as well.
GL :slight_smile: PJ

I tried a lot of settings but i do not get a stable result. the interrupts keep interfering so i will leave this path. the fact that the library lsm6ds3 is different from the datasheet of lsm6ds3TR-C makes it difficult to know what is going on.

Hi there,
Yes they are different parts, not by allot though.
Fire off an e-mail to seeed support and describe you situation. Perhaps they can test it at speed and provide some answers.
HTH
GL :slight_smile: PJ
:wink: :v:

Thank yuo,
i will give that a try

AOK,
Also just reviewing the Interrupt syntax
https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/

Syntax

attachInterrupt(digitalPinToInterrupt(pin), ISR, mode) (recommended)
attachInterrupt(interrupt, ISR, mode) (not recommended)
attachInterrupt(pin, ISR, mode) (Not recommended. Additionally, this syntax only works on Arduino SAMD Boards, Uno WiFi Rev2, Due, and 101.)

also look at the Guide by Gammon Forum : Electronics : Microprocessors : Interrupts, good read maybe shed some light on it.
HTH
GL :slight_smile: PJ

The info on the Gammon Forum is very interesting. I know i should not use the SerialPrint and I will modify that as a test.

Hi There,
I would agree 100% more folks need to LQQK at that thread, It’s the true secret sauce in Arduino Coding IMO. Most interesting is the timing the INT takes with a 16MHZ clock. Factor in the highest speed the IMU can Interrupt the MCU. KEY IMO. you may be hitting that line or just getting the same INT but sampled twice? needs more inquiry. Good Stuff though forsure :stuck_out_tongue_winking_eye:
HTH
GL :slight_smile: PJ

Hello, I apologize for being late. Are you using interrupts to check if the acceleration sampling rate is accurate? If you don’t use interrupts, can the acceleration sampling rate (i.e., changing LSM6DS3_ACC_GYRO_ODR_XL_xHz) be properly modified through code?

The rate can be modified ( increased ) but then more interrupts are generated that are not processed. I think a basic sample with interrupt driven imu readings would be appreciated.

Hi There,
So I looked at the Accel Info and I think the config is not correct.
Have you considered using a filter along with the Tilt Interrupt? Your probably getting allot of duplicates or garbage ones in.
I see most of the HIGHER speed code examples do it this way, so maybe considered.
ALso the WIre Clock may need set explicitly is se also.
ala’ ;

Wire1.setClock(400000UL);  //SCL 400kHz

// initialize and set IMU
  // refer to   LSM6D3.cpp:351
  myIMU.settings.gyroRange = 2000;  // calcGyro()
  myIMU.settings.accelRange = 4;    // calcAccel()
  
  if (myIMU.begin() != 0) {                                      
    Serial.println("IMU Device error");
    while(1);
  }
  
  Wire1.setClock(400000UL);  //SCL 400kHz
    
  // change defalt settings, refer to data sheet 9.13, 9.14, 9.19, 9.20
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL2_G, 0x1C);    // 12.5Hz 2000dps
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x1A);   // 12.5Hz 4G 
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL7_G, 0x00);    // HPF 16mHz
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL8_XL, 0x09);   // ODR/4

  // Maadgwick filter sampling rate
  filter.begin(12.5);  

  // initialize BLE
  if (!BLE.begin()) {
    Serial.println("starting BLE module failed!");
    while (1);
  }

  // set the local name
  BLE.setLocalName("Monitor");
  // set the device name
  BLE.setDeviceName("XIAO nRF52840 Sence");
  // set the UUID for the service
  BLE.setAdvertisedService(AttService);
  // add the characteristic to the service  
  AttService.addCharacteristic(dataCharacteristic);
  // add service  
  BLE.addService(AttService);

  // start advertising
  BLE.setAdvertisingInterval(160);    //0.625mS * 160 = 100mS
  BLE.setConnectionInterval(6, 3200); //1.25mS * 6 = 7.5mS, 1.25mS * 3200 = 4S
  BLE.advertise();

}

void loop() {

Something along those lines,
HTH
GL :slight_smile: PJ :santa:

I tested with Setting the Wire.Speed butno change.
As far as i know the filter is not available in the driver.

Hi there,
I doubt changing the clock alone will have any difference also the Madgwick.h lib for the filter to catch YAW and TILT cleanly. Look there.
HTH
GL :slight_smile: PJ