312 lines
9.9 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.

#ifndef QMI8658A_H
#define QMI8658A_H
#include "driver/i2c_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_timer.h"
#include <cstdint>
#include <inttypes.h>
#include "i2c_device.h"
// QMI8658A I2C地址定义
#define QMI8658A_I2C_ADDRESS 0x6A // 修改为0x6A适配新PCB板SA0接VDD
// QMI8658A寄存器地址定义
#define QMI8658A_WHO_AM_I 0x00
#define QMI8658A_REVISION_ID 0x01
#define QMI8658A_CTRL1 0x02
#define QMI8658A_CTRL2 0x03
#define QMI8658A_CTRL3 0x04
#define QMI8658A_CTRL4 0x05
#define QMI8658A_CTRL5 0x06
#define QMI8658A_CTRL6 0x07
#define QMI8658A_CTRL7 0x08
#define QMI8658A_CTRL8 0x09
#define QMI8658A_CTRL9 0x0A
// 数据寄存器
#define QMI8658A_TEMP_L 0x33
#define QMI8658A_TEMP_H 0x34
#define QMI8658A_AX_L 0x35
#define QMI8658A_AX_H 0x36
#define QMI8658A_AY_L 0x37
#define QMI8658A_AY_H 0x38
#define QMI8658A_AZ_L 0x39
#define QMI8658A_AZ_H 0x3A
#define QMI8658A_GX_L 0x3B
#define QMI8658A_GX_H 0x3C
#define QMI8658A_GY_L 0x3D
#define QMI8658A_GY_H 0x3E
#define QMI8658A_GZ_L 0x3F
#define QMI8658A_GZ_H 0x40
// 状态寄存器
#define QMI8658A_STATUS0 0x2D
#define QMI8658A_STATUS1 0x2E
// 设备ID
#define QMI8658A_CHIP_ID 0x05
// 工作模式
typedef enum {
QMI8658A_MODE_DISABLE = 0x00,
QMI8658A_MODE_ACC_ONLY = 0x01,
QMI8658A_MODE_GYRO_ONLY = 0x02,
QMI8658A_MODE_DUAL = 0x03
} qmi8658a_mode_t;
// 加速度计量程
typedef enum {
QMI8658A_ACC_RANGE_2G = 0x00,
QMI8658A_ACC_RANGE_4G = 0x01,
QMI8658A_ACC_RANGE_8G = 0x02,
QMI8658A_ACC_RANGE_16G = 0x03
} qmi8658a_acc_range_t;
// 陀螺仪量程
typedef enum {
QMI8658A_GYRO_RANGE_16DPS = 0x00,
QMI8658A_GYRO_RANGE_32DPS = 0x01,
QMI8658A_GYRO_RANGE_64DPS = 0x02,
QMI8658A_GYRO_RANGE_128DPS = 0x03,
QMI8658A_GYRO_RANGE_256DPS = 0x04,
QMI8658A_GYRO_RANGE_512DPS = 0x05,
QMI8658A_GYRO_RANGE_1024DPS = 0x06,
QMI8658A_GYRO_RANGE_2048DPS = 0x07
} qmi8658a_gyro_range_t;
// 输出数据率
typedef enum {
QMI8658A_ODR_8000HZ = 0x00,
QMI8658A_ODR_4000HZ = 0x01,
QMI8658A_ODR_2000HZ = 0x02,
QMI8658A_ODR_1000HZ = 0x03,
QMI8658A_ODR_500HZ = 0x04,
QMI8658A_ODR_250HZ = 0x05,
QMI8658A_ODR_125HZ = 0x06,
QMI8658A_ODR_62_5HZ = 0x07,
QMI8658A_ODR_31_25HZ = 0x08
} qmi8658a_odr_t;
// 传感器数据结构 - 优化版本,使用数组存储
typedef struct {
union {
struct {
float acc_x; // 加速度X轴 (g)
float acc_y; // 加速度Y轴 (g)
float acc_z; // 加速度Z轴 (g)
};
float accel[3]; // 加速度数组 [x, y, z] (g)
};
union {
struct {
float gyro_x; // 陀螺仪X轴 (dps)
float gyro_y; // 陀螺仪Y轴 (dps)
float gyro_z; // 陀螺仪Z轴 (dps)
};
float gyro[3]; // 陀螺仪数组 [x, y, z] (dps)
};
float temperature; // 温度 (°C)
uint64_t timestamp; // 时间戳 (微秒)
bool valid; // 数据有效性标志
} qmi8658a_data_t;
// 错误代码定义
typedef enum {
QMI8658A_OK = 0,
QMI8658A_ERROR_INVALID_PARAM = -1,
QMI8658A_ERROR_I2C_COMM = -2,
QMI8658A_ERROR_CHIP_ID = -3,
QMI8658A_ERROR_INIT_FAILED = -4,
QMI8658A_ERROR_CONFIG_FAILED = -5,
QMI8658A_ERROR_DATA_NOT_READY = -6,
QMI8658A_ERROR_TIMEOUT = -7
} qmi8658a_error_t;
// 传感器状态
typedef enum {
QMI8658A_STATE_UNINITIALIZED = 0,
QMI8658A_STATE_INITIALIZING,
QMI8658A_STATE_READY,
QMI8658A_STATE_ERROR
} qmi8658a_state_t;
// 配置结构体
typedef struct {
qmi8658a_acc_range_t acc_range;
qmi8658a_gyro_range_t gyro_range;
qmi8658a_odr_t acc_odr;
qmi8658a_odr_t gyro_odr;
qmi8658a_mode_t mode;
bool enable_interrupt; // 是否启用中断
uint8_t interrupt_pin; // 中断引脚
bool auto_calibration; // 是否启用自动校准
float acc_offset[3]; // 加速度计偏移校准
float gyro_offset[3]; // 陀螺仪偏移校准
} qmi8658a_config_t;
// 校准数据结构
typedef struct {
float acc_bias[3]; // 加速度计偏置
float gyro_bias[3]; // 陀螺仪偏置
float acc_scale[3]; // 加速度计缩放因子
float gyro_scale[3]; // 陀螺仪缩放因子
bool is_calibrated; // 是否已校准
uint32_t calibration_time; // 校准时间戳
} qmi8658a_calibration_t;
// 数据缓冲配置
#define QMI8658A_BUFFER_SIZE 32
#define QMI8658A_FIFO_SIZE 16
// 中断配置
typedef enum {
QMI8658A_INT_DISABLE = 0,
QMI8658A_INT_DATA_READY = 1,
QMI8658A_INT_FIFO_WATERMARK = 2,
QMI8658A_INT_FIFO_FULL = 3,
QMI8658A_INT_MOTION_DETECT = 4
} qmi8658a_interrupt_t;
// 数据缓冲结构
typedef struct {
qmi8658a_data_t data[QMI8658A_BUFFER_SIZE];
uint32_t head;
uint32_t tail;
uint32_t count;
bool overflow;
SemaphoreHandle_t mutex;
} qmi8658a_buffer_t;
// FIFO配置结构
typedef struct {
bool enable;
uint8_t watermark;
qmi8658a_interrupt_t interrupt_type;
gpio_num_t interrupt_pin;
} qmi8658a_fifo_config_t;
class QMI8658A : public I2cDevice {
public:
QMI8658A(i2c_master_bus_handle_t i2c_bus, uint8_t addr = QMI8658A_I2C_ADDRESS);
~QMI8658A();
// 初始化和配置
qmi8658a_error_t Initialize(const qmi8658a_config_t* config = nullptr);
qmi8658a_error_t UpdateConfiguration(const qmi8658a_config_t* new_config);
qmi8658a_error_t ValidateConfiguration(const qmi8658a_config_t* config);
qmi8658a_error_t GetConfiguration(qmi8658a_config_t* config);
// 运行时配置修改
qmi8658a_error_t SetAccelRange(qmi8658a_acc_range_t range);
qmi8658a_error_t SetGyroRange(qmi8658a_gyro_range_t range);
qmi8658a_error_t SetAccelODR(qmi8658a_odr_t odr);
qmi8658a_error_t SetGyroODR(qmi8658a_odr_t odr);
qmi8658a_error_t SetOperationMode(qmi8658a_mode_t mode);
// 中断和FIFO配置
qmi8658a_error_t ConfigureInterrupt(qmi8658a_interrupt_t int_type, gpio_num_t pin);
qmi8658a_error_t EnableFIFO(const qmi8658a_fifo_config_t* fifo_config);
qmi8658a_error_t DisableFIFO();
qmi8658a_error_t ReadFIFO(qmi8658a_data_t* data_array, uint8_t max_count, uint8_t* actual_count);
// 数据缓冲管理
qmi8658a_error_t InitializeBuffer();
qmi8658a_error_t StartBufferedReading(uint32_t interval_ms);
qmi8658a_error_t StopBufferedReading();
qmi8658a_error_t GetBufferedData(qmi8658a_data_t* data, uint32_t max_count, uint32_t* actual_count);
qmi8658a_error_t ClearBuffer();
uint32_t GetBufferCount();
bool IsBufferOverflow();
// 校准功能
qmi8658a_error_t StartCalibration(uint32_t duration_ms = 5000);
qmi8658a_error_t GetCalibrationStatus(bool* is_calibrating, float* progress);
qmi8658a_error_t ApplyCalibration(const qmi8658a_calibration_t* calibration);
qmi8658a_error_t GetCalibrationData(qmi8658a_calibration_t* calibration);
qmi8658a_error_t SaveCalibrationToNVS();
qmi8658a_error_t LoadCalibrationFromNVS();
// 原有方法保持不变
qmi8658a_error_t SoftReset();
qmi8658a_error_t SetMode(qmi8658a_mode_t mode);
qmi8658a_error_t SetAccelConfig(qmi8658a_acc_range_t range, qmi8658a_odr_t odr);
qmi8658a_error_t SetGyroConfig(qmi8658a_gyro_range_t range, qmi8658a_odr_t odr);
// 数据读取
qmi8658a_error_t ReadSensorData(qmi8658a_data_t* data);
qmi8658a_error_t ReadAccelData(float* acc_x, float* acc_y, float* acc_z);
qmi8658a_error_t ReadGyroData(float* gyro_x, float* gyro_y, float* gyro_z);
qmi8658a_error_t ReadTemperature(float* temperature);
// 状态和诊断方法
qmi8658a_state_t GetState() const { return state_; }
qmi8658a_error_t GetLastError() const { return last_error_; }
bool IsDataReady();
// 芯片信息
uint8_t GetChipId();
uint8_t GetRevisionId();
// 静态连接检测方法(用于生产测试)
static bool CheckConnection(i2c_master_bus_handle_t i2c_bus, uint8_t* detected_address = nullptr);
private:
qmi8658a_config_t config_;
qmi8658a_calibration_t calibration_;
qmi8658a_state_t state_;
qmi8658a_error_t last_error_;
float acc_scale_;
float gyro_scale_;
// 校准相关
bool is_calibrating_;
uint32_t calibration_start_time_;
uint32_t calibration_duration_;
float calibration_acc_sum_[3];
float calibration_gyro_sum_[3];
uint32_t calibration_sample_count_;
// 缓冲区相关
qmi8658a_buffer_t data_buffer_;
TaskHandle_t buffer_task_handle_;
bool buffer_enabled_;
uint32_t buffer_interval_ms_;
// 中断相关
gpio_num_t interrupt_pin_;
qmi8658a_interrupt_t interrupt_type_;
bool interrupt_enabled_;
// FIFO相关
qmi8658a_fifo_config_t fifo_config_;
bool fifo_enabled_;
// 错误处理和验证函数
qmi8658a_error_t SetError(qmi8658a_error_t error);
void CalculateScaleFactors();
void UpdateScaleFactors();
qmi8658a_error_t ApplyConfigurationChanges();
// 新增:寄存器验证和重试机制
qmi8658a_error_t WriteRegWithVerification(uint8_t reg, uint8_t value, uint8_t max_retries = 3);
qmi8658a_error_t VerifyRegisterValue(uint8_t reg, uint8_t expected_value, const char* reg_name);
qmi8658a_error_t WaitForDataReady(uint32_t timeout_ms = 1000);
qmi8658a_error_t PerformSelfTest();
// 缓冲区和中断处理
static void BufferTask(void* parameter);
static void IRAM_ATTR InterruptHandler(void* arg);
qmi8658a_error_t AddToBuffer(const qmi8658a_data_t* data);
qmi8658a_error_t GetFromBuffer(qmi8658a_data_t* data);
// 工具函数
int16_t ReadInt16(uint8_t reg);
};
#endif // QMI8658A_H