Files
Chassis/project/code/ICM_42688.c
T
2026-06-06 21:26:08 +08:00

173 lines
6.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "ICM_42688.h"
//==================================================================================================
// 内部变量
//==================================================================================================
static float accel_scale = 1.0f; // 加速度计 LSB → g
static float gyro_scale = 1.0f; // 陀螺仪 LSB → °/s
//==================================================================================================
// SPI 底层操作宏
//==================================================================================================
#define ICM42688_WRITE_REG(reg, data) spi_write_8bit_register(ICM42688_SPI, reg, data)
#define ICM42688_READ_REGS(reg, data, num) spi_read_8bit_registers(ICM42688_SPI, (reg) | 0x80, data, num)
//==================================================================================================
// 静态函数 — 寄存器级 SPI 操作
//==================================================================================================
/** @brief 向指定寄存器写入一字节
* @param reg 寄存器地址
* @param data 写入值
* 片选 → 写寄存器 → 释放片选
*/
static void icm42688_write_reg(uint8_t reg, uint8_t data)
{
ICM42688_CS_LEVEL(0);
ICM42688_WRITE_REG(reg, data);
ICM42688_CS_LEVEL(1);
}
/** @brief 从指定寄存器连续读取多字节
* @param reg 起始寄存器地址
* @param data 输出缓冲区指针
* @param num 读取字节数
* 片选 → 读多字节 → 释放片选
*/
static void icm42688_read_regs(uint8_t reg, uint8_t *data, uint8_t num)
{
ICM42688_CS_LEVEL(0);
ICM42688_READ_REGS(reg, data, num);
ICM42688_CS_LEVEL(1);
}
/** @brief 将两个 uint8 拼接为 int16(大端序)
* @param hi 高字节
* @param lo 低字节
* @return 有符号 16 位整数
*/
static int16_t icm42688_combine_bytes(uint8_t hi, uint8_t lo)
{
return (int16_t)(((uint16_t)hi << 8) | lo);
}
/** @brief 配置加速度计/陀螺仪的量程和输出速率
* @param afs 加速度计量程
* @param aodr 加速度计输出速率
* @param gfs 陀螺仪量程
* @param godr 陀螺仪输出速率
* 同时更新内部比例系数 accel_scale / gyro_scale
*/
static void icm42688_set_range_odr(enum icm42688_afs afs, enum icm42688_aodr aodr,
enum icm42688_gfs gfs, enum icm42688_godr godr)
{
icm42688_write_reg(ICM42688_ACCEL_CONFIG0, (afs << 5) | (aodr + 1));
icm42688_write_reg(ICM42688_GYRO_CONFIG0, (gfs << 5) | (godr + 1));
switch (afs) {
case ICM42688_AFS_2G: accel_scale = 2000.0f / 32768.0f; break;
case ICM42688_AFS_4G: accel_scale = 4000.0f / 32768.0f; break;
case ICM42688_AFS_8G: accel_scale = 8000.0f / 32768.0f; break;
case ICM42688_AFS_16G: accel_scale = 16000.0f / 32768.0f; break;
default: accel_scale = 1.0f; break;
}
switch (gfs) {
case ICM42688_GFS_15_625DPS: gyro_scale = 15.625f / 32768.0f; break;
case ICM42688_GFS_31_25DPS: gyro_scale = 31.25f / 32768.0f; break;
case ICM42688_GFS_62_5DPS: gyro_scale = 62.5f / 32768.0f; break;
case ICM42688_GFS_125DPS: gyro_scale = 125.0f / 32768.0f; break;
case ICM42688_GFS_250DPS: gyro_scale = 250.0f / 32768.0f; break;
case ICM42688_GFS_500DPS: gyro_scale = 500.0f / 32768.0f; break;
case ICM42688_GFS_1000DPS: gyro_scale = 1000.0f / 32768.0f; break;
case ICM42688_GFS_2000DPS: gyro_scale = 2000.0f / 32768.0f; break;
default: gyro_scale = 1.0f; break;
}
}
//==================================================================================================
// 公开接口
//==================================================================================================
/** @brief 返回当前陀螺仪比例系数 (LSB → °/s)
* 供 imu_calibrate_gyro() 将原始 ADC 均值转换为物理偏移量
*/
float icm42688_gyro_scale(void)
{
return gyro_scale;
}
/** @brief 初始化 ICM-42688
* 1. 初始化 SPI 外设和 CS 引脚
* 2. 读取 WHO_AM_I 进行自检(超时 500ms 后报错死循环)
* 3. 复位并配置量程/速率(默认 ±16G / ±2000dps / 200Hz ODR)
* 4. 设置为低噪声模式
* 由 imu_init() 内部调用,用户一般不直接调用
*/
void icm42688_init(void)
{
system_delay_ms(10);
spi_init(ICM42688_SPI, SPI_MODE0, ICM42688_SPI_SPEED,
ICM42688_SPC_PIN, ICM42688_SDI_PIN, ICM42688_SDO_PIN, SPI_CS_NULL);
gpio_init(ICM42688_CS_PIN, GPO, GPIO_HIGH, GPO_PUSH_PULL);
uint8_t model = 0xFF;
int timeout = 50;
while (1) {
icm42688_read_regs(ICM42688_WHO_AM_I, &model, 1);
if (model == 0x47) {
break;
}
ICM42688_DELAY_MS(10);
if (--timeout < 0) {
zf_log(0, "ICM42688 Init Error!");
while (1);
}
}
icm42688_write_reg(ICM42688_PWR_MGMT0, 0x00);
ICM42688_DELAY_MS(20);
// 如果修改了采样频率(定时器中断周期),则需要对应修改下方的配置
icm42688_set_range_odr(ICM42688_AFS_16G, ICM42688_AODR_200HZ,
ICM42688_GFS_2000DPS, ICM42688_GODR_200HZ);
icm42688_write_reg(ICM42688_PWR_MGMT0, 0x0F);
ICM42688_DELAY_MS(10);
}
/** @brief 读取全部传感器数据(加速度 + 角速度)
* @param data 输出结构体指针
* 一次 12 字节 SPI 突发从 ACCEL_DATA_X1 开始连续读取
* 读取顺序: AX→AY→AZ→GX→GY→GZ(与传感器内部 FIFO 顺序一致)
*/
void icm42688_read_all(icm42688_data_t *data)
{
uint8_t buf[12];
icm42688_read_regs(ICM42688_ACCEL_DATA_X1, buf, 12);
data->accel_x = accel_scale * icm42688_combine_bytes(buf[0], buf[1]);
data->accel_y = accel_scale * icm42688_combine_bytes(buf[2], buf[3]);
data->accel_z = accel_scale * icm42688_combine_bytes(buf[4], buf[5]);
data->gyro_x = gyro_scale * icm42688_combine_bytes(buf[6], buf[7]);
data->gyro_y = gyro_scale * icm42688_combine_bytes(buf[8], buf[9]);
data->gyro_z = gyro_scale * icm42688_combine_bytes(buf[10], buf[11]);
}
/** @brief 读取陀螺仪原始 ADC 值(不做比例换算)
* @param gx/gy/gz 输出 int16 原始值指针
* 供 imu_calibrate_gyro() 在静止状态下采集原始数据计算零偏
*/
void icm42688_read_gyro_raw(int16_t *gx, int16_t *gy, int16_t *gz)
{
uint8_t buf[6];
icm42688_read_regs(ICM42688_GYRO_DATA_X1, buf, 6);
*gx = icm42688_combine_bytes(buf[0], buf[1]);
*gy = icm42688_combine_bytes(buf[2], buf[3]);
*gz = icm42688_combine_bytes(buf[4], buf[5]);
}