Implementing FIFO using XIAO BLE Sense

Hello!

I’ve been trying to identify a proper guide to implement FIFO with XIAO BLE Sense. I’ve tried to follow the guide here (SparkFun_LSM6DS3) but the code seems to be stuck at “Clearning FIFO Buffer” print statement. Though the IMU.begin() function works correctly, the FIFO does not seem to fill up. Furthermore the myIMU.fifoGetStatus() & 0x8000 seems to always equal 0.

I’ve attached my code below:

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

LSM6DS3 myIMU(I2C_MODE, 0x6A);

float ax, ay, az;
float gx, gy, gz;
uint8_t readData = 0; // for IMU status read
uint16_t i = 0 ;

void setup() 
{

  Serial.begin(115200);
  while (!Serial);

  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);   
  digitalWrite(LED_RED, HIGH);
  digitalWrite(LED_GREEN, HIGH);

  // See LSM6D3.cpp:351
  myIMU.settings.gyroRange = 2000;
  myIMU.settings.accelRange = 4;

  myIMU.settings.gyroFifoEnabled = 1;  //Set to include gyro in FIFO
  myIMU.settings.gyroFifoDecimation = 1;  //set 1 for on /1
  myIMU.settings.accelFifoEnabled = 1;  //Set to include accelerometer in the FIFO
  myIMU.settings.accelFifoDecimation = 1;  //set 1 for on /1


    //FIFO control settings
  myIMU.settings.fifoThreshold = 1600;  //Can be 0 to 4096 (16 bit bytes)
  myIMU.settings.fifoSampleRate = 1600;  //Hz.  Can be: 10, 25, 50, 100, 200, 400, 800, 1600, 3300, 6600
  myIMU.settings.fifoModeWord = 6;  //FIFO mode.
  
  if( myIMU.begin() != 0 )
  {
	  Serial.println("Problem starting the sensor with CS @ Pin 10.");
  }
  else
  {
	  Serial.println("Sensor with CS @ Pin 10 started.");
  }
  
  Wire1.setClock(400000UL);  // I2C1 SCL=400kHz
    
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL2_G, 0x8C);     //1.66kHz 2000dps
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL1_XL, 0x8A);    //1.66kHz 4G
        
  // Set gyroscope power mode to high performance and bandwidth to 16 mHz
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL7_G, 0x00);
  // Set the ODR config register to ODR/4
  myIMU.writeRegister(LSM6DS3_ACC_GYRO_CTRL8_XL, 0x09);


  Serial.print("Configuring FIFO with no error checking...");
  myIMU.fifoBegin();
  Serial.print("Done!\n");
  
  Serial.print("Clearing out the FIFO...");
  myIMU.fifoClear();
  Serial.print("Done!\n");



  

}

void loop()
{

  float temp;  //This is to hold read data
  uint16_t tempUnsigned;

   while( ( myIMU.fifoGetStatus() & 0x8000 ) == 0 ) {Serial.println(myIMU.fifoGetStatus() & 0x8000 );};  //Wait for watermark

  Serial.print("Loop"); Serial.print(i); Serial.println();
  i++;
  digitalWrite(LED_RED, LOW);
  
  uint8_t dataBuff[6];

  unsigned int timestamp = micros();
    while( ( myIMU.fifoGetStatus() & 0x1000 ) == 0 ) {

  dataBuff[0] = myIMU.calcGyro(myIMU.fifoRead());
  dataBuff[1] = myIMU.calcGyro(myIMU.fifoRead());
  dataBuff[2] = myIMU.calcGyro(myIMU.fifoRead());
  dataBuff[3] = myIMU.calcAccel(myIMU.fifoRead());
  dataBuff[4] = myIMU.calcAccel(myIMU.fifoRead());
  dataBuff[5] = myIMU.calcAccel(myIMU.fifoRead());
  delay(10); //Wait for the serial buffer to clear (~50 bytes worth of time @ 57600baud)
  
  }
  Serial.println(micros() - timestamp);

  timestamp = micros();
  tempUnsigned = myIMU.fifoGetStatus();
  Serial.print("\nFifo Status 1 and 2 (16 bits): 0x");
  Serial.println(tempUnsigned, HEX);
  Serial.print("\n");  
  Serial.println(micros() - timestamp); // read 6 float data 1400uS

  delay(5000);
}

