陀螺仪LSM6DSV80X开发(5)----高G唤醒中断 本文演示如何在 LSM6DSV80X 的 High-G 加速度计上配置 冲击/唤醒(HG Wakeup)事件检测:设置 High-G 采样率与量程、配置滤波链路、设置唤醒阈值与持续时间,并把事件映射到 INT1 引脚输出中断。最后在主循环中读取事件标志位,判断触发轴向并通过串口打印。
最近在弄ST的课程,需要样片的可以加群申请:615061293 。

[https://www.bilibili.com/video/BV1SzwTzdE6L/]
[https://www.wjx.top/vm/OhcKxJk.aspx#]
[https://download.csdn.net/download/qq_24312945/92915752]
首先需要准备一个开发板,这里我准备的是自己绘制的开发板,需要的可以进行申请。
主控为STM32H503CB,陀螺仪为LSM6DSV80X,磁力计为LIS2MDL。

https://github.com/CoreMaker-lab/LSM6DSV80X
https://gitee.com/CoreMaker/LSM6DSV80X
FIFO 可以存:
● Gyroscope(陀螺)
● Low-g accelerometer(低量程加速度)
● High-g accelerometer(高量程加速度)
● External sensors(最多 4 路外部传感器,走 sensor hub)
● Step counter(计步)
● Timestamp(时间戳)
● Temperature(温度)
● FSM events(FSM 事件)
● High-g peak value(高 G 峰值)
● MLC features/filters/results(MLC 特征/滤波/结果)

用STM32CUBEMX生成例程,这里使用MCU为STM32H503CB。
配置时钟树,配置时钟为250M。

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

配置串口,速率为2000000。



LSM6DSV80X最大IIC通讯速率为1M,配置IIC速度为400k




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



INT1管脚为PB1。


配置如下所示。

开启中断。



打开魔术棒,勾选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/lsm6dsv80x-pid
由于需要向LSM6DSV80X_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);
lsm6dsv80x_pin_int_route_hg_t pin_int = { 0 };
lsm6dsv80x_hg_wake_up_cfg_t wu_cfg = { 0 };
lsm6dsv80x_hg_wu_interrupt_cfg_t int_cfg = { 0 };
/* 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);
可以向WHO_AM_I (0Fh)获取固定值,判断是否为0x73。

lsm6dsv80x_device_id_get为获取函数。

对应的获取ID驱动程序,如下所示。
/* Check device ID */
lsm6dsv80x_device_id_get(&dev_ctx, &whoamI);
printf("LSM6DSV80X_ID=0x%x,whoamI=0x%x",LSM6DSV80X_ID,whoamI);
if (whoamI != LSM6DSV80X_ID)
while (1);
写 0x01(FUNC_CFG_ACCESS)这个寄存器,把 SW_POR 置 1,然后等待芯片完成复位。
lsm6dsv80x_sw_por为 软件上电复位 / 全局复位 函数。

对应的驱动程序,如下所示。
/* Perform device power-on-reset */
lsm6dsv80x_sw_por(&dev_ctx);
在很多传感器中,数据通常被存储在输出寄存器中,这些寄存器分为两部分: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 */
lsm6dsv80x_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
高量程加速度速率可以通过CTRL1_XL_HG (4Eh)设置高量程加速度速率。

设置高量程加速度速率可以使用如下函数。
/* Set Output Data Rate.
* Selected data rate have to be equal or greater with respect
* with MLC data rate.
*/
lsm6dsv80x_hg_xl_data_rate_set(&dev_ctx, LSM6DSV80X_HG_XL_ODR_AT_960Hz, 1);
高量程加速度量程可以通过CTRL1_XL_HG (4Eh)设置。

设置高量程加速度量程可以使用如下函数。
/* Set full scale */
lsm6dsv80x_hg_xl_full_scale_set(&dev_ctx, LSM6DSV80X_80g);
需要注意的是高量程加速度的精度问题。

/* Configure filtering chain */
filt_settling_mask.drdy = PROPERTY_ENABLE;
filt_settling_mask.irq_xl = PROPERTY_ENABLE;
filt_settling_mask.irq_g = PROPERTY_ENABLE;
lsm6dsv80x_filt_settling_mask_set(&dev_ctx, filt_settling_mask);
lsm6dsv80x_filt_xl_lp2_set(&dev_ctx, PROPERTY_ENABLE);
lsm6dsv80x_filt_xl_lp2_bandwidth_set(&dev_ctx, LSM6DSV80X_XL_STRONG);
HG_FUNCTIONS_ENABLE (0x52) 的 HG_SHOCK_DUR[3:0](冲击状态退出持续时间)。
HG_SHOCK_DUR[s] = (HG_SHOCK_DUR + 1) * 512 / ODR_XL_HG
前面把 ODR 设为 960 Hz,所以:
● hg_shock_dur=1 → (1+1)*512/960 ≈ 1.07 s
检测到一次 high-g 事件后,芯片会用这个“持续时间/去抖窗口”来定义 shock 状态的保持/退出节奏,避免事件抖动导致中断疯狂触发

HG_WAKE_UP_THS (0x53) 的 HG_WK_THS[7:0](high-g wake-up 阈值)。
● 分辨率规则: 1 g/LSB。
● FS 选了 ±80 g,所以:
● hg_wakeup_ths=4 ≈ 4 g 阈值
● 直观含义:任一轴的 high-g 加速度超过约 4 g,就会被判定为 wake-up(后续再通过你读到的 hg_wakeup_x/y/z 来看是哪一轴触发)。
wu_cfg.hg_shock_dur = 1;
wu_cfg.hg_wakeup_ths = 4;
lsm6dsv80x_hg_wake_up_cfg_set(&dev_ctx, wu_cfg);
把“HG wakeup 事件(DRDY_XL)路由到芯片的 INT1 引脚上,从而让 INT1 产生脉冲/中断 去唤醒 MCU。
/* enable interrupt on HG wakeup */
pin_int.hg_wakeup = PROPERTY_ENABLE;
lsm6dsv80x_pin_int1_route_hg_set(&dev_ctx, &pin_int);
//lsm6dsv80x_pin_int2_route_hg_set(&dev_ctx, &pin_int);
LSM6DSV80X_HG_FUNCTIONS_ENABLE 寄存器中的 hg_interrupts_enable 字段为 1。
把 HG 相关事件(包括 hg_wakeup)允许输出到中断系统。

int_cfg.hg_interrupts_enable = 1;
lsm6dsv80x_hg_wu_interrupt_cfg_set(&dev_ctx, int_cfg);
lsm6dsv80x_hg_event_get() 读 0x4C → 如果 HG_WU_IA 等位为 1 → 再判断 HG_X_WU/HG_Y_WU/HG_Z_WU → 打印是哪几个轴超过阈值。


/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if (thread_wake) {
lsm6dsv80x_hg_event_t status;
thread_wake = 0;
lsm6dsv80x_hg_event_get(&dev_ctx, &status);
if (status.hg_event) {
if (status.hg_wakeup) {
uint8_t axis = 0;
if (status.hg_wakeup_x) {
axis |= AXIS_X;
}
if (status.hg_wakeup_y) {
axis |= AXIS_Y;
}
if (status.hg_wakeup_z) {
axis |= AXIS_Z;
}
printf("WAKEUP event on X: %d, Y = %d, Z= %drn",
(axis & AXIS_X) ? 1 : 0,
(axis & AXIS_Y) ? 1 : 0,
(axis & AXIS_Z) ? 1 : 0);
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

审核编辑 黄宇
全部0条评论
快来发表一下你的评论吧 !