cancel
Showing results for 
Search instead for 
Did you mean: 

Enabling FIFO on LSM6DSOX

amarco
Associate II

Hi, 

 

I'm trying to get the FIFO working on the LSM6DSOX on a custom board with a silicon labs microcontroller, communicating both through SPI.

 

I have checked the application note at https://www.st.com/resource/en/application_note/an5272-lsm6dsox-alwayson-3axis-accelerometer-and-3axis-gyroscope-stmicroelectronics.pdf and followed the example code at https://github.com/STMicroelectronics/STMems_Standard_C_drivers/blob/master/lsm6dsox_STdC/examples/lsm6dsox_fifo.c, but no success, so I'm wondering if I'm missing something or it's a hardware problem. 

 

I'm able to read the device id and communicate normaly with the IMU through SPI, retrieving acc and gyro readings without issues.

 

This is my code for enabling the FIFO:

 

  lsm6dsox_reset_set(&imu_dev, PROPERTY_ENABLE);
  uint8_t rst;
  do {
    lsm6dsox_reset_get(&imu_dev, &rst);
  } while (rst);

  /* Disable I3C interface */
  lsm6dsox_i3c_disable_set(&imu_dev, LSM6DSOX_I3C_DISABLE);
  /* Enable Block Data Update */
  lsm6dsox_block_data_update_set(&imu_dev, PROPERTY_ENABLE);
  /* Set full scale */
  lsm6dsox_xl_full_scale_set(&imu_dev, LSM6DSOX_2g);
  lsm6dsox_gy_full_scale_set(&imu_dev, LSM6DSOX_2000dps);
  /*
   * Set FIFO watermark (number of unread sensor data TAG + 6 bytes
   * stored in FIFO) to 10 samples
   */
  lsm6dsox_fifo_watermark_set(&imu_dev, 10);
  /* Set FIFO batch XL/Gyro ODR to 12.5Hz */
  lsm6dsox_fifo_xl_batch_set(&imu_dev, LSM6DSOX_XL_BATCHED_AT_12Hz5);
  lsm6dsox_fifo_gy_batch_set(&imu_dev, LSM6DSOX_GY_BATCHED_AT_12Hz5);
  /* Set FIFO mode to Stream mode (aka Continuous Mode) */
  lsm6dsox_fifo_mode_set(&imu_dev, LSM6DSOX_STREAM_MODE);
  /* Enable drdy 75 μs pulse: uncomment if interrupt must be pulsed */
  //lsm6dsox_data_ready_mode_set(&imu_dev, LSM6DSOX_DRDY_PULSED);
  /* Uncomment if interrupt generation on Free Fall INT1 pin */
//  lsm6dsox_pin_int1_route_t int1_route;
//  lsm6dsox_pin_int1_route_get(&imu_dev, &int1_route);
//  int1_route.fifo_th = PROPERTY_ENABLE;
//  int1_route.fifo_full = PROPERTY_ENABLE;
//  int1_route.fifo_ovr = PROPERTY_ENABLE;
//  int1_route.fifo_bdr = PROPERTY_ENABLE;
//  lsm6dsox_pin_int1_route_set(&imu_dev, int1_route);
  /* Uncomment if interrupt generation on Free Fall INT2 pin */
//  lsm6dsox_pin_int2_route_t int2_route;
//  lsm6dsox_pin_int2_route_get(&imu_dev, NULL, &int2_route);
//  int2_route.fifo_th = PROPERTY_ENABLE;
//  int2_route.fifo_bdr = PROPERTY_ENABLE;
//  int2_route.fifo_full = PROPERTY_ENABLE;
//  int2_route.fifo_ovr = PROPERTY_ENABLE;
//  lsm6dsox_pin_int2_route_set(&imu_dev, NULL, int2_route);
  /* Set Output Data Rate */
  lsm6dsox_xl_data_rate_set(&imu_dev, LSM6DSOX_XL_ODR_12Hz5);
  lsm6dsox_gy_data_rate_set(&imu_dev, LSM6DSOX_GY_ODR_12Hz5);

 

