210 lines
6.2 KiB
C
210 lines
6.2 KiB
C
/**
|
||
* ==================================================
|
||
* @file imu_lis3dhtr.c
|
||
* @brief TODO 描述该文件的功能
|
||
* @author wangb
|
||
* @date 2026-01-27 12:21
|
||
* @version 1.0
|
||
*
|
||
* @details 本文件包含...
|
||
*
|
||
* @copyright Copyright (c) 2026 wangb. All Rights Reserved.
|
||
*
|
||
* @license 不开源
|
||
* ==================================================
|
||
*/
|
||
|
||
|
||
#include "mems_lis3dhtr.h"
|
||
|
||
#include "cmsis_os2.h"
|
||
#include "elog.h"
|
||
#include "i2c.h"
|
||
|
||
|
||
volatile uint8_t lis3dh_int_flag = 0;
|
||
static uint8_t last_int_src = 0; // 记录上一次中断源
|
||
/* ================= 内部 I2C 读写 ================= */
|
||
|
||
void lis3dh_read(uint8_t reg, uint8_t *data, uint16_t len)
|
||
{
|
||
/* 多字节读必须置位 bit7 */
|
||
if (len > 1)
|
||
reg |= 0x80;
|
||
|
||
HAL_I2C_Mem_Read(&hi2c1,
|
||
LIS3DHTR_I2C_ADDR,
|
||
reg,
|
||
I2C_MEMADD_SIZE_8BIT,
|
||
data,
|
||
len,
|
||
1000);
|
||
}
|
||
|
||
void lis3dh_write(uint8_t reg, uint8_t data)
|
||
{
|
||
HAL_I2C_Mem_Write(&hi2c1,
|
||
LIS3DHTR_I2C_ADDR,
|
||
reg,
|
||
I2C_MEMADD_SIZE_8BIT,
|
||
&data,
|
||
1,
|
||
1000);
|
||
}
|
||
/* ================= 清除所有中断标志 ================= */
|
||
void lis3dh_clear_all_int_flags(void) {
|
||
uint8_t dummy;
|
||
|
||
// 读取INT1_SRC清除中断锁存(关键!)
|
||
lis3dh_read(LIS3DH_REG_INT1_SRC, &dummy, 1);
|
||
|
||
// 读取状态寄存器确保数据就绪标志清除
|
||
lis3dh_read(LIS3DH_REG_STATUS, &dummy, 1);
|
||
|
||
// 读取REFERENCE寄存器重置高通滤波器
|
||
lis3dh_read(LIS3DH_REG_REFERENCE, &dummy, 1);
|
||
|
||
last_int_src = 0;
|
||
}
|
||
|
||
/* ================= LIS3DH 中断初始化 ================= */
|
||
static void lis3dh_int1_fall_init(void) {
|
||
uint8_t val;
|
||
|
||
/* 第一步:禁用所有中断并清除标志 */
|
||
lis3dh_write(LIS3DH_REG_CTRL3, 0x00);
|
||
lis3dh_write(LIS3DH_REG_INT1_CFG, 0x00);
|
||
osDelay(10);
|
||
|
||
/* 第二步:清除所有可能的中断标志 */
|
||
lis3dh_clear_all_int_flags();
|
||
osDelay(10);
|
||
|
||
/* 第三步:配置CTRL2 - 高通滤波器 */
|
||
// 0x11 = 100Hz截止频率,HP使能
|
||
lis3dh_write(LIS3DH_REG_CTRL2, 0x11);
|
||
|
||
/* 第四步:配置CTRL3 - INT1引脚输出AOI1中断 */
|
||
val = 0x40; // I1_AOI1 = 1
|
||
lis3dh_write(LIS3DH_REG_CTRL3, val);
|
||
|
||
/* 第五步:INT1_CFG - 配置检测逻辑 */
|
||
// 0x2A = 0010 1010:只检测Z轴高阈值和低阈值
|
||
// 0x3F = 0011 1111:检测所有轴(根据你的日志0x25/0x65包含多个轴)
|
||
val = 0x2A; // 先用Z轴测试
|
||
lis3dh_write(LIS3DH_REG_INT1_CFG, val);
|
||
|
||
/* 第六步:INT1_THS - 阈值设置 */
|
||
val = 15; // 15 * 16mg = 240mg ≈ 0.24g(自由落体阈值)
|
||
lis3dh_write(LIS3DH_REG_INT1_THS, val);
|
||
|
||
/* 第七步:INT1_DUR - 持续时间(去抖动) */
|
||
val = 2; // 2 * 1/ODR = 20ms @ 100Hz
|
||
lis3dh_write(LIS3DH_REG_INT1_DUR, val);
|
||
|
||
/* 第八步:配置CTRL5 - 锁存中断 */
|
||
// 0x0A = 0000 1010:LIR_INT1=1(锁存),INT1高阈值使能
|
||
lis3dh_write(LIS3DH_REG_CTRL5, 0x0A);
|
||
|
||
/* 第九步:再次清除所有标志 */
|
||
lis3dh_clear_all_int_flags();
|
||
|
||
elog_info("MEMS", "INT1 fall detect configured (Latch Mode)");
|
||
}
|
||
|
||
/* ================= LIS3DH 初始化 ================= */
|
||
uint8_t imu_lis3dhtr_init(void) {
|
||
uint8_t whoami = 0;
|
||
lis3dh_read(LIS3DH_REG_WHOAMI, &whoami, 1);
|
||
elog_info("MEMS", "LIS3DHTR WHO_AM_I = 0x%02X", whoami);
|
||
|
||
if (whoami != 0x33)
|
||
return 0;
|
||
|
||
/* CTRL_REG1: 100Hz ODR, XYZ 使能 */
|
||
lis3dh_write(LIS3DH_REG_CTRL1, 0x57);
|
||
|
||
/* CTRL_REG4: BDU=1, HR=1, FS=±2g */
|
||
lis3dh_write(LIS3DH_REG_CTRL4, 0xA0);
|
||
|
||
/* 初始化 INT1 跌落检测 */
|
||
lis3dh_int1_fall_init();
|
||
|
||
/* 读回验证 */
|
||
uint8_t c1, c2, c3, c4, c5, cfg;
|
||
lis3dh_read(LIS3DH_REG_CTRL1, &c1, 1);
|
||
lis3dh_read(LIS3DH_REG_CTRL2, &c2, 1);
|
||
lis3dh_read(LIS3DH_REG_CTRL3, &c3, 1);
|
||
lis3dh_read(LIS3DH_REG_CTRL4, &c4, 1);
|
||
lis3dh_read(LIS3DH_REG_CTRL5, &c5, 1);
|
||
lis3dh_read(LIS3DH_REG_INT1_CFG, &cfg, 1);
|
||
|
||
elog_info("MEMS", "CTRL1=0x%02X CTRL2=0x%02X CTRL3=0x%02X", c1, c2, c3);
|
||
elog_info("MEMS", "CTRL4=0x%02X CTRL5=0x%02X INT1_CFG=0x%02X", c4, c5, cfg);
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* ================= 读取加速度 ================= */
|
||
|
||
uint8_t imu_lis3dhtr_read_accel(lis3dh_accel_t *accel)
|
||
{
|
||
uint8_t status;
|
||
lis3dh_read(LIS3DH_REG_STATUS, &status, 1);
|
||
|
||
if ((status & 0x08) == 0)
|
||
return 0; // 新数据未准备好
|
||
|
||
uint8_t buf[6];
|
||
lis3dh_read(LIS3DH_REG_OUT_X_L, buf, 6);
|
||
|
||
int16_t raw_x = ((int16_t)buf[1] << 8 | buf[0]) >> 4;
|
||
int16_t raw_y = ((int16_t)buf[3] << 8 | buf[2]) >> 4;
|
||
int16_t raw_z = ((int16_t)buf[5] << 8 | buf[4]) >> 4;
|
||
|
||
accel->x_g = raw_x * 0.001f; // ±2g HR模式,1LSB≈1mg
|
||
accel->y_g = raw_y * 0.001f;
|
||
accel->z_g = raw_z * 0.001f;
|
||
|
||
return 1;
|
||
}
|
||
|
||
/* ================= 外部中断回调 ================= */
|
||
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
|
||
if (GPIO_Pin == lis3dhtr_Pin) {
|
||
uint8_t src;
|
||
|
||
// 1. 读取中断源(这会清除锁存中断)
|
||
lis3dh_read(LIS3DH_REG_INT1_SRC, &src, 1);
|
||
|
||
// 2. 有效性检查:源寄存器必须有中断标志
|
||
if (src == 0x00) {
|
||
// 可能是假中断,额外操作确保清除
|
||
uint8_t dummy;
|
||
lis3dh_read(LIS3DH_REG_INT1_SRC, &dummy, 1);
|
||
return;
|
||
}
|
||
|
||
// 3. 去重:避免相同中断源连续触发
|
||
if (src == last_int_src) {
|
||
// 相同中断,可能是未及时处理,强制清除
|
||
elog_debug("MEMS", "Duplicate INT1 SRC = 0x%02X", src);
|
||
return;
|
||
}
|
||
|
||
// 4. 记录并处理
|
||
last_int_src = src;
|
||
elog_warn("MEMS", "INT1 SRC = 0x%02X", src);
|
||
|
||
// 5. 解析中断类型(用于调试和高级处理)
|
||
if (src & 0x40) elog_debug("MEMS", "Z high triggered");
|
||
if (src & 0x20) elog_debug("MEMS", "Z low triggered");
|
||
if (src & 0x10) elog_debug("MEMS", "Y high triggered");
|
||
if (src & 0x08) elog_debug("MEMS", "Y low triggered");
|
||
if (src & 0x04) elog_debug("MEMS", "X high triggered");
|
||
if (src & 0x02) elog_debug("MEMS", "X low triggered");
|
||
|
||
// 6. 设置处理标志
|
||
lis3dh_int_flag = 1;
|
||
}
|
||
} |