陀螺仪LSM6DSOW开发(3)----FIFO数据读取与配置

描述

概述

本文档旨在详细介绍如何配置和读取LSM6DSOW传感器的FIFO数据。LSM6DSOW是一款高性能的6轴IMU(惯性测量单元),集成了三轴加速度计和三轴陀螺仪。FIFO(先进先出)缓冲区是LSM6DSOW的重要功能之一,它能够有效地存储传感器数据,减少主机的读取频率,从而降低功耗和提高数据采集效率。

最近在弄ST和瑞萨RA的课程,需要样片的可以加群申请:615061293 。

mems

视频教学

https://www.bilibili.com/video/BV1Dw4m1r712/

样品申请

https://www.wjx.top/vm/OhcKxJk.aspx#

源码下载

https://download.csdn.net/download/qq_24312945/89592307

硬件准备

首先需要准备一个开发板,这里我准备的是自己绘制的开发板,需要的可以进行申请。 主控为STM32H503CB,陀螺仪为LSM6DSOW,磁力计为LIS2MDL。

mems

主要内容

  1. 初始化LSM6DSOW传感器并检查其设备ID
  2. 恢复传感器默认配置并设置必要的参数
  3. 配置FIFO模式和水印阈值
  4. 设置加速度计和陀螺仪的数据速率
  5. 连续读取FIFO中的传感器数据并解析输出

LSM6DSOW支持六种不同的FIFO模式,每种模式适用于不同的应用场景:

  1. Bypass Mode(旁路模式):
    ○ 在旁路模式下,FIFO不运行,传感器数据直接输出,不存储在FIFO中。该模式常用于实时数据读取。
  2. FIFO Mode(FIFO模式):
    ○ 在FIFO模式下,数据连续存储到FIFO中,直到FIFO满。当FIFO满时,旧数据将被新数据覆盖。适用于需要连续存储数据供后续处理的情况。
  3. Continuous Mode(连续模式):
    ○ 在连续模式下,FIFO始终保存最新的数据,当FIFO满时,旧数据被丢弃,新数据继续写入FIFO。适用于需要实时监控最新数据的应用。
  4. Continuous to FIFO Mode(连续到FIFO模式):
    ○ 开始时处于连续模式,当检测到某个事件时切换到FIFO模式。适用于在特定事件发生后保存数据。
  5. Bypass to Continuous Mode(旁路到连续模式):
    ○ 开始时处于旁路模式,当检测到某个事件时切换到连续模式。适用于事件发生后开始实时数据监控。
  6. Bypass to FIFO Mode(旁路到FIFO模式):
    ○ 开始时处于旁路模式,当检测到某个事件时切换到FIFO模式,开始存储数据。适用于事件发生后开始数据记录。

mems

生成STM32CUBEMX

用STM32CUBEMX生成例程,这里使用MCU为STM32H503CB。

配置时钟树,配置时钟为250M。

mems

串口配置

查看原理图,PA9和PA10设置为开发板的串口。

mems

配置串口,速率为2000000。

mems

IIC配置

mems

LSM6DSOW最大IIC通讯速率为400k。

mems

配置IIC速度为400k

mems

CS和SA0设置

mems

mems

由于还有一个磁力计,需要把该CS也使能。

mems

mems

INT设置

mems

配置为输入检测模式。

mems

ICASHE

mems

修改堆栈

mems

串口重定向

打开魔术棒,勾选MicroLIB

mems

在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/lsm6dso-pid

初始化管脚

由于需要向LSM6DSO_I2C_ADD_L写入以及为IIC模式。

mems

所以使能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);


  stmdev_ctx_t dev_ctx;
  /* Initialize mems driver interface */
  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)获取固定值,判断是否为0x6C

mems

lsm6dso_device_id_get为获取函数。

mems

对应的获取ID驱动程序,如下所示。