(the lines that are commented are not exactly the same on the sample, as they didn't match actual reg type declarations) and for reading the FIFO I have:

 

uint8_t imu_read_fifo(bool read_acc, bool read_gyro, uint8_t *buffer, uint8_t max_samples_read, uint8_t* samples_read){

  uint8_t wmflag = 0;

  lsm6dsox_fifo_wtm_flag_get(&imu_dev, &wmflag);

  while (!wmflag) {
      lsm6dsox_fifo_wtm_flag_get(&imu_dev, &wmflag);
  }
  *samples_read = 0;
  uint16_t fifo_num_samples;
  lsm6dsox_fifo_data_level_get(&imu_dev, &fifo_num_samples);
  *samples_read = 0;
  if (fifo_num_samples == 0){
      return SL_STATUS_OK;
  } else if (fifo_num_samples < max_samples_read){
      max_samples_read = fifo_num_samples;
  }

  uint8_t data_len = 0;
  while (*samples_read < max_samples_read){
      uint8_t* acc_data = &buffer[data_len];
      uint8_t* gyro_data = &buffer[data_len + read_acc ? 6 : 0];
      imu_read_fifo_measure_nc(read_acc, read_gyro, acc_data, gyro_data);
      data_len +=  read_acc ? 6 : 0;
      data_len +=  read_gyro ? 6 : 0;
      (*samples_read) ++;
  }
  //lsm6dsl_fifo_raw_data_get(&imu_dev, buffer, len);
}

void imu_read_fifo_measure_nc(bool read_acc, bool read_gyro, uint8_t *acc_data, uint8_t *gyro_data){
  uint8_t dummy_data[6];
  uint8_t sensor_tag;

  uint16_t fifo_num_samples;
  lsm6dsox_fifo_data_level_get(&imu_dev, &fifo_num_samples);

  while (fifo_num_samples && (read_acc || read_gyro)){
      lsm6dsox_fifo_sensor_tag_get(&imu_dev, &sensor_tag);
      switch (sensor_tag) {
        case LSM6DSOX_XL_NC_TAG:
          lsm6dsox_fifo_out_raw_get(&imu_dev, acc_data);
          read_acc = false;
          break;
        case LSM6DSOX_GYRO_NC_TAG:
          lsm6dsox_fifo_out_raw_get(&imu_dev, gyro_data);
          read_gyro = false;
          break;
        default:
          lsm6dsox_fifo_out_raw_get(&imu_dev, dummy_data);
      }
      fifo_num_samples --;
  }
}

 

But the watermark flag never changed and I get stuck in the while loop. I have tried also placing the execution on the reading part, but I didn't get anything when calling lsm6dsox_fifo_data_level_get.

 

If there is no a hardware problem, I think maybe I'm missing a trigger condition for the FIFO, or anything else is needed for enablling it.

 

I have searched elsewhere and I found references to use compression which require enabling something else, but I didn't found specific references to that being required for just using the FIFO (neither I would need the watermark or the interrupt, I just need to buffer some samples while I'm writing a previous batch on a flash memory which uses the same SPI line and can operate on a poll basis).

 

I also found something related to timestamping samples:

 

  lsm6dsox_fifo_timestamp_decimation_set(&imu_dev, LSM6DSOX_DEC_1);
  lsm6dsox_timestamp_set(&imu_dev, PROPERTY_ENABLE);
  lsm6dsox_fifo_timestamp_decimation_set(&imu_dev, LSM6DSOX_NO_DECIMATION);

 

