陀螺仪LSM6DSV320X开发(1)----轮询获取陀螺仪数据 LSM6DSV320X 是面向高强度运动与高冲击记录场景的一项重要升级。它通过低g与高g的高效覆盖,结合片上先进处理能力,可在持续运动追踪与强冲击事件捕获之间取得平衡,为需要获取高价值运动/冲击数据并进行深入分析的应用提供理想选择。无论是高强度运动追踪、冲击/跌落记录,还是对事件波形与动态细节的还原需求,LSM6DSV320X 都能提供稳定一致的测量表现与可用数据洞察。
最近在弄ST的课程,需要样片的可以加群申请:615061293 。
LSM6DSV320X 作为行业领先的高性能 6 轴 IMU,采用专用 high-g 加速度计通道,并引入创新机械结构以优化低加速度与高加速度的测量表现,实现从日常运动到猛烈冲击的连续覆盖。其 low-g 加速度计最高可达 ±16 g,high-g 加速度计最高可达 ±320 g,陀螺仪最高可达 ±4000 dps;同时在2.5 × 3.0 × 0.83 mm 的紧凑封装内集成三颗完全同步的传感器,并提供 1.5 KB FIFO(压缩可至 4.5 KB),便于对冲击事件与高动态信号进行高保真记录与回溯分析。

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