/* Check device ID */
  lsm6dso_device_id_get(&dev_ctx, &whoamI);
    printf("LSM6DSO_ID=0x%x,whoamI=0x%x",LSM6DSO_ID,whoamI);
  if (whoamI != LSM6DSO_ID)
    while (1);

复位操作

可以向CTRL3 (12h)的SW_RESET寄存器写入1进行复位。

mems

lsm6dso_reset_set为重置函数。

mems

对应的驱动程序,如下所示。

/* Restore default configuration */
  lsm6dso_reset_set(&dev_ctx, PROPERTY_ENABLE);

  do {
    lsm6dso_reset_get(&dev_ctx, &rst);
  } while (rst);

关闭I3C

/* Disable I3C interface */
  lsm6dso_i3c_disable_set(&dev_ctx, LSM6DSO_I3C_DISABLE);

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进行开启。

mems 对应的驱动程序,如下所示。

/* Enable Block Data Update */
  lsm6dso_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);

设置量程和速率

速率可以通过CTRL1 (10h)设置加速度速率和CTRL2 (11h)进行设置角速度速率。

mems

mems

设置加速度量程可以通过CTRL1 (10h)进行设置。

mems

设置角速度量程可以通过CTRL2 (11h)进行设置。

mems

设置加速度和角速度的量程和速率可以使用如下函数。

/* Set Output Data Rate */
  lsm6dso_xl_data_rate_set(&dev_ctx, LSM6DSO_XL_ODR_12Hz5);
  lsm6dso_gy_data_rate_set(&dev_ctx, LSM6DSO_GY_ODR_12Hz5);
  /* Set full scale */
  lsm6dso_xl_full_scale_set(&dev_ctx, LSM6DSO_2g);
  lsm6dso_gy_full_scale_set(&dev_ctx, LSM6DSO_2000dps);

设置FIFO水印

可编程FIFO阈值可以通过FIFO_CTRL1(07h)和FIFO_CTRL2(08h)寄存器中的WTM8[0]位设置。为了监视FIFO状态,可以读取专用寄存器(FIFO_STATUS1(3Ah),FIFO_STATUS2(3Bh)),以检测FIFO溢出事件、FIFO满状态、FIFO空状态、FIFO水位状态和FIFO中存储的未读样本数。

mems

LSM6DSOW传感器通过一系列控制寄存器来配置和管理FIFO。通过配置WTM,用户可以灵活地管理传感器数据的批处理。当数据量达到设定的阈值时,主处理器可以一次性读取大量数据,提高数据读取效率,减少频繁的I/O操作。 1 LSB = 1传感器(6字节) + TAG(1字节)写入FIFO

mems

/* Set FIFO watermark (number of unread sensor data TAG + 6 bytes
   * stored in FIFO) to 10 samples
   */
  lsm6dso_fifo_watermark_set(&dev_ctx, 10);

FIFO_CTRL3寄存器用于选择陀螺仪和加速度计数据在FIFO中的批处理数据速率(BDR)。每个传感器都有独立的控制位,可以设置不同的批处理数据速率,从而控制数据写入FIFO的频率。

mems

/* Set FIFO batch XL/Gyro ODR to 12.5Hz */
  lsm6dso_fifo_xl_batch_set(&dev_ctx, LSM6DSO_XL_BATCHED_AT_12Hz5);
  lsm6dso_fifo_gy_batch_set(&dev_ctx, LSM6DSO_GY_BATCHED_AT_12Hz5);

FIFO_CTRL4寄存器用于配置LSM6DSOW传感器的FIFO模式、时间戳批处理和温度数据批处理速率。该寄存器包含多个字段,每个字段的功能如下所述。
FIFO_MODE[2:0]: FIFO模式选择
● 用于选择FIFO的工作模式。
● 000: Bypass mode(旁路模式),FIFO禁用
● 001: FIFO mode(FIFO模式),FIFO满时停止收集数据
● 010: 保留
● 011: Continuous-to-FIFO mode(连续到FIFO模式),连续模式直到触发器释放,然后进入FIFO模式
● 100: Bypass-to-continuous mode(旁路到连续模式),旁路模式直到触发器释放,然后进入连续模式
● 101: 保留
● 110: Continuous mode(连续模式),FIFO满时新数据覆盖旧数据
● 111: Bypass-to-FIFO mode(旁路到FIFO模式),旁路模式直到触发器释放,然后进入FIFO模式