Playing with this, I was able to trigger the watermark, and data_level_get returns non 0 content, but lsm6dsox_fifo_sensor_tag_get(&imu_dev, &sensor_tag) gives sensor_tag = 0x00 (by the way, the switch case on the lsm6dsox_fifo_sensor_tag_get function defaults to GYRO_NC_TAG, https://github.com/STMicroelectronics/lsm6dsox-pid/blob/3c2d02b69cb18de0cabd94c15dcd73aab6bd6edb/lsm6dsox_reg.c#L7584, what leads to misinterpret that a gyro reading is retrieved when the sensor_tag reports 0, which was my case). And lsm6dsox_fifo_out_raw_get also return 0x00 for the six bytes.

 

The setup is placed on my desk, I'm not moving it while I'm making the trials, but the direct acc and gyro readings are coherent with that (1G on the z axis, near 0 on the others and small values for the gyro) and no other code is being executed

 

Any help will be appreciated!

 

Regards,

Álvaro

 

15 REPLIES 15
Federica Bossi
ST Employee

Hi @amarco ,

You can look at our PID examples on Github. You can find several examples about the use of the FIFO.

Hope this helps.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
amarco
Associate II

Hi Federica,

 

Yes, that is the exact code I used to enable the FIFO, but can't get any data... I have tested the code on another board to discard an IMU malfunction, but I get the same behaviour, so I guess I missing something when configuring the FIFO.

 

Regards,

Álvaro

Federica Bossi
ST Employee

Hi @amarco ,

Have you tried to acquire the outputs not using the FIFO?

Just to exclude problems related to your hardware.

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.
amarco
Associate II

Hi Federica,

 

Yes, I can get the acc and gyro readings without issues

 

Regards,

Álvaro

amarco
Associate II

Hi, any update on this? Can someone verify wether the sample code on https://github.com/STMicroelectronics/STMems_Standard_C_drivers/blob/master/lsm6dsox_STdC/examples/lsm6dsox_fifo.c actually works?

Regards,

Álvaro

kyrreaa
Associate III

I know this is old, but in case anyone sees this later:
I found that without setting ODR for XL/GYR it does not generate any data to put into FIFO. This could explain the missing data. The two settings seem independent but the ODR turns on/off the internal hardware. I do not know why the design is like this and I can not find any good explanation in the documentation but unless ODR_XL and ODR_ACC is not set to power down there is no data for FIFO.

Hi Kirreaa,

 

Still alive, thanks for the update!

You mean that the procedure for enabling the FIFO should be as this (end part)?

 

  lsm6dsox_reset_set(&imu_dev, PROPERTY_ENABLE);
  uint8_t rst;
  do {
    lsm6dsox_reset_get(&imu_dev, &rst);
  } while (rst);

  /* Disable I3C interface */
  lsm6dsox_i3c_disable_set(&imu_dev, LSM6DSOX_I3C_DISABLE);
  /* Enable Block Data Update */
  lsm6dsox_block_data_update_set(&imu_dev, PROPERTY_ENABLE);
  /* Set full scale */
  lsm6dsox_xl_full_scale_set(&imu_dev, LSM6DSOX_2g);
  lsm6dsox_gy_full_scale_set(&imu_dev, LSM6DSOX_2000dps);
  /*
   * Set FIFO watermark (number of unread sensor data TAG + 6 bytes
   * stored in FIFO) to 10 samples
   */
  lsm6dsox_fifo_watermark_set(&imu_dev, 10);
  /* Set FIFO batch XL/Gyro ODR to 12.5Hz */
  lsm6dsox_fifo_xl_batch_set(&imu_dev, LSM6DSOX_XL_BATCHED_AT_12Hz5);
  lsm6dsox_fifo_gy_batch_set(&imu_dev, LSM6DSOX_GY_BATCHED_AT_12Hz5);
  /* Set FIFO mode to Stream mode (aka Continuous Mode) */
  lsm6dsox_fifo_mode_set(&imu_dev, LSM6DSOX_STREAM_MODE);
  /* Enable drdy 75 μs pulse: uncomment if interrupt must be pulsed */
  //lsm6dsox_data_ready_mode_set(&imu_dev, LSM6DSOX_DRDY_PULSED);
  /* Uncomment if interrupt generation on Free Fall INT1 pin */
//  lsm6dsox_pin_int1_route_t int1_route;
//  lsm6dsox_pin_int1_route_get(&imu_dev, &int1_route);
//  int1_route.fifo_th = PROPERTY_ENABLE;
//  int1_route.fifo_full = PROPERTY_ENABLE;
//  int1_route.fifo_ovr = PROPERTY_ENABLE;
//  int1_route.fifo_bdr = PROPERTY_ENABLE;
//  lsm6dsox_pin_int1_route_set(&imu_dev, int1_route);
  /* Uncomment if interrupt generation on Free Fall INT2 pin */
//  lsm6dsox_pin_int2_route_t int2_route;
//  lsm6dsox_pin_int2_route_get(&imu_dev, NULL, &int2_route);
//  int2_route.fifo_th = PROPERTY_ENABLE;
//  int2_route.fifo_bdr = PROPERTY_ENABLE;
//  int2_route.fifo_full = PROPERTY_ENABLE;
//  int2_route.fifo_ovr = PROPERTY_ENABLE;
//  lsm6dsox_pin_int2_route_set(&imu_dev, NULL, int2_route);
  /* Set Output Data Rate */
//  lsm6dsox_xl_data_rate_set(&imu_dev, LSM6DSOX_XL_ODR_12Hz5); WRONG?
//  lsm6dsox_gy_data_rate_set(&imu_dev, LSM6DSOX_GY_ODR_12Hz5); WRONG?

  lsm6dsox_xl_data_rate_set(&imu_dev, LSM6DSOX_XL_ODR_OFF); // RIGHT?
  lsm6dsox_gy_data_rate_set(&imu_dev, LSM6DSOX_GY_ODR_OFF); // RIGHT?

 

 

I have tried this with my old setup but it doesn't worked (although I didn't remember well all the details...)

 

Regards,

Álvaro

kyrreaa
Associate III

Sorry, I did not see that you had enabled the XL and GYR rates. I thought you had just selected rates for the FIFO (as this was what I had done and then it did not work).

For readout triggering I use the int1 routing of FIFO TH and it works for me.
I read the length of fifo as you do and then I read the number of samples indicated * 7 and decode each element based on the tag.

What I found useful was making sure the batch interval/watermark matched up with the ratio for accellerometer and gyro. Since I run the accelerometer faster than gyro (208Hz vs 26Hz) I have a 8:1 ratio here. So I set my watermark to 9. This gives me 8 acc + 1 gyr for every interrupt.

With equal value for acc/gyr and setting of 10 you should be getting 5 of each.

Maybe it is the order of operations?

I first always restore default configuration. Then I disable I3C and enable block updates.
Then I configure the watermark and batch rates first, before enabling both the acc and gyro by setting their rates to not powerdown. Finally I enable fifo batching by changing it from bypass mode to stream mode.

Try moving the lsm6dsox_xl_data_rate_set / lsm6dsox_gy_data_rate_set calls to enable them over the stream mode fifo call?

kyrreaa
Associate III

I just thought of something, since I use BDU mode (block data update) it is important I always read Status1 and then Status2 so that I get updated information. Your function lsm6dsox_fifo_wtm_flag_get() does only read status2 if it is implemented identical to the sample code I was supplied. Since you do not enable BDU I am not sure if this matters.