[https://github.com/CoreMaker-lab/LSM6DSV320X]
[https://gitee.com/CoreMaker/LSM6DSV320X]
● 四通道架构分别处理UI、EIS、OIS和高g数据
● “智能全感知”的系统功率优化体验
● 高达4.5 KB的智能FIFO
● 双加速度计通道
○ 低g值通道±2/±4/±8/±16 g量程
○ 高g值通道支持±32/±64/±128/±256/±320 g量程
● ±250/±500/±1000/±2000/±4000 dps量程
● SPI/I²C和MIPI I3C® v1.1串行接口,支持主处理器数据同步功能
● 辅助SPI和MIPI I3C® v1.1接口,用于陀螺仪和加速度计的OIS数据输出
● 可通过辅助或主接口配置OIS
● 主接口的专用EIS通道,具有专用滤波功能
● 高级计步器,步伐侦测和步数计算
● 大幅运动检测,倾斜度检测
● 标准中断:自由落体、唤醒、6D/4D方向识别、单击和双击、高g唤醒和高g冲击
● 可编程有限状态机支持960 Hz高速率处理加速度计(高g/低g)、陀螺仪及外部传感器数据
● 面向AI应用的机器学习内核,支持功能导出并配有滤波器
● 嵌入式自适应自配置 (ASC)
● 嵌入式低功耗传感器融合 (SFLP) 算法
● 嵌入式温度传感器
● 独立IO供电
○ I²C电压范围:1.62 V至3.6 V
○ SPI/MIPI I3C®扩展电压范围:1.08 V至3.6 V
● 供电电流
○ 6轴配置@ 0.67 mA,组合高性能模式
○ 9轴配置@ 0.80 mA,组合高性能模式
● 紧凑外形:2.5 mm x 3 mm x 0.83 mm
● 符合ECOPACK和RoHS标准
用STM32CUBEMX生成例程,这里使用MCU为STM32H503CB。
配置时钟树,配置时钟为250M。

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

配置串口,速率为2000000。
对于LSM6DSV320X,可以使用SPI或者IIC进行通讯。
最小系统图如下所示。
在CS管脚为1的时候,为IIC模式。

本文使用的板子原理图如下所示。


在使用IIC通讯模式的时候,SA0是用来控制IIC的地址位的。
对于IIC的地址,可以通过TA0引脚修改。TA0引脚可以用来修改设备地址的最低有效位。如果TA0引脚连接到电源电压,LSb(最低有效位)为'1'(地址1101011b);否则,如果TA0引脚连接到地线,LSb的值为'0'(地址1101010b)。
接口如下所示。
主要使用的管脚为CS、SCL、SDA、SA0。

该模块支持的速度为普通模式(100k)和快速模式(400k)以及快速模式+(1M)。



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




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





打开魔术棒,勾选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/lsm6dsv320x-pid
由于需要向LSM6DSV320X_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);
stmdev_ctx_t dev_ctx;
double_t lowg_xl_sum[3], hg_xl_sum[3], gyro_sum[3], temp_sum;
uint16_t lowg_xl_cnt = 0, hg_xl_cnt = 0, gyro_cnt = 0, temp_cnt = 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。

lsm6dsv320x_device_id_get为获取函数。

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

lsm6dsv320x_sw_por为 软件上电复位 / 全局复位 函数。

对应的驱动程序,如下所示。
/* Perform device power-on-reset */
lsm6dsv320x_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 */
lsm6dsv320x_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
低量程加速度速率可以通过CTRL1 (10h)设置加速度速率。

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

设置高量程加速度速率可以使用如下函数。
lsm6dsv320x_hg_xl_data_rate_set(&dev_ctx, LSM6DSV320X_HG_XL_ODR_AT_960Hz, 1);
角速度量程可以通过CTRL2 (11h)设置角速度速率。

设置角速度速率可以使用如下函数。
lsm6dsv320x_gy_setup(&dev_ctx, LSM6DSV320X_ODR_AT_120Hz, LSM6DSV320X_GY_HIGH_PERFORMANCE_MD);l
低量程加速度量程可以通过CTRL8 (17h)设置。

设置加速度量程可以使用如下函数。
/* Set full scale */
lsm6dsv320x_xl_full_scale_set(&dev_ctx, LSM6DSV320X_2g);
高量程加速度量程可以通过CTRL1_XL_HG (4Eh)设置。

设置高量程加速度量程可以使用如下函数。
lsm6dsv320x_hg_xl_full_scale_set(&dev_ctx, LSM6DSV320X_320g);
需要注意的是高量程加速度的精度问题。
角速度量程可以通过CTRL6 (15h)设置。
设置角速度量程量程可以使用如下函数。
lsm6dsv320x_gy_full_scale_set(&dev_ctx, LSM6DSV320X_2000dps);
/* Configure filtering chain */
filt_settling_mask.drdy = PROPERTY_ENABLE;
filt_settling_mask.irq_xl = PROPERTY_ENABLE;
filt_settling_mask.irq_g = PROPERTY_ENABLE;
lsm6dsv320x_filt_settling_mask_set(&dev_ctx, filt_settling_mask);
lsm6dsv320x_filt_gy_lp1_set(&dev_ctx, PROPERTY_ENABLE);
lsm6dsv320x_filt_gy_lp1_bandwidth_set(&dev_ctx, LSM6DSV320X_GY_ULTRA_LIGHT);
lsm6dsv320x_filt_xl_lp2_set(&dev_ctx, PROPERTY_ENABLE);
lsm6dsv320x_filt_xl_lp2_bandwidth_set(&dev_ctx, LSM6DSV320X_XL_STRONG);
lowg_xl_sum[0] = lowg_xl_sum[1] = lowg_xl_sum[2] = 0.0;
hg_xl_sum[0] = hg_xl_sum[1] = hg_xl_sum[2] = 0.0;
gyro_sum[0] = gyro_sum[1] = gyro_sum[2] = 0.0;
temp_sum = 0.0;
进入一个无限循环,不断检查是否有新的数据(加速度、角速率、温度)可用。
对于每种类型的数据(加速度、角速率、温度),如果有新数据,就读取原始数据,转换为对应的单位(毫克、毫度每秒、摄氏度),并通过串行输出打印。
对于数据是否准备好,可以访问STATUS_REG (1Eh)进行判断。

lsm6dsv320x_data_ready_t drdy;
/* Read output only if new xl value is available */
lsm6dsv320x_flag_data_ready_get(&dev_ctx, &drdy);
对于低量程加速度数据,可以通过28-2D进行获取。


对于高量程加速度数据,可以通过34-39进行获取。


对于角速度数据,可以通过22-27进行获取。

对于温度数据,可以通过20-21进行获取。

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
lsm6dsv320x_data_ready_t drdy;
/* Read output only if new xl value is available */
lsm6dsv320x_flag_data_ready_get(&dev_ctx, &drdy);
if (drdy.drdy_xl) {
/* Read acceleration field data */
memset(data_raw_motion, 0x00, 3 * sizeof(int16_t));
lsm6dsv320x_acceleration_raw_get(&dev_ctx, data_raw_motion);
acceleration_mg[0] = lsm6dsv320x_from_fs2_to_mg(data_raw_motion[0]);
acceleration_mg[1] = lsm6dsv320x_from_fs2_to_mg(data_raw_motion[1]);
acceleration_mg[2] = lsm6dsv320x_from_fs2_to_mg(data_raw_motion[2]);
lowg_xl_sum[0] += acceleration_mg[0];
lowg_xl_sum[1] += acceleration_mg[1];
lowg_xl_sum[2] += acceleration_mg[2];
lowg_xl_cnt++;
}
if (drdy.drdy_hgxl) {
/* Read acceleration field data */
memset(data_raw_motion, 0x00, 3 * sizeof(int16_t));
lsm6dsv320x_hg_acceleration_raw_get(&dev_ctx, data_raw_motion);
acceleration_mg[0] = lsm6dsv320x_from_fs256_to_mg(data_raw_motion[0]);
acceleration_mg[1] = lsm6dsv320x_from_fs256_to_mg(data_raw_motion[1]);
acceleration_mg[2] = lsm6dsv320x_from_fs256_to_mg(data_raw_motion[2]);
hg_xl_sum[0] += acceleration_mg[0];
hg_xl_sum[1] += acceleration_mg[1];
hg_xl_sum[2] += acceleration_mg[2];
hg_xl_cnt++;
}
/* Read output only if new xl value is available */
if (drdy.drdy_gy) {
/* Read angular rate field data */
memset(data_raw_motion, 0x00, 3 * sizeof(int16_t));
lsm6dsv320x_angular_rate_raw_get(&dev_ctx, data_raw_motion);
angular_rate_mdps[0] = lsm6dsv320x_from_fs2000_to_mdps(data_raw_motion[0]);
angular_rate_mdps[1] = lsm6dsv320x_from_fs2000_to_mdps(data_raw_motion[1]);
angular_rate_mdps[2] = lsm6dsv320x_from_fs2000_to_mdps(data_raw_motion[2]);
gyro_sum[0] += angular_rate_mdps[0];
gyro_sum[1] += angular_rate_mdps[1];
gyro_sum[2] += angular_rate_mdps[2];
gyro_cnt++;
}
if (drdy.drdy_temp) {
/* Read temperature data */
memset(&data_raw_temperature, 0x00, sizeof(int16_t));
lsm6dsv320x_temperature_raw_get(&dev_ctx, &data_raw_temperature);
temperature_degC = lsm6dsv320x_from_lsb_to_celsius(data_raw_temperature);
temp_sum += temperature_degC;
temp_cnt++;
}
if (lowg_xl_cnt >= CNT_FOR_OUTPUT) {
/* print avg low-g xl data */
acceleration_mg[0] = lowg_xl_sum[0] / lowg_xl_cnt;
acceleration_mg[1] = lowg_xl_sum[1] / lowg_xl_cnt;
acceleration_mg[2] = lowg_xl_sum[2] / lowg_xl_cnt;
printf("lg xl (avg of %d samples) [mg]:%4.2ft%4.2ft%4.2frn",
lowg_xl_cnt, acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
lowg_xl_sum[0] = lowg_xl_sum[1] = lowg_xl_sum[2] = 0.0;
lowg_xl_cnt = 0;
/* print avg high-g xl data */
acceleration_mg[0] = hg_xl_sum[0] / hg_xl_cnt;
acceleration_mg[1] = hg_xl_sum[1] / hg_xl_cnt;
acceleration_mg[2] = hg_xl_sum[2] / hg_xl_cnt;
printf("hg xl (avg of %d samples) [mg]:%4.2ft%4.2ft%4.2frn",
hg_xl_cnt, acceleration_mg[0], acceleration_mg[1], acceleration_mg[2]);
hg_xl_sum[0] = hg_xl_sum[1] = hg_xl_sum[2] = 0.0;
hg_xl_cnt = 0;
/* print avg gyro data */
angular_rate_mdps[0] = gyro_sum[0] / gyro_cnt;
angular_rate_mdps[1] = gyro_sum[1] / gyro_cnt;
angular_rate_mdps[2] = gyro_sum[2] / gyro_cnt;
printf("gyro (avg of %d samples) [mdps]:%4.2ft%4.2ft%4.2frn",
gyro_cnt, angular_rate_mdps[0], angular_rate_mdps[1], angular_rate_mdps[2]);
gyro_sum[0] = gyro_sum[1] = gyro_sum[2] = 0.0;
gyro_cnt = 0;
/* print avg temperature data */
temperature_degC = temp_sum / temp_cnt;
printf("Temperature (avg of %d samples) [degC]:%6.2frnrn",
temp_cnt, temperature_degC);
temp_cnt = 0;
temp_sum = 0.0;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */

全部0条评论
快来发表一下你的评论吧 !