mems

/* Set FIFO mode to Stream mode (aka Continuous Mode) */
  lsm6dso_fifo_mode_set(&dev_ctx, LSM6DSO_STREAM_MODE);

设置中断

COUNTER_BDR_REG1寄存器用于配置批处理数据速率计数器的相关参数。该寄存器允许用户选择数据准备模式、重置内部计数器以及选择批处理事件的触发器。以下是COUNTER_BDR_REG1寄存器的详细描述。
COUNTER_BDR_REG1寄存器位字段
● dataready_pulsed: 启用脉冲数据准备模式
○ 0: 数据准备锁存模式(默认),仅在接口读取后返回0;
○ 1: 数据准备脉冲模式(数据准备脉冲持续时间为75微秒)。

mems

INT1_CTRL寄存器用于配置INT1引脚的控制信号。该寄存器的每个位可以启用一个信号,当MIPI I3CSM动态地址未分配时,信号可以通过INT1引脚传输。一些位还可以在使用MIPI I3CSM接口时触发IBI(带内中断)。引脚的输出是此处选择的信号与MD1_CFG(5Eh)中的信号的或组合。
INT1_CTRL寄存器字段描述
● DEN_DRDY_flag: 发送DEN_DRDY(DEN标记在传感器数据标志上)到INT1引脚。
● INT1_CNT_BDR: 启用COUNTER_BDR_IA中断在INT1引脚上。
● INT1_FIFO_FULL: 启用FIFO满中断在INT1引脚上。当使用MIPI I3CSM接口时,它还可以用于触发IBI。
● INT1_FIFO_OVR: 启用FIFO溢出中断在INT1引脚上。当使用MIPI I3CSM接口时,它还可以用于触发IBI。
● INT1_FIFO_TH: 启用FIFO阈值中断在INT1引脚上。当使用MIPI I3CSM接口时,它还可以用于触发IBI。
● INT1_BOOT: 启用引导状态在INT1引脚上。
● INT1_DRDY_G: 启用陀螺仪数据准备中断在INT1引脚上。当使用MIPI I3CSM接口时,它还可以用于触发IBI。
● INT1_DRDY_XL: 启用加速度计数据准备中断在INT1引脚上。当使用MIPI I3CSM接口时,它还可以用于触发IBI。

mems

lsm6dso_pin_int1_route_get(&dev_ctx, &int1_route);
  int1_route.fifo_th = PROPERTY_ENABLE;
  lsm6dso_pin_int1_route_set(&dev_ctx, int1_route);

获取FIFO数据

FIFO_STATUS寄存器用于监控LSM6DSOW传感器FIFO的状态。它们包括FIFO_STATUS1(3Ah)和FIFO_STATUS2(3Bh),分别用于报告未读数据和FIFO状态信息。

当FIFO中的数据量达到或超过预设的水位线时,FIFO_WTM_IA位将被置为1。这意味着主处理器可以通过读取该位的状态来确定何时需要处理FIFO中的数据。例如,当数据量达到水位线时,触发一次中断,主处理器读取并处理FIFO中的数据,然后继续下一轮数据采集。

mems

