#include "qmi8658a.h" #include #include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #define TAG "QMI8658A" QMI8658A::QMI8658A(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr), state_(QMI8658A_STATE_UNINITIALIZED), last_error_(QMI8658A_OK), acc_scale_(1.0f), gyro_scale_(1.0f), is_calibrating_(false), calibration_start_time_(0), calibration_duration_(0), calibration_sample_count_(0), buffer_task_handle_(nullptr), buffer_enabled_(false), buffer_interval_ms_(0), interrupt_pin_(GPIO_NUM_NC), interrupt_type_(QMI8658A_INT_DISABLE), interrupt_enabled_(false), fifo_enabled_(false) { // 默认配置 - 修正ODR设置以匹配实际寄存器值 config_.mode = QMI8658A_MODE_DUAL; config_.acc_range = QMI8658A_ACC_RANGE_4G; // 匹配CTRL2寄存器值0x16 config_.gyro_range = QMI8658A_GYRO_RANGE_512DPS; // 匹配CTRL3寄存器值0x56 config_.acc_odr = QMI8658A_ODR_125HZ; // 匹配实际寄存器值0x06 config_.gyro_odr = QMI8658A_ODR_125HZ; // 匹配实际寄存器值0x06 // 初始化缓冲区结构 memset(&data_buffer_, 0, sizeof(data_buffer_)); data_buffer_.mutex = nullptr; // 初始化校准数据 memset(&calibration_, 0, sizeof(calibration_)); memset(calibration_acc_sum_, 0, sizeof(calibration_acc_sum_)); memset(calibration_gyro_sum_, 0, sizeof(calibration_gyro_sum_)); // 初始化FIFO配置 memset(&fifo_config_, 0, sizeof(fifo_config_)); } qmi8658a_error_t QMI8658A::Initialize(const qmi8658a_config_t* config) { ESP_LOGI(TAG, "Initializing QMI8658A sensor..."); state_ = QMI8658A_STATE_INITIALIZING; // 执行自检 qmi8658a_error_t result = PerformSelfTest(); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Self-test failed during initialization"); state_ = QMI8658A_STATE_ERROR; return result; } // 软件复位 result = SoftReset(); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Software reset failed"); state_ = QMI8658A_STATE_ERROR; return result; } // 保存配置 if (config) { config_ = *config; } // 计算比例因子 CalculateScaleFactors(); // 配置加速度计 result = SetAccelConfig(config_.acc_range, config_.acc_odr); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to configure accelerometer"); state_ = QMI8658A_STATE_ERROR; return result; } // 配置陀螺仪 result = SetGyroConfig(config_.gyro_range, config_.gyro_odr); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to configure gyroscope"); state_ = QMI8658A_STATE_ERROR; return result; } // 设置工作模式 uint8_t mode_val = config_.mode; result = SetMode(static_cast(mode_val)); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to set mode"); state_ = QMI8658A_STATE_ERROR; return result; } // 等待传感器稳定 vTaskDelay(pdMS_TO_TICKS(50)); // 验证关键寄存器配置 uint8_t expected_ctrl2 = (config_.acc_range << 4) | config_.acc_odr; result = VerifyRegisterValue(QMI8658A_CTRL2, expected_ctrl2, "CTRL2"); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "CTRL2 verification failed"); state_ = QMI8658A_STATE_ERROR; return result; } uint8_t expected_ctrl3 = (config_.gyro_range << 4) | config_.gyro_odr; result = VerifyRegisterValue(QMI8658A_CTRL3, expected_ctrl3, "CTRL3 (Gyro Config)"); if (result != QMI8658A_OK) { state_ = QMI8658A_STATE_ERROR; return result; } result = VerifyRegisterValue(QMI8658A_CTRL7, mode_val, "CTRL7 (Mode)"); if (result != QMI8658A_OK) { state_ = QMI8658A_STATE_ERROR; return result; } // 等待数据就绪 if (config_.mode != QMI8658A_MODE_DISABLE) { ESP_LOGI(TAG, "Waiting for sensor data to be ready..."); result = WaitForDataReady(2000); // 2秒超时 if (result != QMI8658A_OK) { ESP_LOGW(TAG, "Data ready timeout, but continuing initialization"); // 不将此作为致命错误,继续初始化 } } // 诊断寄存器状态 ESP_LOGI(TAG, "=== QMI8658A Register Diagnostics ==="); uint8_t ctrl1 = ReadReg(QMI8658A_CTRL1); uint8_t ctrl2 = ReadReg(QMI8658A_CTRL2); uint8_t ctrl3 = ReadReg(QMI8658A_CTRL3); uint8_t ctrl7 = ReadReg(QMI8658A_CTRL7); uint8_t status0 = ReadReg(QMI8658A_STATUS0); uint8_t status1 = ReadReg(QMI8658A_STATUS1); ESP_LOGI(TAG, "CTRL1: 0x%02X, CTRL2: 0x%02X, CTRL3: 0x%02X, CTRL7: 0x%02X", ctrl1, ctrl2, ctrl3, ctrl7); ESP_LOGI(TAG, "STATUS0: 0x%02X, STATUS1: 0x%02X", status0, status1); ESP_LOGI(TAG, "====================================="); // 等待数据就绪 ESP_LOGI(TAG, "Waiting for data ready..."); uint32_t wait_count = 0; const uint32_t max_wait = 100; // 最多等待1秒 while (wait_count < max_wait) { uint8_t status = ReadReg(QMI8658A_STATUS0); if (status & 0x03) { // 检查加速度计或陀螺仪数据就绪 ESP_LOGI(TAG, "Data ready after %lu ms", wait_count * 10); break; } vTaskDelay(pdMS_TO_TICKS(10)); wait_count++; } if (wait_count >= max_wait) { ESP_LOGW(TAG, "Data ready timeout, but initialization completed"); } state_ = QMI8658A_STATE_READY; ESP_LOGI(TAG, "QMI8658A initialization completed successfully"); return QMI8658A_OK; } uint8_t QMI8658A::GetChipId() { uint8_t chip_id = ReadReg(QMI8658A_WHO_AM_I); if (chip_id == 0xFF) { ESP_LOGE(TAG, "Failed to read chip ID register, I2C communication error"); return 0xFF; } return chip_id; } uint8_t QMI8658A::GetRevisionId() { return ReadReg(QMI8658A_REVISION_ID); } // 静态连接检测方法(用于生产测试) bool QMI8658A::CheckConnection(i2c_master_bus_handle_t i2c_bus, uint8_t* detected_address) { // 可能的QMI8658A I2C地址 uint8_t possible_addresses[] = {0x6A, 0x6B}; uint8_t num_addresses = sizeof(possible_addresses) / sizeof(possible_addresses[0]); for (uint8_t i = 0; i < num_addresses; i++) { uint8_t addr = possible_addresses[i]; // 创建临时I2C设备句柄进行测试 i2c_master_dev_handle_t dev_handle; i2c_device_config_t dev_cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = addr, .scl_speed_hz = 400000, // 400kHz }; esp_err_t ret = i2c_master_bus_add_device(i2c_bus, &dev_cfg, &dev_handle); if (ret != ESP_OK) { continue; // 尝试下一个地址 } // 尝试读取WHO_AM_I寄存器 uint8_t reg_addr = QMI8658A_WHO_AM_I; uint8_t chip_id = 0; ret = i2c_master_transmit_receive(dev_handle, ®_addr, 1, &chip_id, 1, 1000); // 清理设备句柄 i2c_master_bus_rm_device(dev_handle); if (ret == ESP_OK && chip_id == QMI8658A_CHIP_ID) { // 找到有效的QMI8658A设备 if (detected_address != nullptr) { *detected_address = addr; } return true; } } return false; // 未找到有效设备 } qmi8658a_error_t QMI8658A::SoftReset() { ESP_LOGI(TAG, "Performing soft reset..."); // 使用带验证的写入函数 qmi8658a_error_t result = WriteRegWithVerification(QMI8658A_CTRL1, 0xB0); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to perform soft reset"); return result; } // 等待复位完成 vTaskDelay(pdMS_TO_TICKS(20)); // 增加等待时间确保复位完成 // 验证复位是否成功 - 检查芯片ID uint8_t chip_id = GetChipId(); if (chip_id != QMI8658A_CHIP_ID) { ESP_LOGE(TAG, "Soft reset verification failed: chip ID = 0x%02X", chip_id); return SetError(QMI8658A_ERROR_INIT_FAILED); } ESP_LOGI(TAG, "Soft reset completed and verified successfully"); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::SetMode(qmi8658a_mode_t mode) { ESP_LOGI(TAG, "Setting mode: %d", mode); // 使用带验证的写入函数,最多重试3次 qmi8658a_error_t result = WriteRegWithVerification(QMI8658A_CTRL7, mode, 3); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to set mode: %d", mode); return result; } // 更新配置 config_.mode = mode; ESP_LOGI(TAG, "Mode set successfully: CTRL7=0x%02X", mode); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::SetAccelConfig(qmi8658a_acc_range_t range, qmi8658a_odr_t odr) { ESP_LOGI(TAG, "Setting accelerometer config: range=%d, odr=%d", range, odr); uint8_t ctrl2_val = (range << 4) | odr; // 使用带验证的写入函数,最多重试3次 qmi8658a_error_t result = WriteRegWithVerification(QMI8658A_CTRL2, ctrl2_val, 3); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to set accelerometer config: range=%d, odr=%d", range, odr); return result; } // 更新配置 config_.acc_range = range; config_.acc_odr = odr; ESP_LOGI(TAG, "Accelerometer config set successfully: CTRL2=0x%02X", ctrl2_val); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::SetGyroConfig(qmi8658a_gyro_range_t range, qmi8658a_odr_t odr) { ESP_LOGI(TAG, "Setting gyroscope config: range=%d, odr=%d", range, odr); uint8_t ctrl3_val = (range << 4) | odr; // 使用带验证的写入函数,最多重试3次 qmi8658a_error_t result = WriteRegWithVerification(QMI8658A_CTRL3, ctrl3_val, 3); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to set gyroscope config: range=%d, odr=%d", range, odr); return result; } // 更新配置 config_.gyro_range = range; config_.gyro_odr = odr; ESP_LOGI(TAG, "Gyroscope config set successfully: CTRL3=0x%02X", ctrl3_val); return QMI8658A_OK; } void QMI8658A::CalculateScaleFactors() { // 计算加速度计比例因子 (g) switch (config_.acc_range) { case QMI8658A_ACC_RANGE_2G: acc_scale_ = 2.0f / 32768.0f; break; case QMI8658A_ACC_RANGE_4G: acc_scale_ = 4.0f / 32768.0f; break; case QMI8658A_ACC_RANGE_8G: acc_scale_ = 8.0f / 32768.0f; break; case QMI8658A_ACC_RANGE_16G: acc_scale_ = 16.0f / 32768.0f; break; } // 计算陀螺仪比例因子 (dps) switch (config_.gyro_range) { case QMI8658A_GYRO_RANGE_16DPS: gyro_scale_ = 16.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_32DPS: gyro_scale_ = 32.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_64DPS: gyro_scale_ = 64.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_128DPS: gyro_scale_ = 128.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_256DPS: gyro_scale_ = 256.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_512DPS: gyro_scale_ = 512.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_1024DPS: gyro_scale_ = 1024.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_2048DPS: gyro_scale_ = 2048.0f / 32768.0f; break; } ESP_LOGI(TAG, "Scale factors - Acc: %.6f, Gyro: %.6f", acc_scale_, gyro_scale_); } int16_t QMI8658A::ReadInt16(uint8_t reg_low) { uint8_t data[2]; ReadRegs(reg_low, data, 2); return (int16_t)((data[1] << 8) | data[0]); } qmi8658a_error_t QMI8658A::ReadAccelData(float* acc_x, float* acc_y, float* acc_z) { if (!acc_x || !acc_y || !acc_z) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } if (state_ != QMI8658A_STATE_READY) { return SetError(QMI8658A_ERROR_DATA_NOT_READY); } int16_t raw_x = ReadInt16(QMI8658A_AX_L); int16_t raw_y = ReadInt16(QMI8658A_AY_L); int16_t raw_z = ReadInt16(QMI8658A_AZ_L); *acc_x = raw_x * acc_scale_; *acc_y = raw_y * acc_scale_; *acc_z = raw_z * acc_scale_; return QMI8658A_OK; } qmi8658a_error_t QMI8658A::ReadGyroData(float* gyro_x, float* gyro_y, float* gyro_z) { if (!gyro_x || !gyro_y || !gyro_z) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } if (state_ != QMI8658A_STATE_READY) { return SetError(QMI8658A_ERROR_DATA_NOT_READY); } int16_t raw_x = ReadInt16(QMI8658A_GX_L); int16_t raw_y = ReadInt16(QMI8658A_GY_L); int16_t raw_z = ReadInt16(QMI8658A_GZ_L); *gyro_x = raw_x * gyro_scale_; *gyro_y = raw_y * gyro_scale_; *gyro_z = raw_z * gyro_scale_; return QMI8658A_OK; } qmi8658a_error_t QMI8658A::ReadTemperature(float* temperature) { if (!temperature) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } if (state_ != QMI8658A_STATE_READY) { return SetError(QMI8658A_ERROR_DATA_NOT_READY); } int16_t raw_temp = ReadInt16(QMI8658A_TEMP_L); // 温度转换公式:温度 = raw_temp / 256.0 (°C) *temperature = raw_temp / 256.0f; return QMI8658A_OK; } qmi8658a_error_t QMI8658A::InitializeBuffer() { // 初始化缓冲区 memset(&data_buffer_, 0, sizeof(data_buffer_)); data_buffer_.mutex = xSemaphoreCreateMutex(); if (data_buffer_.mutex == NULL) { return SetError(QMI8658A_ERROR_INIT_FAILED); } buffer_enabled_ = false; buffer_task_handle_ = NULL; ESP_LOGI(TAG, "Data buffer initialized"); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::StartBufferedReading(uint32_t interval_ms) { if (state_ != QMI8658A_STATE_READY) { return SetError(QMI8658A_ERROR_DATA_NOT_READY); } if (buffer_enabled_) { ESP_LOGW(TAG, "Buffered reading already started"); return QMI8658A_OK; } buffer_interval_ms_ = interval_ms; buffer_enabled_ = true; // 创建缓冲任务 BaseType_t result = xTaskCreate( BufferTask, "qmi8658a_buffer", 4096, this, 5, &buffer_task_handle_ ); if (result != pdPASS) { buffer_enabled_ = false; return SetError(QMI8658A_ERROR_INIT_FAILED); } ESP_LOGI(TAG, "Started buffered reading with %" PRIu32 " ms interval", interval_ms); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::StopBufferedReading() { if (!buffer_enabled_) { return QMI8658A_OK; } buffer_enabled_ = false; if (buffer_task_handle_ != NULL) { vTaskDelete(buffer_task_handle_); buffer_task_handle_ = NULL; } ESP_LOGI(TAG, "Stopped buffered reading"); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::GetBufferedData(qmi8658a_data_t* data, uint32_t max_count, uint32_t* actual_count) { if (!data || !actual_count) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } *actual_count = 0; if (xSemaphoreTake(data_buffer_.mutex, pdMS_TO_TICKS(100)) != pdTRUE) { return SetError(QMI8658A_ERROR_TIMEOUT); } uint32_t count = 0; while (count < max_count && data_buffer_.count > 0) { data[count] = data_buffer_.data[data_buffer_.tail]; data_buffer_.tail = (data_buffer_.tail + 1) % QMI8658A_BUFFER_SIZE; data_buffer_.count--; count++; } *actual_count = count; xSemaphoreGive(data_buffer_.mutex); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::ClearBuffer() { if (xSemaphoreTake(data_buffer_.mutex, pdMS_TO_TICKS(100)) != pdTRUE) { return SetError(QMI8658A_ERROR_TIMEOUT); } data_buffer_.head = 0; data_buffer_.tail = 0; data_buffer_.count = 0; data_buffer_.overflow = false; xSemaphoreGive(data_buffer_.mutex); ESP_LOGI(TAG, "Buffer cleared"); return QMI8658A_OK; } uint32_t QMI8658A::GetBufferCount() { if (xSemaphoreTake(data_buffer_.mutex, pdMS_TO_TICKS(10)) != pdTRUE) { return 0; } uint32_t count = data_buffer_.count; xSemaphoreGive(data_buffer_.mutex); return count; } bool QMI8658A::IsBufferOverflow() { if (xSemaphoreTake(data_buffer_.mutex, pdMS_TO_TICKS(10)) != pdTRUE) { return false; } bool overflow = data_buffer_.overflow; xSemaphoreGive(data_buffer_.mutex); return overflow; } qmi8658a_error_t QMI8658A::ConfigureInterrupt(qmi8658a_interrupt_t int_type, gpio_num_t pin) { interrupt_type_ = int_type; interrupt_pin_ = pin; if (int_type == QMI8658A_INT_DISABLE) { interrupt_enabled_ = false; return QMI8658A_OK; } // 配置GPIO中断 gpio_config_t io_conf = {}; io_conf.intr_type = GPIO_INTR_POSEDGE; io_conf.mode = GPIO_MODE_INPUT; io_conf.pin_bit_mask = (1ULL << pin); io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; io_conf.pull_up_en = GPIO_PULLUP_ENABLE; esp_err_t ret = gpio_config(&io_conf); if (ret != ESP_OK) { return SetError(QMI8658A_ERROR_INIT_FAILED); } // 安装中断服务 ret = gpio_install_isr_service(0); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { return SetError(QMI8658A_ERROR_INIT_FAILED); } // 添加中断处理程序 ret = gpio_isr_handler_add(pin, InterruptHandler, this); if (ret != ESP_OK) { return SetError(QMI8658A_ERROR_INIT_FAILED); } // 配置传感器中断 uint8_t int_config = 0; switch (int_type) { case QMI8658A_INT_DATA_READY: int_config = 0x01; break; case QMI8658A_INT_FIFO_WATERMARK: int_config = 0x02; break; case QMI8658A_INT_FIFO_FULL: int_config = 0x04; break; case QMI8658A_INT_MOTION_DETECT: int_config = 0x08; break; default: break; } WriteReg(0x56, int_config); // INT_EN寄存器 interrupt_enabled_ = true; ESP_LOGI(TAG, "Interrupt configured: type=%d, pin=%d", int_type, pin); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::EnableFIFO(const qmi8658a_fifo_config_t* fifo_config) { if (!fifo_config) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } fifo_config_ = *fifo_config; // 配置FIFO uint8_t fifo_ctrl = 0x40; // 启用FIFO if (fifo_config->watermark > 0 && fifo_config->watermark <= QMI8658A_FIFO_SIZE) { fifo_ctrl |= (fifo_config->watermark & 0x1F); } WriteReg(0x13, fifo_ctrl); // FIFO_CTRL寄存器 // 如果配置了中断,设置中断 if (fifo_config->interrupt_type != QMI8658A_INT_DISABLE) { qmi8658a_error_t result = ConfigureInterrupt(fifo_config->interrupt_type, fifo_config->interrupt_pin); if (result != QMI8658A_OK) { return result; } } fifo_enabled_ = true; ESP_LOGI(TAG, "FIFO enabled with watermark: %d", fifo_config->watermark); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::DisableFIFO() { WriteReg(0x13, 0x00); // 禁用FIFO fifo_enabled_ = false; ESP_LOGI(TAG, "FIFO disabled"); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::ReadFIFO(qmi8658a_data_t* data_array, uint8_t max_count, uint8_t* actual_count) { if (!data_array || !actual_count) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } *actual_count = 0; if (!fifo_enabled_) { return SetError(QMI8658A_ERROR_DATA_NOT_READY); } // 读取FIFO状态 uint8_t fifo_status = ReadReg(0x14); // FIFO_STATUS寄存器 uint8_t fifo_count = fifo_status & 0x1F; if (fifo_count == 0) { return QMI8658A_OK; } uint8_t read_count = (fifo_count < max_count) ? fifo_count : max_count; for (uint8_t i = 0; i < read_count; i++) { qmi8658a_error_t result = ReadSensorData(&data_array[i]); if (result != QMI8658A_OK) { return result; } } *actual_count = read_count; return QMI8658A_OK; } qmi8658a_error_t QMI8658A::AddToBuffer(const qmi8658a_data_t* data) { if (!data) { return QMI8658A_ERROR_INVALID_PARAM; } if (xSemaphoreTake(data_buffer_.mutex, pdMS_TO_TICKS(10)) != pdTRUE) { return QMI8658A_ERROR_TIMEOUT; } if (data_buffer_.count >= QMI8658A_BUFFER_SIZE) { // 缓冲区满,覆盖最旧的数据 data_buffer_.tail = (data_buffer_.tail + 1) % QMI8658A_BUFFER_SIZE; data_buffer_.overflow = true; } else { data_buffer_.count++; } data_buffer_.data[data_buffer_.head] = *data; data_buffer_.head = (data_buffer_.head + 1) % QMI8658A_BUFFER_SIZE; xSemaphoreGive(data_buffer_.mutex); return QMI8658A_OK; } void QMI8658A::BufferTask(void* parameter) { QMI8658A* sensor = static_cast(parameter); qmi8658a_data_t data; while (sensor->buffer_enabled_) { if (sensor->ReadSensorData(&data) == QMI8658A_OK) { sensor->AddToBuffer(&data); // 如果正在校准,添加到校准数据 if (sensor->is_calibrating_) { sensor->calibration_acc_sum_[0] += data.acc_x; sensor->calibration_acc_sum_[1] += data.acc_y; sensor->calibration_acc_sum_[2] += data.acc_z; sensor->calibration_gyro_sum_[0] += data.gyro_x; sensor->calibration_gyro_sum_[1] += data.gyro_y; sensor->calibration_gyro_sum_[2] += data.gyro_z; sensor->calibration_sample_count_++; } } vTaskDelay(pdMS_TO_TICKS(sensor->buffer_interval_ms_)); } vTaskDelete(NULL); } void IRAM_ATTR QMI8658A::InterruptHandler(void* arg) { QMI8658A* sensor = static_cast(arg); // 在中断中只做最小的处理 BaseType_t xHigherPriorityTaskWoken = pdFALSE; // 可以在这里设置一个标志或发送通知 // 实际的数据读取应该在任务中进行 // 使用sensor参数避免未使用变量警告 (void)sensor; (void)xHigherPriorityTaskWoken; } qmi8658a_error_t QMI8658A::ReadSensorData(qmi8658a_data_t* data) { if (!data) { ESP_LOGE(TAG, "Data pointer is null"); return SetError(QMI8658A_ERROR_INVALID_PARAM); } if (state_ != QMI8658A_STATE_READY) { ESP_LOGE(TAG, "Sensor not ready, current state: %d", state_); return SetError(QMI8658A_ERROR_DATA_NOT_READY); } // 检查数据是否就绪 if (!IsDataReady()) { ESP_LOGW(TAG, "Sensor data not ready, STATUS0: 0x%02X", ReadReg(0x2D)); return SetError(QMI8658A_ERROR_DATA_NOT_READY); } // 初始化数据结构 memset(data, 0, sizeof(qmi8658a_data_t)); data->timestamp = esp_timer_get_time(); data->valid = false; qmi8658a_error_t result; // 读取加速度数据 if (config_.mode == QMI8658A_MODE_ACC_ONLY || config_.mode == QMI8658A_MODE_DUAL) { result = ReadAccelData(&data->acc_x, &data->acc_y, &data->acc_z); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to read accelerometer data, error: %d", result); return result; } ESP_LOGD(TAG, "Accel data: X=%.3f, Y=%.3f, Z=%.3f", data->acc_x, data->acc_y, data->acc_z); } // 读取陀螺仪数据 if (config_.mode == QMI8658A_MODE_GYRO_ONLY || config_.mode == QMI8658A_MODE_DUAL) { result = ReadGyroData(&data->gyro_x, &data->gyro_y, &data->gyro_z); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to read gyroscope data, error: %d", result); return result; } ESP_LOGD(TAG, "Gyro data: X=%.3f, Y=%.3f, Z=%.3f", data->gyro_x, data->gyro_y, data->gyro_z); } // 读取温度数据 result = ReadTemperature(&data->temperature); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to read temperature data, error: %d", result); return result; } ESP_LOGD(TAG, "Temperature: %.2f°C", data->temperature); data->valid = true; ESP_LOGD(TAG, "Successfully read sensor data"); return QMI8658A_OK; } bool QMI8658A::IsDataReady() { if (state_ != QMI8658A_STATE_READY) { return false; } // 读取状态寄存器检查数据是否准备就绪 uint8_t status = ReadReg(0x2D); // STATUS0寄存器 return (status & 0x03) != 0; // 检查加速度计和陀螺仪数据就绪位 } qmi8658a_error_t QMI8658A::SetError(qmi8658a_error_t error) { last_error_ = error; return error; } // 新增:带验证的寄存器写入函数 qmi8658a_error_t QMI8658A::WriteRegWithVerification(uint8_t reg, uint8_t value, uint8_t max_retries) { for (uint8_t retry = 0; retry < max_retries; retry++) { // 写入寄存器 esp_err_t ret = WriteRegWithError(reg, value); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to write register 0x%02X (attempt %d/%d): %s", reg, retry + 1, max_retries, esp_err_to_name(ret)); if (retry == max_retries - 1) { return SetError(QMI8658A_ERROR_I2C_COMM); } vTaskDelay(pdMS_TO_TICKS(10)); // 等待10ms后重试 continue; } // 等待写入完成 vTaskDelay(pdMS_TO_TICKS(5)); // 读回验证 uint8_t read_value = ReadReg(reg); if (read_value == 0xFF) { ESP_LOGE(TAG, "Failed to read back register 0x%02X for verification (attempt %d/%d)", reg, retry + 1, max_retries); if (retry == max_retries - 1) { return SetError(QMI8658A_ERROR_I2C_COMM); } vTaskDelay(pdMS_TO_TICKS(10)); continue; } if (read_value == value) { ESP_LOGI(TAG, "Register 0x%02X successfully written and verified: 0x%02X", reg, value); return QMI8658A_OK; } else { ESP_LOGW(TAG, "Register 0x%02X verification failed (attempt %d/%d): wrote 0x%02X, read 0x%02X", reg, retry + 1, max_retries, value, read_value); if (retry == max_retries - 1) { return SetError(QMI8658A_ERROR_CONFIG_FAILED); } vTaskDelay(pdMS_TO_TICKS(10)); } } return SetError(QMI8658A_ERROR_CONFIG_FAILED); } // 新增:验证寄存器值函数 qmi8658a_error_t QMI8658A::VerifyRegisterValue(uint8_t reg, uint8_t expected_value, const char* reg_name) { uint8_t actual_value = ReadReg(reg); if (actual_value == 0xFF) { ESP_LOGE(TAG, "Failed to read %s register (0x%02X) for verification", reg_name, reg); return SetError(QMI8658A_ERROR_I2C_COMM); } if (actual_value != expected_value) { ESP_LOGE(TAG, "%s register (0x%02X) verification failed: expected 0x%02X, got 0x%02X", reg_name, reg, expected_value, actual_value); return SetError(QMI8658A_ERROR_CONFIG_FAILED); } ESP_LOGI(TAG, "%s register (0x%02X) verified successfully: 0x%02X", reg_name, reg, actual_value); return QMI8658A_OK; } // 新增:等待数据就绪函数 qmi8658a_error_t QMI8658A::WaitForDataReady(uint32_t timeout_ms) { uint32_t start_time = esp_timer_get_time() / 1000; // 转换为毫秒 uint32_t elapsed_time = 0; ESP_LOGI(TAG, "Waiting for data ready (timeout: %lu ms)...", timeout_ms); while (elapsed_time < timeout_ms) { uint8_t status0 = ReadReg(QMI8658A_STATUS0); if (status0 == 0xFF) { ESP_LOGE(TAG, "Failed to read STATUS0 register while waiting for data ready"); return SetError(QMI8658A_ERROR_I2C_COMM); } // 检查加速度计和陀螺仪数据是否就绪 bool acc_ready = (status0 & 0x01) != 0; bool gyro_ready = (status0 & 0x02) != 0; if (acc_ready && gyro_ready) { ESP_LOGI(TAG, "Data ready detected after %lu ms (STATUS0: 0x%02X)", elapsed_time, status0); return QMI8658A_OK; } vTaskDelay(pdMS_TO_TICKS(10)); // 等待10ms elapsed_time = (esp_timer_get_time() / 1000) - start_time; } ESP_LOGE(TAG, "Timeout waiting for data ready after %lu ms", timeout_ms); return SetError(QMI8658A_ERROR_TIMEOUT); } // 新增:自检函数 qmi8658a_error_t QMI8658A::PerformSelfTest() { ESP_LOGI(TAG, "Performing self-test..."); // 检查芯片ID uint8_t chip_id = GetChipId(); if (chip_id != QMI8658A_CHIP_ID) { ESP_LOGE(TAG, "Self-test failed: Invalid chip ID 0x%02X", chip_id); return SetError(QMI8658A_ERROR_CHIP_ID); } // 检查关键寄存器的可读性 uint8_t test_regs[] = {QMI8658A_WHO_AM_I, QMI8658A_REVISION_ID, QMI8658A_STATUS0, QMI8658A_STATUS1}; const char* test_reg_names[] = {"WHO_AM_I", "REVISION_ID", "STATUS0", "STATUS1"}; for (int i = 0; i < 4; i++) { uint8_t value = ReadReg(test_regs[i]); if (value == 0xFF) { ESP_LOGE(TAG, "Self-test failed: Cannot read %s register (0x%02X)", test_reg_names[i], test_regs[i]); return SetError(QMI8658A_ERROR_I2C_COMM); } ESP_LOGI(TAG, "Self-test: %s (0x%02X) = 0x%02X", test_reg_names[i], test_regs[i], value); } ESP_LOGI(TAG, "Self-test completed successfully"); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::UpdateConfiguration(const qmi8658a_config_t* new_config) { if (!new_config) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } // 验证新配置 qmi8658a_error_t result = ValidateConfiguration(new_config); if (result != QMI8658A_OK) { return result; } // 保存旧配置以便回滚 qmi8658a_config_t old_config = config_; config_ = *new_config; // 应用配置更改 result = ApplyConfigurationChanges(); if (result != QMI8658A_OK) { // 回滚到旧配置 config_ = old_config; return result; } ESP_LOGI(TAG, "Configuration updated successfully"); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::ValidateConfiguration(const qmi8658a_config_t* config) { if (!config) { return QMI8658A_ERROR_INVALID_PARAM; } // 验证加速度计量程 if (config->acc_range > QMI8658A_ACC_RANGE_16G) { ESP_LOGE(TAG, "Invalid accelerometer range: %d", config->acc_range); return QMI8658A_ERROR_INVALID_PARAM; } // 验证陀螺仪量程 if (config->gyro_range > QMI8658A_GYRO_RANGE_2048DPS) { ESP_LOGE(TAG, "Invalid gyroscope range: %d", config->gyro_range); return QMI8658A_ERROR_INVALID_PARAM; } // 验证ODR设置 if (config->acc_odr > QMI8658A_ODR_8000HZ || config->gyro_odr > QMI8658A_ODR_8000HZ) { ESP_LOGE(TAG, "Invalid ODR setting"); return QMI8658A_ERROR_INVALID_PARAM; } // 验证工作模式 if (config->mode > QMI8658A_MODE_DUAL) { ESP_LOGE(TAG, "Invalid operation mode: %d", config->mode); return QMI8658A_ERROR_INVALID_PARAM; } return QMI8658A_OK; } qmi8658a_error_t QMI8658A::GetConfiguration(qmi8658a_config_t* config) { if (!config) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } *config = config_; return QMI8658A_OK; } qmi8658a_error_t QMI8658A::SetAccelRange(qmi8658a_acc_range_t range) { if (range > QMI8658A_ACC_RANGE_16G) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } config_.acc_range = range; qmi8658a_error_t result = SetAccelConfig(range, config_.acc_odr); if (result == QMI8658A_OK) { UpdateScaleFactors(); } return result; } qmi8658a_error_t QMI8658A::SetGyroRange(qmi8658a_gyro_range_t range) { if (range > QMI8658A_GYRO_RANGE_2048DPS) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } config_.gyro_range = range; qmi8658a_error_t result = SetGyroConfig(range, config_.gyro_odr); if (result == QMI8658A_OK) { UpdateScaleFactors(); } return result; } qmi8658a_error_t QMI8658A::SetAccelODR(qmi8658a_odr_t odr) { if (odr > QMI8658A_ODR_8000HZ) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } config_.acc_odr = odr; return SetAccelConfig(config_.acc_range, odr); } qmi8658a_error_t QMI8658A::SetGyroODR(qmi8658a_odr_t odr) { if (odr > QMI8658A_ODR_8000HZ) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } config_.gyro_odr = odr; return SetGyroConfig(config_.gyro_range, odr); } qmi8658a_error_t QMI8658A::SetOperationMode(qmi8658a_mode_t mode) { if (mode > QMI8658A_MODE_DUAL) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } config_.mode = mode; return SetMode(mode); } qmi8658a_error_t QMI8658A::StartCalibration(uint32_t duration_ms) { if (state_ != QMI8658A_STATE_READY) { return SetError(QMI8658A_ERROR_DATA_NOT_READY); } is_calibrating_ = true; calibration_start_time_ = esp_timer_get_time() / 1000; // 转换为毫秒 calibration_duration_ = duration_ms; calibration_sample_count_ = 0; // 清零累加器 memset(calibration_acc_sum_, 0, sizeof(calibration_acc_sum_)); memset(calibration_gyro_sum_, 0, sizeof(calibration_gyro_sum_)); ESP_LOGI(TAG, "Started calibration for %" PRIu32 " ms", duration_ms); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::GetCalibrationStatus(bool* is_calibrating, float* progress) { if (!is_calibrating || !progress) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } *is_calibrating = is_calibrating_; if (is_calibrating_) { uint32_t current_time = esp_timer_get_time() / 1000; uint32_t elapsed = current_time - calibration_start_time_; *progress = (float)elapsed / calibration_duration_; if (elapsed >= calibration_duration_) { // 校准完成,计算偏置 if (calibration_sample_count_ > 0) { for (int i = 0; i < 3; i++) { calibration_.acc_bias[i] = calibration_acc_sum_[i] / calibration_sample_count_; calibration_.gyro_bias[i] = calibration_gyro_sum_[i] / calibration_sample_count_; } calibration_.is_calibrated = true; calibration_.calibration_time = current_time; } is_calibrating_ = false; *is_calibrating = false; *progress = 1.0f; ESP_LOGI(TAG, "Calibration completed with %" PRIu32 " samples", calibration_sample_count_); } } else { *progress = 0.0f; } return QMI8658A_OK; } qmi8658a_error_t QMI8658A::ApplyCalibration(const qmi8658a_calibration_t* calibration) { if (!calibration) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } calibration_ = *calibration; ESP_LOGI(TAG, "Applied calibration data"); return QMI8658A_OK; } qmi8658a_error_t QMI8658A::GetCalibrationData(qmi8658a_calibration_t* calibration) { if (!calibration) { return SetError(QMI8658A_ERROR_INVALID_PARAM); } *calibration = calibration_; return QMI8658A_OK; } void QMI8658A::UpdateScaleFactors() { // 根据加速度计量程计算比例因子 switch (config_.acc_range) { case QMI8658A_ACC_RANGE_2G: acc_scale_ = 2.0f / 32768.0f; break; case QMI8658A_ACC_RANGE_4G: acc_scale_ = 4.0f / 32768.0f; break; case QMI8658A_ACC_RANGE_8G: acc_scale_ = 8.0f / 32768.0f; break; case QMI8658A_ACC_RANGE_16G: acc_scale_ = 16.0f / 32768.0f; break; default: acc_scale_ = 2.0f / 32768.0f; break; } // 根据陀螺仪量程计算比例因子 switch (config_.gyro_range) { case QMI8658A_GYRO_RANGE_16DPS: gyro_scale_ = 16.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_32DPS: gyro_scale_ = 32.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_64DPS: gyro_scale_ = 64.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_128DPS: gyro_scale_ = 128.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_256DPS: gyro_scale_ = 256.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_512DPS: gyro_scale_ = 512.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_1024DPS: gyro_scale_ = 1024.0f / 32768.0f; break; case QMI8658A_GYRO_RANGE_2048DPS: gyro_scale_ = 2048.0f / 32768.0f; break; default: gyro_scale_ = 256.0f / 32768.0f; break; } } qmi8658a_error_t QMI8658A::ApplyConfigurationChanges() { qmi8658a_error_t result; // 应用加速度计配置 result = SetAccelConfig(config_.acc_range, config_.acc_odr); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to configure accelerometer"); state_ = QMI8658A_STATE_ERROR; return result; } // 应用陀螺仪配置 result = SetGyroConfig(config_.gyro_range, config_.gyro_odr); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to configure gyroscope"); state_ = QMI8658A_STATE_ERROR; return result; } // 设置工作模式 uint8_t mode_val = config_.mode; result = SetMode(static_cast(mode_val)); if (result != QMI8658A_OK) { ESP_LOGE(TAG, "Failed to set mode"); state_ = QMI8658A_STATE_ERROR; return result; } // 更新比例因子 UpdateScaleFactors(); return QMI8658A_OK; } QMI8658A::~QMI8658A() { // 停止缓冲读取 if (buffer_enabled_) { StopBufferedReading(); } // 停止校准 if (is_calibrating_) { is_calibrating_ = false; } // 清理缓冲区 - 只有在mutex已创建时才释放 if (data_buffer_.mutex != nullptr) { vSemaphoreDelete(data_buffer_.mutex); data_buffer_.mutex = nullptr; } // 禁用FIFO if (fifo_enabled_) { DisableFIFO(); } // 设置为禁用模式 - 只有在传感器已初始化时才调用 if (state_ != QMI8658A_STATE_UNINITIALIZED) { SetMode(QMI8658A_MODE_DISABLE); } ESP_LOGI(TAG, "QMI8658A destructor completed"); }