Could someone please use this thread to point me to resources or explain the best way to implement FIFO for 1600 ODR for each accelerometer & gyroscope values. Hopefully, this will be a guide for others facing the same problem too.

Thanks a million!

1 Like

What board library and board selection are you using?
(mbed or non-mbed?)

I’m using the Seeed Arduino LSM6DS3 library (Board: XIAO nRF52840 Sense). I have both the mbed and non-mbed libraries installed (using non-mbed above). However, since there’s no proper documentation within the XIAO Seed Arduino Github for FIFO implementation, I’ve been following the Sparkfun github example with the Seeed Arduino LSM6DS3 library import (Linked above).

The FIFO outputs 16 bits of data, so
uint16_t dataBuff[6];.
When I print dataBuff, it looks like some data is received.

That’s interesting. But my code still seems to be stuck at

Serial.print("Clearing out the FIFO...");
myIMU.fifoClear();

For some reason, the code does not budge forward from this point. I’ve tried restarting the board, but no luck.

Update: So interestingly, I started playing with this line of code

  myIMU.settings.gyroFifoDecimation = 1;  //set 1 for on /1
  myIMU.settings.accelFifoDecimation = 1;  //set 1 for on /1

and now the code works for only FIFO sample rates up to 200Hz. Anything above 200Hz produces the first error. For values below 200Hz I’m facing the second problem as I mentioned in the original post.

myIMU.fifoGetStatus() & 0x8000 seems to always equals 0.

This causes the program to be stuck inside the while loop waiting for the FIFOGetStatus() to fill up, and the FIFO buffer never fills up.

I played with your code, and found that it worked better with the delay(10) commented out.

Also, dataBuff is actually an array of float.

I also seem to have issues above 200Hz…

This is in regards to the sample rate of the FIFO. In steady state, the output throughput must be greater than the input throughput to avoid overflow; it takes about 3ms to output 6 words of data over I2C, so the maximum sample rate of the FIFO is 300Hz, or 200Hz if you can set it. If SPI could be used, it would be possible to sample at a much faster rate.

Well, it kinda sucks that the internal IMU is hardwired to I2C within the XIAO. Would the assumption still stand if the I2C rate is increased to 400kHz or greater using the Wire.h library?

Explicitly setting the frequency to 400 kHz made no difference.
I experimented with the following sketch. For your reference.

//----------------------------------------------------------------------------------------------
//BSP : Seeed nRF52 mbed-enabled Borads 2.9.1
//Board : Seeed nRF52 mbed-enabled Borads / Seeed XIAO BLE Sense - nRF52840
//2023/03/02
//----------------------------------------------------------------------------------------------

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

LSM6DS3 myIMU(I2C_MODE, 0x6A);

float ax, ay, az;
float gx, gy, gz;

uint8_t readData = 0;
unsigned int timestamp = micros();
int i = 0;
  
void setup() 
{
  Serial.begin(115200);
  while (!Serial);

  // See LSM6D3.cpp:351
  myIMU.settings.gyroRange = 2000;        // full scale [deg/sec]
  myIMU.settings.accelRange = 4;          // full scale [g]
  myIMU.settings.gyroSampleRate = 1660;   // 13, 26, 52, 104, 208, 416, 833, 1660
  myIMU.settings.accelSampleRate = 1660;  // 13, 26, 52, 104, 208, 416, 833, 1660, 3330, 6660, 13330
  myIMU.settings.fifoSampleRate = 100;    // 10, 25, 50, 100, 200, 400, 600, 800, 1600, 3300, 6600
  myIMU.settings.fifoThreshold = 1000;    // Can be 0 to 4096 (16 bit bytes)
  myIMU.settings.fifoModeWord = 6;        // FIFO mode

  if (myIMU.begin() != 0) 
  {                                      
    Serial.println("Device error");
    while(1);
  } 
  Wire1.setClock(400000UL);  // I2C1 SCL=400kHz

  Serial.print("Configuring FIFO...");
  myIMU.fifoBegin(); 
  myIMU.fifoClear();
  Serial.print("Done!\n");
}