DIFF_FIFO 位于 FIFO_STATUS1 (3Ah) 和 FIFO_STATUS2 (3Bh) 寄存器中,用于指示FIFO中未读传感器数据的数量。它包括两个部分:
● DIFF_FIFO7:07:07:0: 位于 FIFO_STATUS1 寄存器中,表示未读数据的低8位。
● DIFF_FIFO9:89:89:8: 位于 FIFO_STATUS2 寄存器中,表示未读数据的高2位。
DIFF_FIFO字段用于跟踪FIFO中未读的数据量。通过读取DIFF_FIFO,可以确定FIFO中当前存储了多少数据,这对于决定何时读取FIFO中的数据非常重要。该字段的值在数据从FIFO中读取时会自动更新。

mems

FIFO_DATA_OUT_TAG (78h)寄存器用于标识FIFO中的传感器数据来源。该寄存器包含标识符(TAG),用于指示数据是由哪个传感器生成的,并帮助用户正确地解析FIFO中的数据。
TAG_SENSOR: 标识FIFO中的传感器数据源。根据传感器类型和数据源,该字段值表示具体的传感器数据。详细见下表。
FIFO_DATA_OUT_TAG 寄存器提供了数据标签,用于识别FIFO中存储的数据来源。这对于解析和处理从FIFO中读取的数据非常重要。通过TAG字段,用户可以区分不同传感器的数据,并采取适当的处理措施。

mems

FIFO_DATA_OUT_X, FIFO_DATA_OUT_Y 和 FIFO_DATA_OUT_Z 寄存器,这些寄存器用于读取LSM6DSOW传感器的FIFO中的X、Y和Z轴数据。每个轴的数据由两个寄存器组成:一个低字节寄存器(_L)和一个高字节寄存器(_H)。
为了从FIFO中读取加速度计或陀螺仪的X、Y、Z轴数据,需要依次读取对应的低字节和高字节寄存器,并将它们组合成一个完整的16位数据。

mems

mems

/* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    uint16_t num = 0;
    uint8_t wmflag = 0;
    lsm6dso_fifo_tag_t reg_tag;
    axis3bit16_t dummy;

        if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0))
        {
    /* Read watermark flag */
    lsm6dso_fifo_wtm_flag_get(&dev_ctx, &wmflag);

    if (wmflag > 0) {
      /* Read number of samples in FIFO */
      lsm6dso_fifo_data_level_get(&dev_ctx, &num);

      while (num--) {
        /* Read FIFO tag */
        lsm6dso_fifo_sensor_tag_get(&dev_ctx, ®_tag);

        switch (reg_tag) {
          case LSM6DSO_XL_NC_TAG:
            memset(data_raw_acceleration.u8bit, 0x00, 3 * sizeof(int16_t));
            lsm6dso_fifo_out_raw_get(&dev_ctx, data_raw_acceleration.u8bit);
            acceleration_mg[0] =
              lsm6dso_from_fs2_to_mg(data_raw_acceleration.i16bit[0]);
            acceleration_mg[1] =
              lsm6dso_from_fs2_to_mg(data_raw_acceleration.i16bit[1]);
            acceleration_mg[2] =
              lsm6dso_from_fs2_to_mg(data_raw_acceleration.i16bit[2]);
            printf("Acceleration [mg]:%4.2ft%4.2ft%4.2frn",
                    acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
            break;

          case LSM6DSO_GYRO_NC_TAG:
            memset(data_raw_angular_rate.u8bit, 0x00, 3 * sizeof(int16_t));
            lsm6dso_fifo_out_raw_get(&dev_ctx, data_raw_angular_rate.u8bit);
            angular_rate_mdps[0] =
              lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate.i16bit[0]);
            angular_rate_mdps[1] =
              lsm6dso_from_fs2000_to_mdps(data_raw_angular_rate.i16bit[1]);
            angular_rate_mdps[2] =
              lsm6dso_from_fs2000_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]);
            break;                

          default:
            /* Flush unused samples */
            memset(dummy.u8bit, 0x00, 3 * sizeof(int16_t));
            lsm6dso_fifo_out_raw_get(&dev_ctx, dummy.u8bit);
            break;
        }
      }
    }            
        }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */

演示

mems

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分