2023-11-18 11:51 AM
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
2025-01-27 05:00 AM
Hi Kyrreaa,
I also misunderstood you and tough you had shutdown the ODR_XL and ODR_GY, but then the correct is enable ODR_XL/GYR and BATCH_XL/GYR.
The order I followed is the same on the git hub example, which is pretty much the same you are using (although you said that you enable the fifo batching in the last step).
I tried the same sequence (reset, ic3_disable, block_data_update, watermark, batch_set, scale+odr_set, fifo_mode_set_stream) but still get stuck in the loop
while (!wmflag) {
lsm6dsox_fifo_wtm_flag_get(&imu_dev, &wmflag);
}
And if I bypass the loop, the lsm6dsox_fifo_data_level_get(&imu_dev, &fifo_num_samples) return there is no samples in the FIFO, which is consistent with no watermark_flag being triggered
Maybe is something related with the interruption :\
Did you also tried check the watermark_flag?
Regards,
Álvaro
2025-01-27 05:10 AM
I never check the WTM flag as I use a level interrupt on the int1 pin. When I get the interrupt I disable it and trigger reading of data. Once the reading is done I re-enable my local int1 interrupt and if the level is still high this triggers a new read immediately.
I did find an interesting line in the appnote though:
"The selected batch data rate must be equal to or lower than the output data rate
configured through the ODR_XL and ODR_G fields of the CTRL1_XL and CTRL2_G registers."
This explains why I had issues before. The ODR dictates the actual rate the system works at, and the batching rates will decimate the data from this.
2025-01-27 05:25 AM
Hi Kyrreaa,
I though block_data_update applies only to the updates in the acc and gyro readings, but I tried
As you said, the lsm6dsox_fifo_wtm_flag_get() reads only status2, and I added a prior call for reading status1 reg
while (!wmflag) {
lsm6dsox_read_reg(&imu_dev, LSM6DSOX_FIFO_STATUS1, &wmflag, 1);
lsm6dsox_fifo_wtm_flag_get(&imu_dev, &wmflag);
}
but no luck... I also had configured the batch data rate and the output data rate at the same frequency, so I guess that it's ok
I think the problem is "turning on the FIFO", and maybe it's mandatory to use the interrupt. I'll try to explore that way, although it will require a closer look on the code from my side. But at least, I know some one was able to get the FIFO working...!
Regards,
Álvaro
2025-01-27 05:28 AM
Yes, the FIFO absolutely does work.
Since my code is doing so much other stuff I can't be polling the flags, thus I never tried that.
I'll add a check for the flag to see what state it is in before and after reading the data. Just to see.
I have searched for errata just to be sure but have not found any public document about it.
2025-01-27 05:52 AM
OK, results are in...
FIFO STATUS before/after reading data: 0x8009 / 0x0000
Upper bit is the FIFO_WTM_IA and since I use a watermark of 9 that fits the bottom 10 bits showing 9.
2025-01-28 02:26 AM
Hi Kirreaa,
I have been doing some tries with the interrupt, and I found that when I was setting the fifo stream mode, after reading the value I get a bypass value, thus it appears to be a misconfiguration on the communication on the SPI line and I was reading always 0x00... (just for making a quick try...)
I tried with another hardware configuration, and I was able to pass the watermark flag loop, thus I think my initial problem was in the block_data_update+reg_status2 reading (I also found the note in the dataset warning about it's required reading both registers when bloc_data_update enabled).
Now I'm facing troubles with the lsm6dsox_fifo_data_level_get(&imu_dev, &fifo_num_samples), as it gets also 0 samples stored, but I will investigate that later...
Thankyou very much for pointing me on the block_data_update!
Regards,
Álvaro