void loop()
{
/*
  while((myIMU.fifoGetStatus() & 0x8000) == 0) {  //No need to wait for watermark
    Serial.println(myIMU.fifoGetStatus(), HEX);    
  }  //Wait for watermark
*/    
  while((myIMU.fifoGetStatus() & 0x1000) == 0) {  // while not empty
    timestamp = micros(); 
    gx = myIMU.calcGyro(myIMU.fifoRead());
    gy = myIMU.calcGyro(myIMU.fifoRead());
    gz = myIMU.calcGyro(myIMU.fifoRead());
    ax = myIMU.calcAccel(myIMU.fifoRead());
    ay = myIMU.calcAccel(myIMU.fifoRead());
    az = myIMU.calcAccel(myIMU.fifoRead());
    Serial.print("                                        fifo read time[uS] = ");  
    Serial.println(micros() - timestamp);       // 2.5mS
    
    timestamp = micros();
    Serial.print(ax); Serial.print(", ");
    Serial.print(ay); Serial.print(", ");
    Serial.print(az); Serial.print(", ");
    Serial.print(gx); Serial.print(", ");
    Serial.print(gy); Serial.print(", ");
    Serial.print(gz); Serial.print(", ");
    Serial.print("print time[uS] = ");
    Serial.println(micros() - timestamp);       // 4.1mS
    
    // Simulations that sometimes take a long time to process
    i++;            
    if(i > 100) {
      delay(200);
      i = 0;
    }
    Serial.print("                                        number of unread words = ");
    Serial.println(myIMU.fifoGetStatus() & 0x07FF);
  }   
}

This is helpful! I tried explicitly setting the I2C rate to 800kHz and was able to acquire data by setting FIFO sample rate to 400 Hz, but that seems to be the limit.

At this point, before I debug any further, I would like to know whether if it is even possible to obtain a set of 1600 samples each (1600 each for ax, ay, az, gx, gy, gz) every second using the XIAO’s internal IMU?

According to the nRF52840 datasheet “6.29.9.1 TWI interface electrical specifications”, the I2C bit rate is up to 400 kbps.
Both gyro and accel should be able to sample at 1.66 kHz inside the IMU, but not read out over I2C. I am curious as to why such a fast sampling rate is necessary.

We looked at this for health care related, NIST spec.
Guidelines to IMU Selection and a Comparison of Seven IMUs …
A tad above my pay grade but good info .
HTH
GL:-p

1 Like

I’m using the XIAO to perform hand tracking using an RNN model to map the IMU LCS to WCS. In order to detect finger taps, the sampling rate has to be > 1.6kHz for reliable hand tracking (according to research papers). I thought the XIAO would satisfy all the requirements given its small size and IMU capabilities. But, I didn’t realize that the internal I2C would be a bottleneck. :frowning:

I recommend connecting an IMU to XIAO_BLE via SPI.
The SPI transfer rate is 19.5 uS/byte for mbed or 5.6 uS/byte for non-mbed, based on the actual measurements in the link below.
When reading 12 bytes (6 data) from the FIFO, I think the FIFO can be sampled at 4.2 kHz or 14.8 kHz.

What is WCS?

PJ, thanks for the interesting info.

…RNN model to map the IMU LCS to WCS

Recurrent Neural Network model to map the IMU Local Coordinate System to the World Coordinate System.