概述
LSM6DS3TR-C是STMicroelectronics公司推出的iNEMO惯性模块,集成了三轴加速度计和三轴陀螺仪,具备低功耗、强大的运动检测功能。该传感器支持多种操作模式,并内置FIFO缓冲区,用于批量处理和存储传感器数据。
FIFO(First In First Out)缓冲区在数据采集和处理过程中起着至关重要的作用。本文将介绍如何在LSM6DS3TR-C传感器中配置和读取FIFO数据,包括配置FIFO模式、设置数据速率和读取存储的数据。
最近在弄ST和瑞萨RA的课程,需要样片的可以加群申请:615061293 。
视频教学
[https://www.bilibili.com/video/BV1mS421d7eM/]
样品申请
[https://www.wjx.top/vm/OhcKxJk.aspx#]
源码下载
[https://download.csdn.net/download/qq_24312945/89504804]
主要内容
- 初始化LSM6DSV16X传感器并检查其设备ID
- 恢复传感器默认配置并设置必要的参数
- 配置FIFO模式和水印阈值
- 设置加速度计和陀螺仪的数据速率
- 连续读取FIFO中的传感器数据并解析输出
LSM6DS3TR-C支持多种FIFO模式,包括:
● Bypass模式:直接从寄存器读取数据,不使用FIFO。
● FIFO模式:数据写入FIFO,直到缓冲区满为止。
● Continuous模式:数据连续写入FIFO,新的数据会覆盖旧数据。
● Continuous-to-FIFO模式:初始阶段为连续模式,当特定条件满足时切换为FIFO模式。
● Bypass-to-Continuous模式:初始阶段为Bypass模式,当特定条件满足时切换为连续模式。
生成STM32CUBEMX
用STM32CUBEMX生成例程,这里使用MCU为STM32H503CB。
配置时钟树,配置时钟为250M。
串口配置
查看原理图,PA9和PA10设置为开发板的串口。
配置串口,速率为2000000。
IIC配置
LSM6DS3TR-C最大IIC通讯速率为400k。
配置IIC速度为400k
CS和SA0设置
由于还有一个磁力计,需要把该CS也使能。
ICASHE
修改堆栈
串口重定向
打开魔术棒,勾选MicroLIB
在main.c中,添加头文件,若不添加会出现 identifier "FILE" is undefined报错。
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
函数声明和串口重定向:
/* USER CODE BEGIN PFP */
int fputc(int ch, FILE *f){
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/* USER CODE END PFP */
参考驱动程序
[https://github.com/STMicroelectronics/lsm6ds3tr-c-pid]
FIFO参考程序
[https://github.com/STMicroelectronics/STMems_Standard_C_drivers/blob/master/lsm6ds3_STdC/examples/lsm6ds3_multi_read_fifo_simple.c]
初始化管脚
由于需要向LSM6DS3TR_C_I2C_ADD_L写入以及为IIC模式。
所以使能CS为高电平,配置为IIC模式。 配置SA0为低电平。
printf("HELLO!n");
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SA0_GPIO_Port, SA0_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(CS2_GPIO_Port, CS2_Pin, GPIO_PIN_SET);
HAL_Delay(100);
/* Initialize mems driver interface */
stmdev_ctx_t dev_ctx;
dev_ctx.write_reg = platform_write;
dev_ctx.read_reg = platform_read;
dev_ctx.mdelay = platform_delay;
dev_ctx.handle = &SENSOR_BUS;
/* Init test platform */
// platform_init();
/* Wait sensor boot time */
platform_delay(BOOT_TIME);
获取ID
可以向WHO_AM_I (0Fh)获取固定值,判断是否为0x6A
lsm6ds3tr_c_device_id_get为获取函数。
对应的获取ID驱动程序,如下所示。
/* Check device ID */
whoamI = 0;
lsm6ds3tr_c_device_id_get(&dev_ctx, &whoamI);
printf("LSM6DS3TR-C_ID=0x%x,whoamI=0x%x",LSM6DS3TR_C_ID,whoamI);
if ( whoamI != LSM6DS3TR_C_ID )
while (1); /*manage here device not found */
复位操作
可以向CTRL3 (12h)的SW_RESET寄存器写入1进行复位。
lsm6ds3tr_c_reset_set为重置函数。
对应的驱动程序,如下所示。
/* Restore default configuration */
lsm6ds3tr_c_reset_set(&dev_ctx, PROPERTY_ENABLE);
do {
lsm6ds3tr_c_reset_get(&dev_ctx, &rst);
} while (rst);
设置量程
设置加速度量程可以配置CTRL1_XL (10h)寄存器的FS_XL,FS_XL [1:0]可以设置量程。
设置角速度量程可以配置CTRL2_G (11h)寄存器的FS_G,FS_G [1:0]可以设置量程。
/* Set full scale */
lsm6ds3tr_c_xl_full_scale_set(&dev_ctx, LSM6DS3TR_C_2g);
lsm6ds3tr_c_gy_full_scale_set(&dev_ctx, LSM6DS3TR_C_2000dps);
BDU设置
在很多传感器中,数据通常被存储在输出寄存器中,这些寄存器分为两部分:MSB和LSB。这两部分共同表示一个完整的数据值。例如,在一个加速度计中,MSB和LSB可能共同表示一个加速度的测量值。
连续更新模式(BDU = ‘0’):在默认模式下,输出寄存器的值会持续不断地被更新。这意味着在你读取MSB和LSB的时候,寄存器中的数据可能会因为新的测量数据而更新。这可能导致一个问题:当你读取MSB时,如果寄存器更新了,接下来读取的LSB可能就是新的测量值的一部分,而不是与MSB相对应的值。这样,你得到的就是一个“拼凑”的数据,它可能无法准确代表任何实际的测量时刻。
块数据更新(BDU)模式(BDU = ‘1’):当激活BDU功能时,输出寄存器中的内容不会在读取MSB和LSB之间更新。这就意味着一旦开始读取数据(无论是先读MSB还是LSB),寄存器中的那一组数据就被“锁定”,直到两部分都被读取完毕。这样可以确保你读取的MSB和LSB是同一测量时刻的数据,避免了读取到代表不同采样时刻的数据。
简而言之,BDU位的作用是确保在读取数据时,输出寄存器的内容保持稳定,从而避免读取到拼凑或错误的数据。这对于需要高精度和稳定性的应用尤为重要。
可以向CTRL3 (12h)的BDU寄存器写入1进行开启。
对应的驱动程序,如下所示。
/* Enable Block Data Update */
lsm6ds3tr_c_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
设置速率
设置加速度速率可以配置CTRL1_XL (10h)寄存器,ODR_XL [3:0]可以设置速率。
设置角速度速率可以配置CTRL2_G (11h))寄存器,ODR_G [3:0]可以设置速率。
/* Set XL and Gyro Output Data Rate:
* in this example we set 12.5 Hz for Accelerometer and
* 12.5 Hz for Gyroscope
*/
lsm6ds3tr_c_xl_data_rate_set(&dev_ctx, LSM6DS3TR_C_XL_ODR_26Hz);
lsm6ds3tr_c_gy_data_rate_set(&dev_ctx, LSM6DS3TR_C_GY_ODR_26Hz);
FIFO读取程序
FIFO中的数据组织如下:
文档中提到,每个数据集由6个字节组成:
● 陀螺仪数据:6字节
● 加速度计数据:6字节
● 外部传感器数据:6字节
● 步数计和时间戳信息:6字节(包含时间戳)
设置FIFO水印
FIFO水印阈值的配置在寄存器FIFO_CTRL1和FIFO_CTRL2中,具体的设置如下:
● FIFO_CTRL1寄存器(0x06h):
○ 包含低8位的水印阈值FTH_[7:0],每一位代表2个字节(1个字)的FIFO数据。
● FIFO_CTRL2寄存器(0x07h):
○ 包含高3位的水印阈值FTH_[10:8],与FIFO_CTRL1一起使用时,可以设置更高的水印阈值。
在LSM6DS3TR-C传感器中,FIFO的最小分辨率是1个最低有效位(LSB),对应于2个字节(1个字)。这意味着每次写入FIFO的数据块的最小单位是2个字节。
当配置FIFO时,用户需要确保所设置的水印阈值和读取操作符合这个最小分辨率。例如,如果设置了水印阈值为2410,这意味着当FIFO中存储了2410*2个字节的数据时,就会触发相应的水印事件(如中断)。根据这个最小分辨率,每个数据块的大小是2个字节,因此,240个数据块相当于480个数据。
/* Set FIFO watermark to a multiple of a pattern
* in this example we set watermark to 10 pattern
* which means ten sequence of:
* (GYRO + XL) = 12 bytes
* (external sensor+timestamp) = 12 bytes
*/
lsm6ds3tr_c_int1_route_t int_1_reg;
uint16_t pattern_len = 24; // 每个数据集由6个字节组成,4*6=24,每个数据块的大小是2个字节
lsm6ds3tr_c_fifo_watermark_set(&dev_ctx, 10 * pattern_len);
使用流模式
FIFO模式的设置在寄存器FIFO_CTRL5中,具体的设置如下:
● FIFO_MODE_[2:0]: 控制FIFO的工作模式。
○ 000: Bypass模式,FIFO禁用。
○ 001: FIFO模式,当FIFO满时停止收集数据。
○ 011: 连续模式,直到触发器解除,然后切换为FIFO模式。
○ 100: Bypass模式,直到触发器解除,然后切换为连续模式。
○ 110: 连续模式,如果FIFO满,新样本会覆盖旧样本。
使用流模式有以下优点
持续数据采集:适用于需要连续监控的场景,如运动跟踪和实时监控应用。
数据最新性:始终获取到最新的数据,避免数据滞后。
无需等待FIFO清空:当FIFO填满时,新数据自动覆盖旧数据,无需手动清空FIFO。
/* Set FIFO mode to Stream mode */
lsm6ds3tr_c_fifo_mode_set(&dev_ctx, LSM6DS3TR_C_STREAM_MODE);
// /* Enable FIFO watermark interrupt generation on INT1 pin */
// lsm6ds3tr_c_pin_int1_route_get(&dev_ctx, &int_1_reg);
// int_1_reg.int1_fth = PROPERTY_ENABLE;
// lsm6ds3tr_c_pin_int1_route_set(&dev_ctx, int_1_reg);
启用时间戳计数功能
通过设置 CTRL10_C 寄存器中的 timer_en 和 func_en 位来启用 LSM6DS3TR-C 传感器的时间戳计数功能。时间戳计数功能允许传感器记录事件发生的时间,便于时间同步和数据记录分析。
/* Enable timestamp and add it to FIFO */
lsm6ds3tr_c_timestamp_set(&dev_ctx, PROPERTY_ENABLE);
设置时间戳写入FIFO
LSM6DS3TR-C传感器的时间戳批处理速率、温度数据批处理速率、增强的EIS陀螺仪输出批处理,以及FIFO的工作模式。这些配置确保传感器数据能够以适当的速率和模式进行批处理和存储,以满足不同的应用需求。
FIFO_CTRL2寄存器中,timer_pedo_fifo_en位用于控制是否将步数计数器和时间戳数据作为第四个FIFO数据集。具体含义如下:
● 0: 禁用步数计数器和时间戳数据作为第四个FIFO数据集。
○ 当timer_pedo_fifo_en位设置为0时,步数计数器和时间戳数据不会被存储在FIFO中。
● 1: 启用步数计数器和时间戳数据作为第四个FIFO数据集。
○ 当timer_pedo_fifo_en位设置为1时,步数计数器和时间戳数据将被存储在FIFO中,作为第四个数据集。
lsm6ds3tr_c_fifo_pedo_and_timestamp_batch_set(&dev_ctx,PROPERTY_ENABLE);
设置时间戳分辨率
将 WAKE_UP_DUR 寄存器中的 TIMER_HR 位设置为特定的值,以改变时间戳寄存器的分辨率。
时间戳数据为24位的大小。
/* Set the timestamp resolution to 25 μs (TIMER_HR bit in WAKE_UP_DUR register) */
lsm6ds3tr_c_timestamp_res_set(&dev_ctx, LSM6DS3TR_C_LSB_25us);
FIFO存储时间戳设置
通过配置FIFO_CTRL4寄存器中的DEC_DS4_FIFO[2:0]字段来选择第4组FIFO数据集的降采样因子。
lsm6ds3tr_c_fifo_dataset_3_batch_set(&dev_ctx, LSM6DS3TR_C_FIFO_DS3_NO_DEC);
//FIFO_CTRL4 (09h)- >DEC_DS4_FIFO[2:0]
lsm6ds3tr_c_fifo_dataset_4_batch_set(&dev_ctx, LSM6DS3TR_C_FIFO_DS4_NO_DEC);
通过设置FIFO_CTRL2寄存器中的TIMER_PEDO_FIFO_EN和TIMER_PEDO_FIFO_DRDY位来启用和配置步数计数和时间戳数据存储。
// 启用时间戳写入FIFO第四数据集
//FIFO_CTRL2 (07h)- >TIMER_PEDO_FIFO_EN
lsm6ds3tr_c_fifo_pedo_and_timestamp_batch_set(&dev_ctx, PROPERTY_ENABLE);
设置FIFO速率
LSM6DS3TR-C传感器的FIFO控制寄存器3(FIFO_CTRL3)的内容,该寄存器用于选择陀螺仪和加速度计数据写入FIFO的批处理数据速率(BDR,Batch Data Rate)。以下是详细描述:
FIFO_CTRL3寄存器(地址09h),该寄存器包含两个主要字段:
● DEC_FIFO_GYRO [2:0]:选择陀螺仪数据的批处理速率。
● DEC_FIFO_XL [2:0]:选择加速度计数据的批处理速率。
FIFO_CTRL3寄存器的DEC_FIFO_XL字段用于设置加速度计数据的FIFO去采样率,具体配置如下:
● DEC_FIFO_XL [2:0]: 加速度计FIFO去采样率设置。
○ 000: 加速度计传感器不在FIFO中。
○ 001: 不进行去采样。
○ 010: 去采样因子为2。
○ 011: 去采样因子为3。
○ 100: 去采样因子为4。
○ 101: 去采样因子为8。
○ 110: 去采样因子为16。
○ 111: 去采样因子为32。
001表示“不进行去采样”,即加速度计数据写入FIFO的速率与加速度计的输出数据速率(ODR)相同。因此,如果DEC_FIFO_XL的值设置为001,则加速度计数据的FIFO写入速率直接等于加速度计的ODR。
/* Set FIFO batch XL/Gyro ODR to 12.5Hz */
lsm6ds3tr_c_fifo_xl_batch_set(&dev_ctx,LSM6DS3TR_C_FIFO_XL_NO_DEC);
lsm6ds3tr_c_fifo_gy_batch_set(&dev_ctx,LSM6DS3TR_C_FIFO_GY_NO_DEC);
设置FIFO数据可以通过FIFO_CTRL5 寄存器,可以配置传感器的 FIFO 模式和数据输出速率,以满足不同应用的需求。
/* Set ODR FIFO */
lsm6ds3tr_c_fifo_data_rate_set(&dev_ctx, LSM6DS3TR_C_FIFO_26Hz);
初始化
/* USER CODE BEGIN 2 */
printf("HELLO!n");
HAL_GPIO_WritePin(CS1_GPIO_Port, CS1_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(SA0_GPIO_Port, SA0_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(CS2_GPIO_Port, CS2_Pin, GPIO_PIN_SET);
HAL_Delay(100);
/* Initialize mems driver interface */
stmdev_ctx_t dev_ctx;
dev_ctx.write_reg = platform_write;
dev_ctx.read_reg = platform_read;
dev_ctx.mdelay = platform_delay;
dev_ctx.handle = &SENSOR_BUS;
/* Init test platform */
// platform_init();
/* Wait sensor boot time */
platform_delay(BOOT_TIME);
/* Check device ID */
whoamI = 0;
lsm6ds3tr_c_device_id_get(&dev_ctx, &whoamI);
printf("LSM6DS3TR-C_ID=0x%x,whoamI=0x%x",LSM6DS3TR_C_ID,whoamI);
if ( whoamI != LSM6DS3TR_C_ID )
while (1); /*manage here device not found */
/* Restore default configuration */
lsm6ds3tr_c_reset_set(&dev_ctx, PROPERTY_ENABLE);
do {
lsm6ds3tr_c_reset_get(&dev_ctx, &rst);
} while (rst);
/* 设置加速度计和陀螺仪的满量程范围 */
lsm6ds3tr_c_xl_full_scale_set(&dev_ctx, LSM6DS3TR_C_2g);
lsm6ds3tr_c_gy_full_scale_set(&dev_ctx, LSM6DS3TR_C_2000dps);
/* 启用块数据更新(BDU),当FIFO支持时 */
lsm6ds3tr_c_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
/* 设置加速度计和陀螺仪的输出数据速率:
* 在本例中,我们将加速度计和陀螺仪的速率设置为26 Hz
*/
lsm6ds3tr_c_xl_data_rate_set(&dev_ctx, LSM6DS3TR_C_XL_ODR_26Hz);
lsm6ds3tr_c_gy_data_rate_set(&dev_ctx, LSM6DS3TR_C_GY_ODR_26Hz);
/* 设置FIFO水印为模式的倍数
* 在本例中,我们将水印设置为10个模式
* 这意味着10个序列:
* (陀螺仪 + 加速度计) = 12字节
* (外部传感器 + 时间戳) = 12字节
*/
lsm6ds3tr_c_int1_route_t int_1_reg;
uint16_t pattern_len = 24; // 每个数据集由6个字节组成,4*6=24
lsm6ds3tr_c_fifo_watermark_set(&dev_ctx, 10 * pattern_len);
/* 将FIFO模式设置为流模式 */
//FIFO_CTRL5(0x0A)- >STREAM_MODE
lsm6ds3tr_c_fifo_mode_set(&dev_ctx, LSM6DS3TR_C_STREAM_MODE);
/* 启用时间戳并将其添加到FIFO */
//CTRL10_C (19h)- >TIMER_EN
lsm6ds3tr_c_timestamp_set(&dev_ctx, PROPERTY_ENABLE);
//CTRL10_C (19h)- >PEDO_EN
lsm6ds3tr_c_pedo_sens_set(&dev_ctx, PROPERTY_ENABLE); // 根据需求配置步数计数
/* 将时间戳分辨率设置为25 μs (WAKE_UP_DUR寄存器中的TIMER_HR位) */
//WAKE_UP_DUR (5Ch)- >TIMER_HR
lsm6ds3tr_c_timestamp_res_set(&dev_ctx, LSM6DS3TR_C_LSB_25us);
//设置第3数据集(Dataset 3)的降采样因子
lsm6ds3tr_c_fifo_dataset_3_batch_set(&dev_ctx, LSM6DS3TR_C_FIFO_DS3_NO_DEC);
//设置第4数据集(Dataset 4)的降采样因子
//FIFO_CTRL4 (09h)- >DEC_DS4_FIFO[2:0]
lsm6ds3tr_c_fifo_dataset_4_batch_set(&dev_ctx, LSM6DS3TR_C_FIFO_DS4_NO_DEC);
// 启用时间戳写入FIFO第四数据集
//FIFO_CTRL2 (07h)- >TIMER_PEDO_FIFO_EN
lsm6ds3tr_c_fifo_pedo_and_timestamp_batch_set(&dev_ctx, PROPERTY_ENABLE);
/* 设置FIFO传感器的降采样因子 */
lsm6ds3tr_c_fifo_xl_batch_set(&dev_ctx, LSM6DS3TR_C_FIFO_XL_NO_DEC);
lsm6ds3tr_c_fifo_gy_batch_set(&dev_ctx, LSM6DS3TR_C_FIFO_GY_NO_DEC);
/* 设置FIFO的输出数据速率 */
//FIFO_CTRL5 (0Ah)
lsm6ds3tr_c_fifo_data_rate_set(&dev_ctx, LSM6DS3TR_C_FIFO_26Hz);
/* USER CODE END 2 */
获取FIFO数据
当对FIFO输出寄存器FIFO_DATA_OUT_L (3Eh)和FIFO_DATA_OUT_H (3Fh)进行多次读取操作时,舍入功能会自动启用。
对LSM6DS3TR-C传感器的配置,并从FIFO中读取加速度、角速度、时间戳和外部传感器数据。
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
uint16_t num = 0,num1=0;
uint16_t num_pattern = 0;
uint8_t waterm = 0;
/* 读取LSM6DS3TR-C的水印标志 */
lsm6ds3tr_c_fifo_wtm_flag_get(&dev_ctx, &waterm);
if (waterm) {
/* 读取FIFO中的字数 */
lsm6ds3tr_c_fifo_data_level_get(&dev_ctx, &num);
num_pattern = num / 24*2;
printf("num=%dn",num);
while (num_pattern-- > 0) {
printf ("num1=%dn",num1);
num1++;
/* 根据传感器的ODR配置,FIFO模式由以下样本序列组成:GYRO, XL 外部传感器 时间戳*/
lsm6ds3tr_c_fifo_raw_data_get(&dev_ctx,
data_raw_angular_rate.u8bit,
3 * sizeof(int16_t));
angular_rate_mdps[0] =
lsm6ds3tr_c_from_fs2000dps_to_mdps(data_raw_angular_rate.i16bit[0]);
angular_rate_mdps[1] =
lsm6ds3tr_c_from_fs2000dps_to_mdps(data_raw_angular_rate.i16bit[1]);
angular_rate_mdps[2] =
lsm6ds3tr_c_from_fs2000dps_to_mdps(data_raw_angular_rate.i16bit[2]);
printf(
"Angular rate [mdps]:%4.2ft%4.2ft%4.2frn",
angular_rate_mdps[0], angular_rate_mdps[1], angular_rate_mdps[2]);
lsm6ds3tr_c_fifo_raw_data_get(&dev_ctx,
data_raw_acceleration.u8bit,
3 * sizeof(int16_t));
acceleration_mg[0] =
lsm6ds3tr_c_from_fs2g_to_mg(data_raw_acceleration.i16bit[0]);
acceleration_mg[1] =
lsm6ds3tr_c_from_fs2g_to_mg(data_raw_acceleration.i16bit[1]);
acceleration_mg[2] =
lsm6ds3tr_c_from_fs2g_to_mg(data_raw_acceleration.i16bit[2]);
printf("Acc [mg]:%4.2ft%4.2ft%4.2frn",
acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
//外部传感器数据
lsm6ds3tr_c_fifo_raw_data_get(&dev_ctx,
data_raw_none.u8bit,
3 * sizeof(int16_t));
// 打印外部传感器数据
printf("External sensor data: %02x %02x %02x %02x %02x %02xrn",
data_raw_none.u8bit[0], data_raw_none.u8bit[1], data_raw_none.u8bit[2],
data_raw_none.u8bit[3], data_raw_none.u8bit[4], data_raw_none.u8bit[5]);
/* 读取时间戳数据 */
uint32_t timestamp=0;
lsm6ds3tr_c_fifo_raw_data_get(&dev_ctx,
data_raw_Timestamp.u8bit,
3*sizeof(int16_t));//
for(int i=0;i< 6;i++)
{
printf("t[%d]=%d ",i,data_raw_Timestamp.u8bit[i]);
}
timestamp=(data_raw_Timestamp.u8bit[1]< < 16)|(data_raw_Timestamp.u8bit[0]< < 8)
|(data_raw_Timestamp.u8bit[3]);
printf("Timestamp: %urn", timestamp);
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
演示
实际测试如下所示,数据为20个数据。
加速度速率为26Hz,角速度速率为26Hz。
时间戳速率26Hz为38.46ms。
下图中的2个时间戳数据为5825473和5823931,5825473-5823931=1542*25us=38.550ms
审核编辑 黄宇
-
陀螺仪
+关注
关注
44文章
749浏览量
97954 -
数据采集
+关注
关注
38文章
5090浏览量
112771 -
fifo
+关注
关注
3文章
379浏览量
43243
发布评论请先 登录
相关推荐
评论