diff --git a/radio/src/boards/jumper-h750/board.cpp b/radio/src/boards/jumper-h750/board.cpp index 80c077da7..11dc79375 100644 --- a/radio/src/boards/jumper-h750/board.cpp +++ b/radio/src/boards/jumper-h750/board.cpp @@ -47,6 +47,7 @@ #include "sdcard.h" #include "debug.h" #include "keys.h" +#include "gyro.h" #include "flysky_gimbal_driver.h" #include "timers_driver.h" diff --git a/radio/src/boards/rm-h750/board.cpp b/radio/src/boards/rm-h750/board.cpp index 51e019501..447412f78 100644 --- a/radio/src/boards/rm-h750/board.cpp +++ b/radio/src/boards/rm-h750/board.cpp @@ -49,12 +49,21 @@ #include "sdcard.h" #include "debug.h" #include "keys.h" +#include "gyro.h" #include "flysky_gimbal_driver.h" #include "timers_driver.h" #include "touch_driver.h" +#if defined(IMU_ICM4207C) +#include "drivers/icm42607C.h" +#endif +#if defined(IMU_SC7U22) +#include "drivers/sc7u22.h" +#endif + + #include // common ADC driver @@ -63,6 +72,22 @@ extern const etx_hal_adc_driver_t _adc_driver; // RGB LED timer extern const stm32_pulse_timer_t _led_timer; +static const etx_imu_t _imu_candidates[] = { +#if defined(IMU_ICM4207C) + { &imu_icm42607_driver, IMU_I2C_BUS, ICM426xx_I2C_BASE_ADDR }, + { &imu_icm42607_driver, IMU_I2C_BUS, ICM426xx_I2C_BASE_ADDR + 1 }, +#endif +#if defined(IMU_SC7U22) + { &imu_sc7u22_driver, IMU_I2C_BUS, SC7U22_I2C_BASE_ADDR }, + { &imu_sc7u22_driver, IMU_I2C_BUS, SC7U22_I2C_BASE_ADDR + 1 }, +#endif +}; + +static void gyroInit() +{ + gyroStart(imuDetect(_imu_candidates, DIM(_imu_candidates))); +} + static void led_strip_off() { for (uint8_t i = 0; i < LED_STRIP_LENGTH; i++) { @@ -178,6 +203,8 @@ void boardInit() // RTC must be initialized before rambackupRestore() is called rtcInit(); + + gyroInit(); } extern void rtcDisableBackupReg(); diff --git a/radio/src/drivers/icm42607C.cpp b/radio/src/drivers/icm42607C.cpp index f4120c9ea..8875277a3 100644 --- a/radio/src/drivers/icm42607C.cpp +++ b/radio/src/drivers/icm42607C.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) EdgeTX + * Copyright (C) EdgeTX * * Based on code named * opentx - https://github.com/opentx/opentx @@ -24,33 +24,36 @@ with code for generic ICM4267XX. All register have different addresses */ -#include "edgetx.h" #include "hal/i2c_driver.h" -#include "stm32_i2c_driver.h" +#include "hal/imu.h" +#include "hal/gpio.h" + +#include "delays_driver.h" + #include "icm42607C.h" -#include "imu_filter.h" -#include "stm32_gpio.h" + #include "inactivity_timer.h" -#include "hal.h" +#include "debug.h" -constexpr uint32_t I2C_TIMEOUT = 5; //ms +static etx_i2c_bus_t s_i2c_bus; +static uint16_t s_i2c_addr; -int16_t getGyroTemperature() +static int16_t __attribute__((unused)) get42607Temperature() { - uint8_t reg = TEMP_DATA_X0_REG; uint8_t buf[2] = {0}; - if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, buf, 2, I2C_TIMEOUT) < 0) { + if (i2c_read(s_i2c_bus, s_i2c_addr, TEMP_DATA_X0_REG, 1, buf, 2) < 0) { TRACE("ICM426xx ERROR: TEMP_DATA_X0_REG i2c read error"); return -1; } - return (((buf[0] << 8) | buf[1]) / 128) + 25; + int16_t raw = (int16_t)((buf[0] << 8) | buf[1]); + return (int16_t)(raw / 128 + 25); } -int write_cmd(uint8_t reg, uint8_t val) +static int write_cmd(uint8_t reg, uint8_t val) { - return i2c_write(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, &val, 1); + return i2c_write(s_i2c_bus, s_i2c_addr, reg, 1, &val, 1); } #if defined(IMU_INT_GPIO) @@ -60,30 +63,35 @@ static void imu_exti_isr(void) } #endif +#if defined(IMU_INT_GPIO) static int write_mreg1(uint8_t reg, uint8_t val) { - if (write_cmd(BLK_SEL_W_REG, 0x00) < 0) return -1; + if (write_cmd(BLK_SEL_W_REG, 0x00) < 0) return -1; if (write_cmd(MADDR_W_REG, reg) < 0) return -1; if (write_cmd(M_W_REG, val) < 0) return -1; - delay_us(10); //42627-pdf p12“Accessing MREG1, MREG2 And MREG3 Registers + delay_us(10); // small delay as recommended by datasheet return 0; } +#endif -int gyroInit(void) +static int gyro42607Init(etx_i2c_bus_t bus, uint16_t addr) { - TRACE("ICM426xx I2C Init"); + s_i2c_bus = bus; + s_i2c_addr = addr; - if (i2c_init(IMU_I2C_BUS) < 0) { + TRACE("ICM426xx I2C Init at address 0x%x", addr); + + if (i2c_init(s_i2c_bus) < 0) { TRACE("ICM426xx ERROR: i2c_init bus error"); return -1; } - if (i2c_dev_ready(IMU_I2C_BUS, ICM426xx_I2C_ADDR) < 0) { + if (i2c_dev_ready(s_i2c_bus, s_i2c_addr) < 0) { TRACE("ICM426xx device init error"); return -1; } uint8_t data = 0; - if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, 0x75, 1, &data, 1, I2C_TIMEOUT) < 0) { + if (i2c_read(s_i2c_bus, s_i2c_addr, WHO_AM_I_REG, 1, &data, 1) < 0) { TRACE("ICM426xx ERROR: i2c read error"); return -1; } @@ -105,14 +113,14 @@ int gyroInit(void) } delay_ms(10); - // Set gyro to 2000 dps, 1kHz ODR + // Configure gyro: 2000 dps, 1 kHz ODR if(write_cmd(GYRO_CONFIG0_REG, GYRO_ODR_1KHZ) < 0) { TRACE("ICM426xx ERROR: GYRO_CONFIG0_REG error"); return -1; } delay_ms(1); - // Set accel to ±4g, 1kHz ODR + // Configure accelerometer: ±4g, 1 kHz ODR if (write_cmd(ACCEL_CONFIG0_REG, ACCEL_ODR_1KHZ) < 0) { TRACE("ICM426xx ERROR: ACCEL_CONFIG0_REG error"); return -1; @@ -127,58 +135,54 @@ int gyroInit(void) delay_ms(1); #if defined(IMU_INT_GPIO) - // CCEL_WOM_X_THR:0-255(0-1g),0x10--16mg + // Configure Wake-on-Motion thresholds via MREG1 interface + // Values chosen to approximate activity detection behaviour used elsewhere if (write_mreg1(ACCEL_WOM_X_THR_REG, 0xFE) < 0) return -1; if (write_mreg1(ACCEL_WOM_Y_THR_REG, 0xFE) < 0) return -1; if (write_mreg1(ACCEL_WOM_Z_THR_REG, 0xFE) < 0) return -1; delay_ms(1); - // config WoM + // Configure WoM mode (OR across axes) if (write_cmd(WOM_CONFIG_REG, 0x03) < 0) return -1; // OR mode delay_ms(1); - // enable INT1 + // Enable INT1 source bits for XYZ if (write_cmd(INT_SOURCE1_REG, 0x07) < 0) return -1; // XYZ interrupt delay_ms(1); - // config INT1 pin + // Ensure INT1 is configured to default behaviour if (write_cmd(INT_CONFIG_REG, 0x00) < 0) return -1; gpio_init_int(IMU_INT_GPIO, GPIO_IN_PU, GPIO_FALLING, imu_exti_isr); #endif + TRACE("ICM426xx succeeded"); return 0; } -int gyroRead(uint8_t buffer[IMU_BUFFER_LENGTH]) +static int gyro42607Read(etx_imu_data_t* data) { - IMU_RawData_t imu_raw; - IMU_FilteredData_t *filtered; - uint8_t buf[6]; - uint8_t reg = GYRO_DATA_X0_REG; - if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, buf, 6, I2C_TIMEOUT) < 0) { - TRACE("ICM426xx ERROR: i2c read error"); + + if (i2c_read(s_i2c_bus, s_i2c_addr, GYRO_DATA_X0_REG, 1, buf, 6) < 0) { + TRACE("ICM426xx ERROR: gyro read error"); return -1; } - imu_raw.gyro_x = -((int16_t)(buf[0] << 8) | buf[1]); // x - imu_raw.gyro_y = -((int16_t)(buf[2] << 8) | buf[3]); // y - imu_raw.gyro_z = ((int16_t)(buf[4] << 8) | buf[5]); // z + data->gyro_x = -((int16_t)(buf[0] << 8) | buf[1]); + data->gyro_y = -((int16_t)(buf[2] << 8) | buf[3]); + data->gyro_z = ((int16_t)(buf[4] << 8) | buf[5]); - reg = ACCEL_DATA_X0_REG; - if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, buf, 6, I2C_TIMEOUT) < 0) { - TRACE("ICM426xx ERROR: i2c read error"); + if (i2c_read(s_i2c_bus, s_i2c_addr, ACCEL_DATA_X0_REG, 1, buf, 6) < 0) { + TRACE("ICM426xx ERROR: accel read error"); return -1; } - imu_raw.accel_x = ((int16_t)(buf[0] << 8) | buf[1]); // x - imu_raw.accel_y = ((int16_t)(buf[2] << 8) | buf[3]); // y - imu_raw.accel_z = ((int16_t)(buf[4] << 8) | buf[5]); // z - - // Process through filters - process_imu_data(&imu_raw); - filtered = get_filtered_imu_data(); - - *(int16_t*)&buffer[6] = -(int16_t)filtered->accel_x; // x - *(int16_t*)&buffer[8] = -(int16_t)filtered->accel_y; // y - *(int16_t*)&buffer[10] = (int16_t)filtered->accel_z; // z + data->accel_x = ((int16_t)(buf[0] << 8) | buf[1]); + data->accel_y = ((int16_t)(buf[2] << 8) | buf[3]); + data->accel_z = ((int16_t)(buf[4] << 8) | buf[5]); return 0; } + +const etx_imu_driver_t imu_icm42607_driver = { + gyro42607Init, + gyro42607Read, + "ICM42607", +}; diff --git a/radio/src/drivers/icm42607C.h b/radio/src/drivers/icm42607C.h index 9813fb121..92b5fba98 100644 --- a/radio/src/drivers/icm42607C.h +++ b/radio/src/drivers/icm42607C.h @@ -1,5 +1,5 @@ /* -* Copyright (C) EdgeTX + * Copyright (C) EdgeTX * * Based on code named * opentx - https://github.com/opentx/opentx @@ -20,13 +20,18 @@ */ /* - WARNING: while this ICM42607C belong to the ICM426xx familly, it is NOT compatible - with code for generic ICM4267XX. All register have different addresses + WARNING: While this ICM42607C belong to the ICM426xx familly, it is NOT + compatible with code for generic ICM4267XX. All registers have + different addresses. */ #pragma once -#define ICM426xx_I2C_ADDR 0x68 +#include "hal/imu.h" + +#define ICM426xx_I2C_BASE_ADDR 0x68 + +extern const etx_imu_driver_t imu_icm42607_driver; // Register addresses #define WHO_AM_I_REG 0x75 @@ -57,14 +62,3 @@ #define INT_SOURCE1_REG 0x2C #define INT_CONFIG_REG 0x06 #define INT_STATUS2_REG 0x3B - -typedef struct { - float fTemperatureDegC; //°C - float fAccX, fAccY, fAccZ; // m/s^2 - float fGyroXradps, fGyroYradps, fGyroZradps; // rad/s -} sIMUoutput; - -extern sIMUoutput IMUoutput; - -int gyroInit(void); -int gyroRead(unsigned char*); diff --git a/radio/src/drivers/imu_filter.cpp b/radio/src/drivers/imu_filter.cpp deleted file mode 100644 index a0694b1dd..000000000 --- a/radio/src/drivers/imu_filter.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* -* Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "edgetx.h" -#include "imu_filter.h" -#include -#include - -// Filter parameters -#define COMPLEMENTARY_ALPHA 0.92f // Complementary filter coefficient -#define LP_FILTER_ALPHA 0.9f // Low-pass filter coefficient -#define SAMPLE_TIME_S 0.005f // Gyro is read every 5ms as part of execMixerFrequentActions() -#define RAD_TO_DEG 57.2958f -#define DEG_TO_RAD 0.0174533f - -// Filter state variables -static IMU_FilteredData_t filtered_data = {0}; -static float prev_accel[3] = {0}; -static float prev_gyro[3] = {0}; -static uint8_t filter_initialized = 0; - -// Low-pass filter implementation -float low_pass_filter(float new_value, float prev_value, float alpha) { - return alpha * prev_value + (1.0f - alpha) * new_value; -} - -// Calculate roll and pitch from accelerometer data -void calculate_accel_angles(float ax, float ay, float az, float *roll, float *pitch) { - // Normalize accelerometer data - float norm = sqrtf(ax*ax + ay*ay + az*az); - if (norm == 0.0f) return; - - ax /= norm; - ay /= norm; - az /= norm; - - // Calculate angles - *roll = atan2f(ay, sqrtf(ax*ax + az*az)); - *pitch = atan2f(-ax, sqrtf(ay*ay + az*az)); -} - -// Complementary filter for attitude estimation -void complementary_filter(IMU_RawData_t *raw_data, float dt) { - float accel_roll, accel_pitch; - - // Calculate angles from accelerometer - calculate_accel_angles(raw_data->accel_x, raw_data->accel_y, raw_data->accel_z, - &accel_roll, &accel_pitch); - - if (!filter_initialized) { - // Initialize filter with accelerometer angles - filtered_data.roll = accel_roll; - filtered_data.pitch = accel_pitch; - filtered_data.yaw = 0.0f; - filter_initialized = 1; - } else { - // Integrate gyroscope data - float gyro_roll = filtered_data.roll + raw_data->gyro_x * dt; - float gyro_pitch = filtered_data.pitch + raw_data->gyro_y * dt; - float gyro_yaw = filtered_data.yaw + raw_data->gyro_z * dt; - - // Apply complementary filter - filtered_data.roll = COMPLEMENTARY_ALPHA * gyro_roll + - (1.0f - COMPLEMENTARY_ALPHA) * accel_roll; - filtered_data.pitch = COMPLEMENTARY_ALPHA * gyro_pitch + - (1.0f - COMPLEMENTARY_ALPHA) * accel_pitch; - filtered_data.yaw = gyro_yaw; // No magnetometer correction in this example - - // Keep yaw within -π to π range - while (filtered_data.yaw > M_PI) filtered_data.yaw -= 2.0f * M_PI; - while (filtered_data.yaw < -M_PI) filtered_data.yaw += 2.0f * M_PI; - } -} - -// Apply low-pass filter to raw sensor data -void apply_lowpass_filter(IMU_RawData_t *raw_data) { - // Filter accelerometer data - filtered_data.accel_x = low_pass_filter(raw_data->accel_x, prev_accel[0], LP_FILTER_ALPHA); - filtered_data.accel_y = low_pass_filter(raw_data->accel_y, prev_accel[1], LP_FILTER_ALPHA); - filtered_data.accel_z = low_pass_filter(raw_data->accel_z, prev_accel[2], LP_FILTER_ALPHA); - - // Filter gyroscope data - filtered_data.gyro_x = low_pass_filter(raw_data->gyro_x, prev_gyro[0], LP_FILTER_ALPHA); - filtered_data.gyro_y = low_pass_filter(raw_data->gyro_y, prev_gyro[1], LP_FILTER_ALPHA); - filtered_data.gyro_z = low_pass_filter(raw_data->gyro_z, prev_gyro[2], LP_FILTER_ALPHA); - - // Update previous values - prev_accel[0] = filtered_data.accel_x; - prev_accel[1] = filtered_data.accel_y; - prev_accel[2] = filtered_data.accel_z; - - prev_gyro[0] = filtered_data.gyro_x; - prev_gyro[1] = filtered_data.gyro_y; - prev_gyro[2] = filtered_data.gyro_z; -} - -// Main IMU filter processing function -void process_imu_data(IMU_RawData_t *raw_data) { - // Apply low-pass filtering to raw data - apply_lowpass_filter(raw_data); - - // Apply complementary filter for attitude estimation - complementary_filter(raw_data, SAMPLE_TIME_S); -} - -// Get filtered IMU data -IMU_FilteredData_t* get_filtered_imu_data(void) { - return &filtered_data; -} - -// Reset filter state -void reset_imu_filter(void) { - memset(&filtered_data, 0, sizeof(filtered_data)); - memset(prev_accel, 0, sizeof(prev_accel)); - memset(prev_gyro, 0, sizeof(prev_gyro)); - filter_initialized = 0; -} - -// Advanced Kalman filter structure (optional implementation) -typedef struct { - float Q_angle; // Process noise variance for accelerometer - float Q_bias; // Process noise variance for gyro bias - float R_measure; // Measurement noise variance - float angle; // Estimated angle - float bias; // Estimated bias - float rate; // Unbiased rate - float P[2][2]; // Error covariance matrix -} kalman_state_t; - -// Kalman filter implementation (more advanced option) -float kalman_filter(kalman_state_t *state, float new_angle, float new_rate, float dt) { - // Prediction step - state->rate = new_rate - state->bias; - state->angle += dt * state->rate; - - // Update error covariance - state->P[0][0] += dt * (dt * state->P[1][1] - state->P[0][1] - state->P[1][0] + state->Q_angle); - state->P[0][1] -= dt * state->P[1][1]; - state->P[1][0] -= dt * state->P[1][1]; - state->P[1][1] += state->Q_bias * dt; - - // Innovation - float S = state->P[0][0] + state->R_measure; - float K[2] = {state->P[0][0] / S, state->P[1][0] / S}; - - float y = new_angle - state->angle; - - // Update step - state->angle += K[0] * y; - state->bias += K[1] * y; - - // Update error covariance - float P00_temp = state->P[0][0]; - float P01_temp = state->P[0][1]; - - state->P[0][0] -= K[0] * P00_temp; - state->P[0][1] -= K[0] * P01_temp; - state->P[1][0] -= K[1] * P00_temp; - state->P[1][1] -= K[1] * P01_temp; - - return state->angle; -} \ No newline at end of file diff --git a/radio/src/targets/common/arm/stm32/lsm6ds_driver.cpp b/radio/src/drivers/lsm6ds.cpp similarity index 86% rename from radio/src/targets/common/arm/stm32/lsm6ds_driver.cpp rename to radio/src/drivers/lsm6ds.cpp index b1b619927..9f1112d05 100644 --- a/radio/src/targets/common/arm/stm32/lsm6ds_driver.cpp +++ b/radio/src/drivers/lsm6ds.cpp @@ -19,18 +19,18 @@ * GNU General Public License for more details. */ -#include "gyro.h" -#include "hal.h" - -#if defined(IMU_I2C_BUS) && defined(IMU_I2C_ADDRESS) +#include "lsm6ds.h" #include "hal/i2c_driver.h" -#include "stm32_i2c_driver.h" #include "delays_driver.h" -#include +#include "definitions.h" + #include +static etx_i2c_bus_t s_i2c_bus; +static uint16_t s_i2c_addr; + /* COMMON VALUES FOR ACCEL-GYRO SENSORS */ #define LSM6DS_WHO_AM_I 0x0f #define LSM6DS_WHO_AM_I_DEF 0x69 @@ -204,72 +204,64 @@ static const char configure[][2] = { {LSM6DS_BDU_ADDR, 0x04} }; -#define I2C_TIMEOUT_MAX 10000 -#define I2C_LSM6DS_MAX_WRITE 32 - -static int I2C_LSM6DS_WriteRegister(uint8_t reg, uint8_t* data, uint8_t len) +static int write_reg(uint8_t reg, uint8_t val) { - uint8_t buffer[I2C_LSM6DS_MAX_WRITE]; - - if (len >= I2C_LSM6DS_MAX_WRITE - 1) return -1; - - buffer[0] = reg; - memcpy(buffer + 1, data, len); - - return stm32_i2c_master_tx(IMU_I2C_BUS, IMU_I2C_ADDRESS, buffer, len + 1, 100); + return i2c_write(s_i2c_bus, s_i2c_addr, reg, 1, &val, 1); } -static int I2C_LSM6DS_WriteRegister(uint8_t reg, uint8_t value) +static int read_reg(uint8_t reg) { - return I2C_LSM6DS_WriteRegister(reg, &value, 1); + uint8_t val = 0; + if (i2c_read(s_i2c_bus, s_i2c_addr, reg, 1, &val, 1) < 0) + return -1; + return val; } -static int I2C_LSM6DS_ReadRegister(uint8_t reg, uint8_t* data, uint8_t len) +static int read_regs(uint8_t reg, uint8_t* data, uint8_t len) { - if (stm32_i2c_master_tx(IMU_I2C_BUS, IMU_I2C_ADDRESS, ®, 1, 10) < 0) + return i2c_read(s_i2c_bus, s_i2c_addr, reg, 1, data, len); +} + +static int lsm6dsRead(etx_imu_data_t* data) +{ + // LSM6DS registers are contiguous: gyro X/Y/Z then accel X/Y/Z (little-endian) + uint8_t buf[12]; + if (read_regs(LSM6DS_GYRO_OUT_X_L_ADDR, buf, sizeof(buf)) < 0) return -1; - uint8_t value = 0; - if (stm32_i2c_master_rx(IMU_I2C_BUS, IMU_I2C_ADDRESS, data, len, 100) < 0) - return -1; - - return value; + int16_t* raw = (int16_t*)buf; + data->gyro_x = raw[0]; + data->gyro_y = raw[1]; + data->gyro_z = raw[2]; + data->accel_x = raw[3]; + data->accel_y = raw[4]; + data->accel_z = raw[5]; + return 0; } -static int I2C_LSM6DS_ReadRegister(uint8_t reg) +static int lsm6dsInit(etx_i2c_bus_t bus, uint16_t addr) { - uint8_t value = 0; - if (I2C_LSM6DS_ReadRegister(reg, &value, 1) < 0) - return -1; + s_i2c_bus = bus; + s_i2c_addr = addr; - return value; -} - -int gyroInit() -{ - if (i2c_init(IMU_I2C_BUS) < 0) + if (i2c_init(s_i2c_bus) < 0) return -1; // LSM6DS33TR works with LSM6DSLTR code for our use - uint8_t id = I2C_LSM6DS_ReadRegister(LSM6DS_WHO_AM_I); + int id = read_reg(LSM6DS_WHO_AM_I); if (id != LSM6DSLTR_ID && id != LSM6DS33TR_ID) return -1; for (uint8_t i = 0; i < DIM(configure); i++) { - I2C_LSM6DS_WriteRegister(configure[i][0], configure[i][1]); + write_reg(configure[i][0], configure[i][1]); } return 0; } -int gyroRead(uint8_t buffer[IMU_BUFFER_LENGTH]) -{ - return I2C_LSM6DS_ReadRegister(LSM6DS_GYRO_OUT_X_L_ADDR, buffer, IMU_BUFFER_LENGTH); -} +const etx_imu_driver_t imu_lsm6ds_driver = { + lsm6dsInit, + lsm6dsRead, + "LSM6DS", +}; -#else - -int gyroInit() { return -1; } -int gyroRead(uint8_t buffer[IMU_BUFFER_LENGTH]) { return -1; } - -#endif diff --git a/radio/src/targets/simu/gyro_driver.cpp b/radio/src/drivers/lsm6ds.h similarity index 89% rename from radio/src/targets/simu/gyro_driver.cpp rename to radio/src/drivers/lsm6ds.h index f23d46669..187fecb49 100644 --- a/radio/src/targets/simu/gyro_driver.cpp +++ b/radio/src/drivers/lsm6ds.h @@ -19,7 +19,8 @@ * GNU General Public License for more details. */ -#include "gyro.h" +#pragma once -int gyroInit() { return -1; } -int gyroRead(uint8_t*) { return -1; } +#include "hal/imu.h" + +extern const etx_imu_driver_t imu_lsm6ds_driver; diff --git a/radio/src/drivers/sc7u22.cpp b/radio/src/drivers/sc7u22.cpp new file mode 100644 index 000000000..bfb704de9 --- /dev/null +++ b/radio/src/drivers/sc7u22.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "hal/i2c_driver.h" +#include "hal/imu.h" +#include "hal/gpio.h" + +#include "delays_driver.h" + +#include "sc7u22.h" + +#include "inactivity_timer.h" +#include "debug.h" + +static etx_i2c_bus_t s_i2c_bus; +static uint16_t s_i2c_addr; + +static int write_reg(uint8_t reg, uint8_t val) +{ + return i2c_write(s_i2c_bus, s_i2c_addr, reg, 1, &val, 1); +} + +static int read_regs(uint8_t reg, uint8_t *buf, uint8_t len) +{ + return i2c_read(s_i2c_bus, s_i2c_addr, reg, 1, buf, len); +} + +static int soft_reset(void) +{ + // Ensure Addr_Auto is enabled (default 0x50 has it set, but be explicit) + if (write_reg(SC7U22_COM_CONF_REG, SC7U22_COM_CONF_DEFAULT) < 0) + return -1; + delay_ms(1); + + // Write 0xA5 twice to SOFT_RST + if (write_reg(SC7U22_SOFT_RST_REG, 0xA5) < 0) return -1; + if (write_reg(SC7U22_SOFT_RST_REG, 0xA5) < 0) return -1; + + // Datasheet recommends ~100 ms after reset for chip to re-initialise + delay_ms(100); + return 0; +} + +// --------------------------------------------------------------------------- +// Optional: WoM ISR (mirror of ICM42607C pattern) +// --------------------------------------------------------------------------- +#if defined(IMU_INT_GPIO) +static void imu_exti_isr(void) +{ + inactivityTimerReset(ActivitySource::MainControls); +} +#endif + +static int16_t __attribute__((unused)) getSC7U22Temperature(void) +{ + uint8_t buf[2] = {0}; + + if (read_regs(SC7U22_TEMP_H_REG, buf, 2) < 0) { + TRACE("SC7U22 ERROR: TEMP read error"); + return -1; + } + + int16_t raw = (int16_t)((buf[0] << 8) | buf[1]); + return (int16_t)(raw / 512 + 23); +} + + +static int gyroSC7U22Init(etx_i2c_bus_t bus, uint16_t addr) +{ + s_i2c_bus = bus; + s_i2c_addr = addr; + + TRACE("SC7U22 I2C Init at address 0x%x", addr); + + if (i2c_init(s_i2c_bus) < 0) { + TRACE("SC7U22 ERROR: i2c_init bus error"); + return -1; + } + + if (i2c_dev_ready(s_i2c_bus, s_i2c_addr) < 0) { + TRACE("SC7U22 ERROR: device not ready"); + return -1; + } + + uint8_t who_am_i = 0; + if (read_regs(SC7U22_WHO_AM_I_REG, &who_am_i, 1) < 0) { + TRACE("SC7U22 ERROR: WHO_AM_I read error"); + return -1; + } + + if (who_am_i != 0x6A) { + TRACE("SC7U22 ERROR: unexpected WHO_AM_I 0x%02X (expected 0x6A)", who_am_i); + return -1; + } + + if (soft_reset() < 0) { + TRACE("SC7U22 ERROR: soft reset failed"); + return -1; + } + + // ------------------------------------------------------------------------- + // 4. Configure COM_CONF (0x04) + // BDU=1 (block data update – output not updated until both bytes read) + // Addr_Auto=1 (auto-increment for burst reads) + // All other bits at default (push-pull, active-high INT, 4-wire SPI) + // ------------------------------------------------------------------------- + if (write_reg(SC7U22_COM_CONF_REG, SC7U22_COM_CONF_DEFAULT) < 0) { + TRACE("SC7U22 ERROR: COM_CONF write error"); + return -1; + } + delay_ms(1); + + // ------------------------------------------------------------------------- + // 5. Enable accelerometer, gyroscope and temperature sensor via PWR_CTRL + // Datasheet §5.47: ACC_EN | GYR_EN | TEMP_EN + // Delay ≥1 ms after configuring before reading. + // ------------------------------------------------------------------------- + if (write_reg(SC7U22_PWR_CTRL_REG, SC7U22_PWR_CTRL_ENABLE) < 0) { + TRACE("SC7U22 ERROR: PWR_CTRL write error"); + return -1; + } + delay_ms(10); // Allow sensors to start up + + // ------------------------------------------------------------------------- + // 6. Configure accelerometer + // ACC_CONF (0x40): high-performance mode, NORM_AVG4 filter, 1600 Hz ODR + // ACC_RANGE (0x41): ±4g + // ------------------------------------------------------------------------- + if (write_reg(SC7U22_ACC_CONF_REG, SC7U22_ACC_CONF_HP_1KHZ) < 0) { + TRACE("SC7U22 ERROR: ACC_CONF write error"); + return -1; + } + delay_ms(1); + + if (write_reg(SC7U22_ACC_RANGE_REG, SC7U22_ACC_RANGE_4G) < 0) { + TRACE("SC7U22 ERROR: ACC_RANGE write error"); + return -1; + } + delay_ms(1); + + // ------------------------------------------------------------------------- + // 7. Configure gyroscope + // GYR_CONF (0x42): high-performance mode, NORM_AVG4 filter, 1600 Hz ODR + // GYR_RANGE (0x43): ±2000 dps + // ------------------------------------------------------------------------- + if (write_reg(SC7U22_GYR_CONF_REG, SC7U22_GYR_CONF_HP_1KHZ) < 0) { + TRACE("SC7U22 ERROR: GYR_CONF write error"); + return -1; + } + delay_ms(1); + + if (write_reg(SC7U22_GYR_RANGE_REG, SC7U22_GYR_RANGE_2000DPS) < 0) { + TRACE("SC7U22 ERROR: GYR_RANGE write error"); + return -1; + } + delay_ms(1); + + // ------------------------------------------------------------------------- + // 8. Optional: Wake-on-Motion via AOI1 + // Uses the AOI1 OR-interrupt with all three axes enabled. + // Threshold: 0x7F LSB. At ±4g, 1 LSB = 32 mg → 0x7F ≈ 4g (max, safe). + // For activity detection similar to ICM42607C (0xFE ≈ 1g), set 0x1F ≈ 1g. + // ------------------------------------------------------------------------- +#if defined(IMU_INT_GPIO) + // AOI1_CFG: AOI=0 (OR mode), 6D=0, enable ZHIE|YHIE|XHIE + if (write_reg(SC7U22_AOI1_CFG_REG, 0x15) < 0) return -1; // 0b00010101 + delay_ms(1); + + // AOI1_THS: ~0.5g threshold for ±4g range (1 LSB = 32 mg → 16 LSB ≈ 512 mg) + if (write_reg(SC7U22_AOI1_THS_REG, 0x10) < 0) return -1; + delay_ms(1); + + // AOI1_DURATION: minimal (1 sample) + if (write_reg(SC7U22_AOI1_DURATION_REG, 0x00) < 0) return -1; + delay_ms(1); + + // AOI1&AOI2_CFG (0x3F): enable AOI, high-pass filter on AOI1 + // AOI_EN=1 (bit6), HPIS1=1 (bit4) for motion detection with HP data + if (write_reg(SC7U22_AOI1_AOI2_CFG_REG, 0x50) < 0) return -1; + delay_ms(1); + + // Route AOI1 interrupt to INT1 pin (INT1_OUT_SEL2, 0x06, bit0 = INT1_AOI1) + if (write_reg(SC7U22_INT1_OUT_SEL2_REG, 0x01) < 0) return -1; + delay_ms(1); + + // Configure INT1 GPIO as falling-edge interrupt input + gpio_init_int(IMU_INT_GPIO, GPIO_IN_PU, GPIO_FALLING, imu_exti_isr); +#endif + + TRACE("SC7U22 succeeded"); + return 0; +} + +static int gyroSC7U22Read(etx_imu_data_t* data) +{ + uint8_t buf[6]; + + // Read gyroscope: GYR_XH ... GYR_ZL (0x12 ... 0x17, 6 bytes) + if (read_regs(SC7U22_GYR_XH_REG, buf, 6) < 0) { + TRACE("SC7U22 ERROR: gyro read error"); + return -1; + } + data->gyro_x = -((int16_t)(buf[0] << 8) | buf[1]); + data->gyro_y = -((int16_t)(buf[2] << 8) | buf[3]); + data->gyro_z = ((int16_t)(buf[4] << 8) | buf[5]); + + // Read accelerometer: ACC_XH ... ACC_ZL (0x0C ... 0x11, 6 bytes) + if (read_regs(SC7U22_ACC_XH_REG, buf, 6) < 0) { + TRACE("SC7U22 ERROR: accel read error"); + return -1; + } + data->accel_x = ((int16_t)(buf[0] << 8) | buf[1]); + data->accel_y = ((int16_t)(buf[2] << 8) | buf[3]); + data->accel_z = ((int16_t)(buf[4] << 8) | buf[5]); + + return 0; +} + +const etx_imu_driver_t imu_sc7u22_driver = { + gyroSC7U22Init, + gyroSC7U22Read, + "SC7U22", +}; diff --git a/radio/src/drivers/sc7u22.h b/radio/src/drivers/sc7u22.h new file mode 100644 index 000000000..2053d8739 --- /dev/null +++ b/radio/src/drivers/sc7u22.h @@ -0,0 +1,177 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Driver for Silan SC7U22 six-axis IMU (3-axis accelerometer + 3-axis gyroscope). + * + * I2C slave address: 0x19 (SDO/SA0 floating or high) / 0x18 (SDO/SA0 grounded) + * WHO_AM_I register (0x01) expected value: 0x6A + */ + +#pragma once + +#include "hal/imu.h" + +extern const etx_imu_driver_t imu_sc7u22_driver; + +// --------------------------------------------------------------------------- +// I2C address +// --------------------------------------------------------------------------- +// SDO/SA0 tied high or floating → 7-bit address 0x19 +// SDO/SA0 grounded → 7-bit address 0x18 +#define SC7U22_I2C_BASE_ADDR 0x18 + +// --------------------------------------------------------------------------- +// General-purpose registers (directly accessible with 8-bit address) +// --------------------------------------------------------------------------- +#define SC7U22_WHO_AM_I_REG 0x01 // Expected value: 0x6A +#define SC7U22_COM_CONF_REG 0x04 // Communication configuration +#define SC7U22_INT1_OUT_SEL1_REG 0x05 +#define SC7U22_INT1_OUT_SEL2_REG 0x06 +#define SC7U22_INT2_OUT_SEL1_REG 0x07 +#define SC7U22_INT2_OUT_SEL2_REG 0x08 +#define SC7U22_INT1_STAT_REG 0x09 +#define SC7U22_INT2_STAT_REG 0x0A +#define SC7U22_DATA_STAT_REG 0x0B // Data ready status + +// Accelerometer output registers (16-bit, 2's complement, MSB first) +#define SC7U22_ACC_XH_REG 0x0C +#define SC7U22_ACC_XL_REG 0x0D +#define SC7U22_ACC_YH_REG 0x0E +#define SC7U22_ACC_YL_REG 0x0F +#define SC7U22_ACC_ZH_REG 0x10 +#define SC7U22_ACC_ZL_REG 0x11 + +// Gyroscope output registers (16-bit, 2's complement, MSB first) +#define SC7U22_GYR_XH_REG 0x12 +#define SC7U22_GYR_XL_REG 0x13 +#define SC7U22_GYR_YH_REG 0x14 +#define SC7U22_GYR_YL_REG 0x15 +#define SC7U22_GYR_ZH_REG 0x16 +#define SC7U22_GYR_ZL_REG 0x17 + +// Temperature registers: T = (int16_t)(TEMP_H<<8 | TEMP_L) / 512 + 23 °C +#define SC7U22_TEMP_H_REG 0x22 +#define SC7U22_TEMP_L_REG 0x23 + +// FIFO +#define SC7U22_FIFO_CFG0_REG 0x1C +#define SC7U22_FIFO_CFG1_REG 0x1D +#define SC7U22_FIFO_CFG2_REG 0x1E +#define SC7U22_FIFO_STAT0_REG 0x1F +#define SC7U22_FIFO_STAT1_REG 0x20 +#define SC7U22_FIFO_DATA_REG 0x21 + +// Saturation / self-test status +#define SC7U22_DATA_SAT_REG 0x24 + +// Power control +#define SC7U22_PWR_CTRL_REG 0x7D + +// Accelerometer configuration +#define SC7U22_ACC_CONF_REG 0x40 // ACC_FILTER_PERF | ACC_BWP[2:0] | ACC_ODR[3:0] +#define SC7U22_ACC_RANGE_REG 0x41 // FS[1:0]: 00=±2g 01=±4g 10=±8g 11=±16g + +// Gyroscope configuration +#define SC7U22_GYR_CONF_REG 0x42 // GYR_FILTER_PERF | GYR_NOISE_PERF | GYR_BWP[1:0] | GYR_ODR[3:0] +#define SC7U22_GYR_RANGE_REG 0x43 // OIS bits | FS[2:0]: 000=±2000dps … 100=±125dps + +// Soft reset (write 0xA5 twice after enabling Addr_Auto) +#define SC7U22_SOFT_RST_REG 0x4A + +// Segment selector (for special registers) +#define SC7U22_SEG_SEL_REG 0x7F + +// --------------------------------------------------------------------------- +// COM_CONF (0x04) bit definitions +// --------------------------------------------------------------------------- +#define SC7U22_COM_CONF_BOOT (1 << 7) // Reboot memory content +#define SC7U22_COM_CONF_BDU (1 << 6) // Block data update +#define SC7U22_COM_CONF_OIS_EN (1 << 5) // OIS enable +#define SC7U22_COM_CONF_ADDR_AUTO (1 << 4) // Address auto-increment +#define SC7U22_COM_CONF_PP_OD (1 << 3) // INT push-pull / open-drain +#define SC7U22_COM_CONF_INT_H (1 << 2) // INT active level +#define SC7U22_COM_CONF_OISM (1 << 1) // OIS SPI mode +#define SC7U22_COM_CONF_SIM (1 << 0) // SPI 4-wire / 3-wire + +// Default after reset: BDU=1, Addr_Auto=1 → 0x50 +#define SC7U22_COM_CONF_DEFAULT 0x50 + +// --------------------------------------------------------------------------- +// DATA_STAT (0x0B) bit definitions +// --------------------------------------------------------------------------- +#define SC7U22_DATA_STAT_DRDY_GYR (1 << 1) +#define SC7U22_DATA_STAT_DRDY_ACC (1 << 0) +#define SC7U22_DATA_STAT_DRDY_TMP (1 << 2) + +// --------------------------------------------------------------------------- +// PWR_CTRL (0x7D) bit definitions +// --------------------------------------------------------------------------- +#define SC7U22_PWR_CTRL_TEMP_EN (1 << 3) +#define SC7U22_PWR_CTRL_ACC_EN (1 << 2) +#define SC7U22_PWR_CTRL_GYR_EN (1 << 1) + +// Enable accelerometer + gyroscope + temperature sensor +#define SC7U22_PWR_CTRL_ENABLE (SC7U22_PWR_CTRL_TEMP_EN | \ + SC7U22_PWR_CTRL_ACC_EN | \ + SC7U22_PWR_CTRL_GYR_EN) + +// --------------------------------------------------------------------------- +// ACC_CONF (0x40) preset values +// ACC_FILTER_PERF=1 (high-perf), ACC_BWP=010 (NORM_AVG4), ACC_ODR=1000 (100 Hz) +// → bits[7:0] = 1_010_1000 = 0xA8 (matches chip default) +// For 1 kHz high-performance: ACC_ODR=1100 → 0xAC +// --------------------------------------------------------------------------- +#define SC7U22_ACC_CONF_HP_1KHZ 0xAC // High-perf, NORM_AVG4, 1600 Hz ODR +#define SC7U22_ACC_CONF_HP_100HZ 0xA8 // High-perf, NORM_AVG4, 100 Hz ODR (default) + +// ACC_RANGE: ±4g = 0x01 +#define SC7U22_ACC_RANGE_4G 0x01 + +// --------------------------------------------------------------------------- +// GYR_CONF (0x42) preset values +// GYR_FILTER_PERF=1 (high-perf/normal), GYR_NOISE_PERF=0, GYR_BWP=10 (NORM_AVG4), +// GYR_ODR=1000 (100 Hz) → 0xA8 … for 1 kHz: GYR_ODR=1100 → 0xAC +// Chip default is 0xA9 (BWP=10, ODR=1001 = 200 Hz) +// --------------------------------------------------------------------------- +#define SC7U22_GYR_CONF_HP_1KHZ 0xAC // High-perf, NORM_AVG4, 1600 Hz ODR +#define SC7U22_GYR_CONF_HP_100HZ 0xA8 // High-perf, NORM_AVG4, 100 Hz ODR + +// GYR_RANGE: ±2000 dps = FS[2:0]=000 +#define SC7U22_GYR_RANGE_2000DPS 0x00 + +// --------------------------------------------------------------------------- +// WoM / interrupt registers (for optional wake-on-motion, same principle as +// ICM42607C but using SC7U22 AOI mechanism via AOI1_CFG / AOI2_CFG) +// --------------------------------------------------------------------------- +#define SC7U22_AOI1_CFG_REG 0x30 +#define SC7U22_AOI1_STAT_REG 0x31 +#define SC7U22_AOI1_THS_REG 0x32 +#define SC7U22_AOI1_DURATION_REG 0x33 +#define SC7U22_AOI2_CFG_REG 0x34 +#define SC7U22_AOI2_STAT_REG 0x35 +#define SC7U22_AOI2_THS_REG 0x36 +#define SC7U22_AOI2_DURATION_REG 0x37 +#define SC7U22_AOI1_AOI2_CFG_REG 0x3F + +// INT1_OUT_SEL1 bits (0x05) +#define SC7U22_INT1_ACC (1 << 0) +#define SC7U22_INT1_GYR (1 << 2) diff --git a/radio/src/gui/128x64/radio_diaganas.cpp b/radio/src/gui/128x64/radio_diaganas.cpp index db094c1c6..fbe422e45 100644 --- a/radio/src/gui/128x64/radio_diaganas.cpp +++ b/radio/src/gui/128x64/radio_diaganas.cpp @@ -125,13 +125,13 @@ void menuRadioDiagAnalogs(event_t event) y += FH; uint8_t x = INDENT_WIDTH; lcdDrawText(x, y, "X:"); - lcdDrawNumber(x+3*FW-1, y, gyro.outputs[0] * 180 / 1024); + lcdDrawNumber(x+3*FW-1, y, gyroOutputs[0] * 180 / 1024); lcdDrawChar(lcdNextPos, y, CHAR_BW_DEGREE); - lcdDrawNumber(x+10*FW-1, y, gyro.scaledX(), RIGHT); + lcdDrawNumber(x+10*FW-1, y, gyroScaledX(), RIGHT); x = LCD_W/2 + INDENT_WIDTH; lcdDrawText(x, y, "Y:"); - lcdDrawNumber(x+3*FW-1, y, gyro.outputs[1] * 180 / 1024); + lcdDrawNumber(x+3*FW-1, y, gyroOutputs[1] * 180 / 1024); lcdDrawChar(lcdNextPos, y, CHAR_BW_DEGREE); - lcdDrawNumber(x+10*FW-1, y, gyro.scaledY(), RIGHT); + lcdDrawNumber(x+10*FW-1, y, gyroScaledY(), RIGHT); #endif } diff --git a/radio/src/gui/128x64/radio_setup.cpp b/radio/src/gui/128x64/radio_setup.cpp index 7e0aa5997..dad113239 100644 --- a/radio/src/gui/128x64/radio_setup.cpp +++ b/radio/src/gui/128x64/radio_setup.cpp @@ -484,7 +484,7 @@ void menuRadioSetup(event_t event) if (attr) { CHECK_INCDEC_GENVAR(event, g_eeGeneral.imuMax, IMU_MAX_DEFAULT - IMU_MAX_RANGE, IMU_MAX_DEFAULT + IMU_MAX_RANGE); lcdDrawText(lp, y, ")", RIGHT); - lcdDrawNumber(lcdLastLeftPos, y, max(abs(gyro.outputs[0]), abs(gyro.outputs[1])) * 180 / 1024, RIGHT); + lcdDrawNumber(lcdLastLeftPos, y, max(abs(gyroOutputs[0]), abs(gyroOutputs[1])) * 180 / 1024, RIGHT); lcdDrawText(lcdLastLeftPos, y, "(", RIGHT); } } @@ -499,7 +499,7 @@ void menuRadioSetup(event_t event) if (attr) { CHECK_INCDEC_GENVAR(event, g_eeGeneral.imuOffset, IMU_OFFSET_MIN, IMU_OFFSET_MAX); lcdDrawText(lp, y, ")", RIGHT); - lcdDrawNumber(lcdLastLeftPos, y, gyro.outputs[0] * 180 / 1024, RIGHT); + lcdDrawNumber(lcdLastLeftPos, y, gyroOutputs[0] * 180 / 1024, RIGHT); lcdDrawText(lcdLastLeftPos, y, "(", RIGHT); } } diff --git a/radio/src/gui/colorlcd/radio/radio_diaganas.cpp b/radio/src/gui/colorlcd/radio/radio_diaganas.cpp index 560230ed4..c8a375d0d 100644 --- a/radio/src/gui/colorlcd/radio/radio_diaganas.cpp +++ b/radio/src/gui/colorlcd/radio/radio_diaganas.cpp @@ -124,26 +124,37 @@ class AnaViewWindow : public Window } } -#if defined(IMU_ICM4207C) && LANDSCAPE - line = newLine(grid); - lv_obj_set_style_pad_column(line->getLvObj(), PAD_SMALL, LV_PART_MAIN); +#if defined(IMU) && LANDSCAPE + if (imuGetName()) { + line = newLine(grid); + lv_obj_set_style_pad_column(line->getLvObj(), PAD_SMALL, LV_PART_MAIN); - grid.setColSpan(2); - new StaticText(line, rect_t{}, "Tilt X"); - grid.setColSpan(1); - new DynamicNumber(line, rect_t{}, - [=]() { return gyro.scaledX(); }, COLOR_THEME_PRIMARY1_INDEX, RIGHT); + grid.setColSpan(2); + new StaticText(line, rect_t{}, STR_GYRO); + grid.setColSpan(3); + new StaticText(line, rect_t{}, imuGetName()); + grid.setColSpan(1); - for (int i = 0; i < 3; i++) {grid.nextCell();} + line = newLine(grid); + lv_obj_set_style_pad_column(line->getLvObj(), PAD_SMALL, LV_PART_MAIN); - line = newLine(grid); - lv_obj_set_style_pad_column(line->getLvObj(), PAD_SMALL, LV_PART_MAIN); + grid.setColSpan(2); + new StaticText(line, rect_t{}, "Tilt X"); + grid.setColSpan(1); + new DynamicNumber(line, rect_t{}, + [=]() { return gyroScaledX(); }, COLOR_THEME_PRIMARY1_INDEX, RIGHT); - grid.setColSpan(2); - new StaticText(line, rect_t{}, "Tilt Y"); - grid.setColSpan(1); - new DynamicNumber(line, rect_t{}, - [=]() { return gyro.scaledY(); }, COLOR_THEME_PRIMARY1_INDEX, RIGHT); + for (int i = 0; i < 3; i++) {grid.nextCell();} + + line = newLine(grid); + lv_obj_set_style_pad_column(line->getLvObj(), PAD_SMALL, LV_PART_MAIN); + + grid.setColSpan(2); + new StaticText(line, rect_t{}, "Tilt Y"); + grid.setColSpan(1); + new DynamicNumber(line, rect_t{}, + [=]() { return gyroScaledY(); }, COLOR_THEME_PRIMARY1_INDEX, RIGHT); + } #endif #if defined(LUMINOSITY_SENSOR) diff --git a/radio/src/gyro.cpp b/radio/src/gyro.cpp index b6b4468d4..f623c221a 100644 --- a/radio/src/gyro.cpp +++ b/radio/src/gyro.cpp @@ -21,115 +21,143 @@ #include "edgetx.h" #include "hal.h" -#include "debug.h" -#define _USE_MATH_DEFINES -#include #include "hal/usb_driver.h" -#define ACC_LSB_VALUE 0.000488 // 0.488 mg/LSB +#define _USE_MATH_DEFINES +#include -#define ALPHA 0.98 -#define DT 0.01 -#define SCALE_FACT_ACC 0.005 -#define SCALE_FACT_GYRO 0.0078 // 250deg/s / 32000 +#define COMPLEMENTARY_ALPHA 0.92f +#define LP_FILTER_ALPHA 0.9f +#define SAMPLE_TIME_S 0.005f -Gyro gyro; +int16_t gyroOutputs[2]; -#if !defined(IMU_ICM4207C) -static float deg2RESX(float deg) +static imu_read_fn readFn; +static uint8_t errors; +static int16_t offset_x, offset_y; +static int16_t range_x = 8192, range_y = 8192; +static int16_t raw_ax, raw_ay; + +// filter state +static bool filterInitialized; +static float roll, pitch, yaw; +static float filteredAccel[3]; +static float prevAccel[3]; +static float filteredGyro[3]; +static float prevGyro[3]; + +static float lowPass(float val, float prev, float alpha) { - // [-90 : 90] -> [-RESX : RESX] - return (deg * float(RESX)) / 90.0; + return alpha * prev + (1.0f - alpha) * val; } -#endif -void Gyro::wakeup() +static void gyroFilter(etx_imu_data_t* raw) +{ + // low-pass + filteredAccel[0] = lowPass(raw->accel_x, prevAccel[0], LP_FILTER_ALPHA); + filteredAccel[1] = lowPass(raw->accel_y, prevAccel[1], LP_FILTER_ALPHA); + filteredAccel[2] = lowPass(raw->accel_z, prevAccel[2], LP_FILTER_ALPHA); + + filteredGyro[0] = lowPass(raw->gyro_x, prevGyro[0], LP_FILTER_ALPHA); + filteredGyro[1] = lowPass(raw->gyro_y, prevGyro[1], LP_FILTER_ALPHA); + filteredGyro[2] = lowPass(raw->gyro_z, prevGyro[2], LP_FILTER_ALPHA); + + prevAccel[0] = filteredAccel[0]; + prevAccel[1] = filteredAccel[1]; + prevAccel[2] = filteredAccel[2]; + + prevGyro[0] = filteredGyro[0]; + prevGyro[1] = filteredGyro[1]; + prevGyro[2] = filteredGyro[2]; + + // complementary filter for attitude + float ax = raw->accel_x; + float ay = raw->accel_y; + float az = raw->accel_z; + + float norm = sqrtf(ax * ax + ay * ay + az * az); + if (norm == 0.0f) return; + ax /= norm; + ay /= norm; + az /= norm; + + float accelRoll = atan2f(ay, sqrtf(ax * ax + az * az)); + float accelPitch = atan2f(-ax, sqrtf(ay * ay + az * az)); + + if (!filterInitialized) { + roll = accelRoll; + pitch = accelPitch; + yaw = 0.0f; + filterInitialized = true; + } else { + float dt = SAMPLE_TIME_S; + roll = COMPLEMENTARY_ALPHA * (roll + raw->gyro_x * dt) + + (1.0f - COMPLEMENTARY_ALPHA) * accelRoll; + pitch = COMPLEMENTARY_ALPHA * (pitch + raw->gyro_y * dt) + + (1.0f - COMPLEMENTARY_ALPHA) * accelPitch; + yaw += raw->gyro_z * dt; + + if (yaw > (float)M_PI) yaw -= 2.0f * (float)M_PI; + if (yaw < -(float)M_PI) yaw += 2.0f * (float)M_PI; + } +} + +void gyroStart(imu_read_fn fn) +{ + readFn = fn; +} + +void gyroWakeup() { static tmr10ms_t gyroWakeupTime = 0; tmr10ms_t now = get_tmr10ms(); - if (errors >= 100 || now < gyroWakeupTime || usbPluggedInStorageMode()) + if (!readFn || errors >= 100 || now < gyroWakeupTime || + usbPluggedInStorageMode()) return; gyroWakeupTime = now + 1; /* 10ms default */ - int16_t values[IMU_VALUES_COUNT]; - if (gyroRead((uint8_t*)values) < 0) { + etx_imu_data_t raw; + if (readFn(&raw) < 0) { ++errors; return; } - // reset error count on each - // successful query to avoid - // stopping the sensor forever errors = 0; -#if defined(IMU_ICM4207C) - raw_ax = values[3]; - raw_ay = values[4]; + gyroFilter(&raw); + + raw_ax = (int16_t)filteredAccel[0]; + raw_ay = (int16_t)filteredAccel[1]; + int16_t ax = raw_ax - offset_x; int16_t ay = raw_ay - offset_y; - // Use only ACC value, they are really reliable - outputs[0] = (ax * float(RESX)) / range_x; - outputs[1] = (ay * float(RESX)) / range_y; -#else - int16_t ax = values[3]; - int16_t ay = values[4]; - int16_t az = values[5]; - - int16_t gx = values[0]; - int16_t gy = values[1]; - // int16_t gz = values[2]; - - // integrate gyro - roll -= gx * SCALE_FACT_GYRO * DT; - pitch += gy * SCALE_FACT_GYRO * DT; - - int32_t magn = abs(ax) + abs(ay) + abs(az); - if (magn > 8192 && magn < 32768) { - - if (az < 0) az = -az; - - float rollAcc = atan2f((float)ay,(float)az) * 57.3 /* 180/PI */; - float pitchAcc = atan2f((float)ax,(float)az) * 57.3 /* 180/PI */; - - roll = roll * ALPHA + rollAcc * (1.0-ALPHA); - pitch = pitch * ALPHA + pitchAcc * (1.0-ALPHA); - } - - outputs[0] = deg2RESX(roll); - outputs[1] = deg2RESX(pitch); -#endif + gyroOutputs[0] = (ax * float(RESX)) / range_x; + gyroOutputs[1] = (ay * float(RESX)) / range_y; } -int16_t Gyro::scaledX() +int16_t gyroScaledX() { - // return limit(-RESX, - // (int)(outputs[0] - g_eeGeneral.imuOffset * RESX / 180) * - // (180 / (IMU_MAX_DEFAULT + g_eeGeneral.imuMax)), - // RESX); - return limit(-RESX, outputs[0], RESX); + return limit(-RESX, gyroOutputs[0], RESX); } -int16_t Gyro::scaledY() +int16_t gyroScaledY() { - // return limit(-RESX, - // outputs[1] * (180 / (IMU_MAX_DEFAULT + g_eeGeneral.imuMax)), - // RESX); - return limit(-RESX, outputs[1], RESX); + return limit(-RESX, gyroOutputs[1], RESX); } -void Gyro::setIMU_X(int16_t offset, int16_t range) +void gyroSetIMU_X(int16_t offset, int16_t range) { if (offset == -1) offset_x = raw_ax; else offset_x = offset; range_x = range * 8192 / 180; } -void Gyro::setIMU_Y(int16_t offset, int16_t range) +void gyroSetIMU_Y(int16_t offset, int16_t range) { if (offset == -1) offset_y = raw_ay; else offset_y = offset; range_y = range * 8192 / 180; -} \ No newline at end of file +} diff --git a/radio/src/gyro.h b/radio/src/gyro.h index 5336b61d0..e852ed925 100644 --- a/radio/src/gyro.h +++ b/radio/src/gyro.h @@ -19,46 +19,21 @@ * GNU General Public License for more details. */ -#include -#include "myeeprom.h" +#pragma once -#define IMU_VALUES_COUNT 6 -#define IMU_BUFFER_LENGTH (IMU_VALUES_COUNT * sizeof(int16_t)) +#include +#include "hal/imu.h" #define IMU_MAX_DEFAULT 30 #define IMU_MAX_RANGE 60 #define IMU_OFFSET_MIN -30 #define IMU_OFFSET_MAX 10 -#define IMU_SAMPLES_EXPONENT 3 -#define IMU_SAMPLES_COUNT (2 ^ IMU_SAMPLES_EXPONENT) +void gyroStart(imu_read_fn fn); +void gyroWakeup(); +void gyroSetIMU_X(int16_t offset, int16_t range); +void gyroSetIMU_Y(int16_t offset, int16_t range); +int16_t gyroScaledX(); +int16_t gyroScaledY(); -class Gyro -{ - protected: - uint8_t errors = 0; - float roll = 0.0; - float pitch = 0.0; - int16_t offset_x = 0; - int16_t offset_y = 0; - int16_t range_x = 8192; - int16_t range_y = 8192; - int16_t raw_ax = 0; - int16_t raw_ay = 0; - - public: - int16_t outputs[2]; - - void wakeup(); - void setIMU_X(int16_t, int16_t); - void setIMU_Y(int16_t, int16_t); - - int16_t scaledX(); - int16_t scaledY(); -}; - -extern Gyro gyro; - -// Gyro driver -int gyroInit(); -int gyroRead(uint8_t buffer[IMU_BUFFER_LENGTH]); +extern int16_t gyroOutputs[2]; diff --git a/radio/src/drivers/imu_filter.h b/radio/src/hal/imu.cpp similarity index 53% rename from radio/src/drivers/imu_filter.h rename to radio/src/hal/imu.cpp index 2899ae656..273fe3c9b 100644 --- a/radio/src/drivers/imu_filter.h +++ b/radio/src/hal/imu.cpp @@ -1,5 +1,5 @@ /* -* Copyright (C) EdgeTX + * Copyright (C) EdgeTX * * Based on code named * opentx - https://github.com/opentx/opentx @@ -19,20 +19,22 @@ * GNU General Public License for more details. */ -#pragma once +#include "hal/imu.h" -// IMU data structure -typedef struct { - float accel_x, accel_y, accel_z; // Accelerometer data (m/s²) - float gyro_x, gyro_y, gyro_z; // Gyroscope data (rad/s) - float mag_x, mag_y, mag_z; // Magnetometer data (optional) -} IMU_RawData_t; +static const char* s_imu_name = nullptr; -typedef struct { - float roll, pitch, yaw; // Filtered attitude (radians) - float accel_x, accel_y, accel_z; // Filtered acceleration - float gyro_x, gyro_y, gyro_z; // Filtered gyroscope -} IMU_FilteredData_t; +imu_read_fn imuDetect(const etx_imu_t* candidates, uint8_t count) +{ + for (uint8_t i = 0; i < count; i++) { + if (candidates[i].driver->init(candidates[i].bus, candidates[i].addr) == 0) { + s_imu_name = candidates[i].driver->name; + return candidates[i].driver->read; + } + } + return nullptr; +} -void process_imu_data(IMU_RawData_t *raw_data); -IMU_FilteredData_t* get_filtered_imu_data(void); \ No newline at end of file +const char* imuGetName() +{ + return s_imu_name; +} diff --git a/radio/src/hal/imu.h b/radio/src/hal/imu.h new file mode 100644 index 000000000..9aa70ed06 --- /dev/null +++ b/radio/src/hal/imu.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) EdgeTX + * + * Based on code named + * opentx - https://github.com/opentx/opentx + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#pragma once + +#include +#include "hal/i2c_driver.h" + +struct etx_imu_data_t { + float accel_x, accel_y, accel_z; + float gyro_x, gyro_y, gyro_z; +}; + +typedef int (*imu_init_fn)(etx_i2c_bus_t bus, uint16_t addr); +typedef int (*imu_read_fn)(etx_imu_data_t* data); + +struct etx_imu_driver_t { + imu_init_fn init; + imu_read_fn read; + const char* name; +}; + +struct etx_imu_t { + const etx_imu_driver_t* driver; + etx_i2c_bus_t bus; + uint16_t addr; +}; + +// Generic detection: iterates candidates, returns read fn on success +imu_read_fn imuDetect(const etx_imu_t* candidates, uint8_t count); + +// Returns the name of the detected IMU, or nullptr if none +const char* imuGetName(); diff --git a/radio/src/lua/api_general.cpp b/radio/src/lua/api_general.cpp index 43dfe0ee5..dddda8746 100644 --- a/radio/src/lua/api_general.cpp +++ b/radio/src/lua/api_general.cpp @@ -3065,7 +3065,7 @@ static int luaSetIMU_X(lua_State* const L) return 1; } - gyro.setIMU_X(offset, range); + gyroSetIMU_X(offset, range); #endif lua_pushboolean(L, true); return 1; @@ -3096,7 +3096,7 @@ static int luaSetIMU_Y(lua_State* const L) return 1; } - gyro.setIMU_Y(offset, range); + gyroSetIMU_Y(offset, range); #endif lua_pushboolean(L, true); return 1; diff --git a/radio/src/mixer.cpp b/radio/src/mixer.cpp index 147b7a8fc..9aa7f3782 100644 --- a/radio/src/mixer.cpp +++ b/radio/src/mixer.cpp @@ -386,10 +386,10 @@ getvalue_t _getValue(mixsrc_t i, bool* valid) #if defined(IMU) else if (i == MIXSRC_TILT_X) { - return gyro.scaledX(); + return gyroScaledX(); } else if (i == MIXSRC_TILT_Y) { - return gyro.scaledY(); + return gyroScaledY(); } #endif diff --git a/radio/src/targets/common/arm/stm32/CMakeLists.txt b/radio/src/targets/common/arm/stm32/CMakeLists.txt index 2a3cdeb84..c5beb4116 100644 --- a/radio/src/targets/common/arm/stm32/CMakeLists.txt +++ b/radio/src/targets/common/arm/stm32/CMakeLists.txt @@ -137,7 +137,7 @@ endif() if(IMU) add_definitions(-DIMU) - set(SRC ${SRC} gyro.cpp) + set(SRC ${SRC} gyro.cpp hal/imu.cpp) endif() if(AUX_SERIAL OR AUX2_SERIAL) diff --git a/radio/src/targets/horus/CMakeLists.txt b/radio/src/targets/horus/CMakeLists.txt index 6cf115ee8..819a52cba 100644 --- a/radio/src/targets/horus/CMakeLists.txt +++ b/radio/src/targets/horus/CMakeLists.txt @@ -291,7 +291,7 @@ add_library(board OBJECT EXCLUDE_FROM_ALL ${BOARD_COMMON_SRC} targets/common/arm/stm32/delays_driver.cpp targets/common/arm/stm32/heartbeat_driver.cpp - targets/common/arm/stm32/lsm6ds_driver.cpp + drivers/lsm6ds.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/module_timer_driver.cpp targets/common/arm/stm32/sticks_pwm_driver.cpp diff --git a/radio/src/targets/horus/board.cpp b/radio/src/targets/horus/board.cpp index f3696a34d..6c84ff189 100644 --- a/radio/src/targets/horus/board.cpp +++ b/radio/src/targets/horus/board.cpp @@ -53,6 +53,10 @@ #include "csd203_sensor.h" #endif +#if defined(IMU) && defined(IMU_I2C_BUS) && defined(IMU_I2C_ADDRESS) + #define HAS_IMU +#endif + HardwareOptions hardwareOptions; bool boardBacklightOn = false; @@ -150,6 +154,19 @@ uint16_t getSixPosAnalogValue(uint16_t adcValue) } #endif +#if defined(HAS_IMU) +#include "drivers/lsm6ds.h" +#include "stm32_i2c_driver.h" + +static void gyroInit() +{ + const etx_imu_t candidates[] = { + { &imu_lsm6ds_driver, IMU_I2C_BUS, IMU_I2C_ADDRESS }, + }; + gyroStart(imuDetect(candidates, DIM(candidates))); +} +#endif + void boardInit() { delaysInit(); @@ -246,6 +263,10 @@ void boardInit() ledGreen(); #endif #endif + +#if defined(HAS_IMU) + gyroInit(); +#endif } #endif diff --git a/radio/src/targets/horus/imu_lsm6ds33.cpp b/radio/src/targets/horus/imu_lsm6ds33.cpp deleted file mode 100644 index a5ad8eee1..000000000 --- a/radio/src/targets/horus/imu_lsm6ds33.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "edgetx.h" -#include "i2c_driver.h" -#include "imu_lsm6ds33.h" - -I2C_HandleTypeDef hi2c2; - -sIMUsettings IMUsettings = {-1, -1.0, -1, -1, -1.0}; -sIMUoutput IMUoutput = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}; - -float fIMUtemp = 0.0; - -bool I2C_LSM6DS33_ReadRegister(uint8_t reg, uint8_t * buf, uint8_t len) -{ - if (HAL_I2C_Master_Transmit(&hi2c2, LSM6DS33_I2C_ADDR << 1, ®, 1, 10000) != HAL_OK) - { - TRACE("I2C B2 ERROR: ReadRegister write reg. address failed"); - return false; - } - - if (HAL_I2C_Master_Receive(&hi2c2, LSM6DS33_I2C_ADDR << 1, buf, len, 10000) != HAL_OK) - { - TRACE("I2C B2 ERROR: ReadRegister read register failed"); - return false; - } - return true; -} - -bool I2C_LSM6DS33_WriteRegister(uint8_t reg, uint8_t * buf, uint8_t len) -{ - uint8_t uAddrAndBuf[15]; - uAddrAndBuf[0] = reg; - - if (len > 0) - { - for (int i = 0;i < len;i++) - { - uAddrAndBuf[i + 1] = buf[i]; - } - } - - if (HAL_I2C_Master_Transmit(&hi2c2, LSM6DS33_I2C_ADDR << 1, uAddrAndBuf, len + 1, 10000) != HAL_OK) - { - TRACE("I2C B2 ERROR: WriteRegister failed"); - return false; - } - return true; -} - -bool IMUgetConf(void) -{ - uint8_t ui8_regs[2] = {0}; - - if (!I2C_LSM6DS33_ReadRegister(LSM6DS33_CTRL1_XL_ADDR, ui8_regs, 2)) - { - TRACE("ERROR: LSM6DS33 did not respond to I2C address"); - return false; - } - - switch ((ui8_regs[0] >> 4) & 0x0F) // CTRL1_XL - { - case LSM6DS33_ODR_0Hz: IMUsettings.linacc_odr = 0; TRACE("LSM6DS33 lin. acc. output turned off"); break; - case LSM6DS33_ODR_12_5Hz: IMUsettings.linacc_odr = 13; break; - case LSM6DS33_ODR_26Hz: IMUsettings.linacc_odr = 26; break; - case LSM6DS33_ODR_52Hz: IMUsettings.linacc_odr = 52; break; - case LSM6DS33_ODR_104Hz: IMUsettings.linacc_odr = 104; break; - case LSM6DS33_ODR_208Hz: IMUsettings.linacc_odr = 208; break; - case LSM6DS33_ODR_416Hz: IMUsettings.linacc_odr = 417; break; - case LSM6DS33_ODR_833Hz: IMUsettings.linacc_odr = 833; break; - case LSM6DS33_ODR_1_66kHz: IMUsettings.linacc_odr = 1667; break; - case LSM6DS33_ODR_3_33kHz: IMUsettings.linacc_odr = 3333; break; - case LSM6DS33_ODR_6_66kHz: IMUsettings.linacc_odr = 6667; break; - default: TRACE("ERROR: LSM6DS33 lin.acc. output data rate at illegal setting"); return false; break; - } - if (IMUsettings.linacc_odr > 0) TRACE("LSM6DS33 lin. acc. output at %i Hz", IMUsettings.linacc_odr); - - switch ((ui8_regs[0] >> 2) & 0x03) - { - case LSM6DS33_LA_FS_2G: IMUsettings.linacc_mG = 0.061; break; - case LSM6DS33_LA_FS_4G: IMUsettings.linacc_mG = 0.122; break; - case LSM6DS33_LA_FS_8G: IMUsettings.linacc_mG = 0.244; break; - case LSM6DS33_LA_FS_16G: IMUsettings.linacc_mG = 0.488; break; - default: TRACE("ERROR: LSM6DS33 lin. acc full scale value at illegal setting"); return false; break; - } - TRACE("LSM6DS33 lin. acc. resolution %.2f G", IMUsettings.linacc_mG); - - switch ((ui8_regs[0] >> 2) & 0x03) - { - case LSM6DS33_LA_AABW_400Hz: IMUsettings.linacc_aabw = 400; break; - case LSM6DS33_LA_AABW_200Hz: IMUsettings.linacc_aabw = 200; break; - case LSM6DS33_LA_AABW_100Hz: IMUsettings.linacc_aabw = 100; break; - case LSM6DS33_LA_AABW_50Hz: IMUsettings.linacc_aabw = 50; break; - default: TRACE("ERROR: LSM6DS33 lin. acc anti aliasing bandwidth at illegal setting"); return false; break; - } - TRACE("LSM6DS33 lin. acc. anti aliasing bandwidth at %i Hz", IMUsettings.linacc_aabw); - - switch ((ui8_regs[1] >> 4) & 0x0F) // CTRL2_G - { - case LSM6DS33_ODR_0Hz: IMUsettings.gyro_odr = 0; TRACE("LSM6DS33 gyro output turned off"); break; - case LSM6DS33_ODR_12_5Hz: IMUsettings.gyro_odr = 13; break; - case LSM6DS33_ODR_26Hz: IMUsettings.gyro_odr = 26; break; - case LSM6DS33_ODR_52Hz: IMUsettings.gyro_odr = 52; break; - case LSM6DS33_ODR_104Hz: IMUsettings.gyro_odr = 104; break; - case LSM6DS33_ODR_208Hz: IMUsettings.gyro_odr = 208; break; - case LSM6DS33_ODR_416Hz: IMUsettings.gyro_odr = 417; break; - case LSM6DS33_ODR_833Hz: IMUsettings.gyro_odr = 833; break; - case LSM6DS33_ODR_1_66kHz: IMUsettings.gyro_odr = 1667; break; - default: TRACE("ERROR: LSM6DS33 gyro output data rate at illegal setting"); return false; break; - } - if (IMUsettings.gyro_odr > 0) TRACE("LSM6DS33 gyro output at %i Hz", IMUsettings.gyro_odr); - - switch ((ui8_regs[1] >> 1) & 0x07) - { - case LSM6DS33_GY_FS_125dps: IMUsettings.gyro_mDPS = 4.375; break; - case LSM6DS33_GY_FS_250dps: IMUsettings.gyro_mDPS = 8.75; break; - case LSM6DS33_GY_FS_500dps: IMUsettings.gyro_mDPS = 17.5; break; - case LSM6DS33_GY_FS_1000dps: IMUsettings.gyro_mDPS = 35.0; break; - case LSM6DS33_GY_FS_2000dps: IMUsettings.gyro_mDPS = 70.0; break; - default: TRACE("ERROR: LSM6DS33 gyro full scale value at illegal setting"); return false; break; - } - TRACE("LSM6DS33 raw gyro resolution: %.2f milli-degrees/sec.", IMUsettings.gyro_mDPS); - return true; -} - -void init_imu_i2c(void) -{ - TRACE("I2C IMU Init"); - - hi2c2.Instance = I2C_B2; - hi2c2.Init.ClockSpeed = I2C_B2_CLK_RATE; - hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2; - hi2c2.Init.OwnAddress1 = 0; - hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; - hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; - hi2c2.Init.OwnAddress2 = 0; - hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; - hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; - if (HAL_I2C_Init(&hi2c2) != HAL_OK) - { - TRACE("I2C B2 ERROR: HAL_I2C_Init() failed"); - } - // Configure Analogue filter - if (HAL_I2CEx_ConfigAnalogFilter(&hi2c2, I2C_ANALOGFILTER_ENABLE) != HAL_OK) - { - TRACE("I2C B2 ERROR: HAL_I2CEx_ConfigAnalogFilter() failed"); - } - // Configure Digital filter - if (HAL_I2CEx_ConfigDigitalFilter(&hi2c2, 0) != HAL_OK) - { - TRACE("I2C B2 ERROR: HAL_I2CEx_ConfigDigitalFilter() failed"); - } -} - -bool imu_lsm6ds33_init(void) -{ - uint8_t ui8_reg[2] = {0}; - - GPIO_SetBits(AUX_I2C_B2_PWR_GPIO, AUX_I2C_B2_PWR_GPIO_PIN); // Turn on AUX1 power - - init_imu_i2c(); - - if (!I2C_LSM6DS33_ReadRegister(LSM6DS33_WHO_AM_I_ADDR, ui8_reg, 1)) - { - TRACE("ERROR: LSM6DS33 did not respond to I2C address"); - return false; - } - if (ui8_reg[0] != LSM6DS33_WHOAMI) - { - TRACE("LSM6DS33 ERROR: Product ID read failes"); - return false; - } - TRACE("LSM6DS33 detected"); - - // Set IMU configuration - ui8_reg[0] = (LSM6DS33_ODR_104Hz << 4) | (LSM6DS33_LA_FS_4G << 2) | LSM6DS33_LA_AABW_100Hz; // Linear acceleration configuration - ui8_reg[1] = (LSM6DS33_ODR_104Hz << 4) | (LSM6DS33_GY_FS_125dps < 1); // Gyro configuration - if (!I2C_LSM6DS33_WriteRegister(LSM6DS33_CTRL1_XL_ADDR, ui8_reg, 2)) - { - TRACE("ERROR: Failed to write LSM6DS33 configuration"); - return false; - } - - if (!IMUgetConf()) - { - TRACE("ERROR: Failed ro read LSM6DS33 configuration"); - return false; - } - return true; -} - -bool imu_lsm6ds33_read() -{ - uint8_t ui8_regs[14] = {0}; - - int16_t i16_rawTemperature = 0; - int16_t i16_rawGyroX = 0; - int16_t i16_rawGyroY = 0; - int16_t i16_rawGyroZ = 0; - int16_t i16_rawAccX = 0; - int16_t i16_rawAccY = 0; - int16_t i16_rawAccZ = 0; - - // Check first if new data is available - if (!I2C_LSM6DS33_ReadRegister(LSM6DS33_STATUS_REG_ADDR, ui8_regs, 1)) - { - TRACE("ERROR: LSM6DS33 did not respond to I2C address"); - return false; - } - if ((ui8_regs[0] & 0x07) != 0x07) - { - TRACE("ERROR: LSM6DS33 has no new data available yet"); - return false; - } - - if (!I2C_LSM6DS33_ReadRegister(LSM6DS33_OUT_TEMP_L_ADDR, ui8_regs, 14)) - { - TRACE("ERROR: LSM6DS33 did not respond to I2C address"); - return false; - } - - i16_rawTemperature = (ui8_regs[1] << 8) | ui8_regs[0]; - i16_rawGyroX = (ui8_regs[3] << 8) | ui8_regs[2]; - i16_rawGyroY = (ui8_regs[5] << 8) | ui8_regs[4]; - i16_rawGyroZ = (ui8_regs[7] << 8) | ui8_regs[6]; - i16_rawAccX = (ui8_regs[9] << 8) | ui8_regs[8]; - i16_rawAccY = (ui8_regs[11] << 8) | ui8_regs[10]; - i16_rawAccZ = (ui8_regs[13] << 8) | ui8_regs[12]; - - IMUoutput.fGyroXradps = i16_rawGyroX * IMUsettings.gyro_mDPS * M_PI/180.0 / 1000.0; - IMUoutput.fGyroYradps = i16_rawGyroY * IMUsettings.gyro_mDPS * M_PI/180.0 / 1000.0; - IMUoutput.fGyroZradps = i16_rawGyroZ * IMUsettings.gyro_mDPS * M_PI/180.0 / 1000.0; - - IMUoutput.fAccX = i16_rawAccX * IMUsettings.linacc_mG * GRAVITY_EARTH / 1000.0; - IMUoutput.fAccY = i16_rawAccY * IMUsettings.linacc_mG * GRAVITY_EARTH / 1000.0; - IMUoutput.fAccZ = i16_rawAccZ * IMUsettings.linacc_mG * GRAVITY_EARTH / 1000.0; - - IMUoutput.fTemperatureDegC = (float)i16_rawTemperature / 16.0 + 25.0; - /*TRACE("LSM6DS33: %.2f deg.C, GyroXYZ [rad/s]: %.2f, %.2f, %.2f, AccXYZ [m/s^2]: %.2f %.2f %.2f", - IMUoutput.fTemperatureDegC, - IMUoutput.fGyroXradps, IMUoutput.fGyroYradps, IMUoutput.fGyroZradps, - IMUoutput.fAccX, IMUoutput.fAccY, IMUoutput.fAccZ); */ - return true; -} diff --git a/radio/src/targets/horus/imu_lsm6ds33.h b/radio/src/targets/horus/imu_lsm6ds33.h deleted file mode 100644 index 16ec03f8b..000000000 --- a/radio/src/targets/horus/imu_lsm6ds33.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) EdgeTX - * - * Based on code named - * opentx - https://github.com/opentx/opentx - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#pragma once - -#include "i2c_driver.h" - -#define GRAVITY_EARTH 9.80665F // m/s^2 - -#define LSM6DS33_I2C_ADDR 0x6A -#define LSM6DS33_WHOAMI 0x69 -#define LSM6DS33_TIMEOUT 3 // 3ms - -// LSM6DS33 register map -#define LSM6DS33_FUNC_CFG_ACCESS_ADDR 0x01 -#define LSM6DS33_FIFO_CTRL1_ADDR 0x06 -#define LSM6DS33_FIFO_CTRL2_ADDR 0x07 -#define LSM6DS33_FIFO_CTRL3_ADDR 0x08 -#define LSM6DS33_FIFO_CTRL4_ADDR 0x09 -#define LSM6DS33_FIFO_CTRL5_ADDR 0x0A -#define LSM6DS33_ORIENT_CFG_G_ADDR 0x0B -#define LSM6DS33_INT1_CTRL_ADDR 0x0D -#define LSM6DS33_INT2_CTRL_ADDR 0x0E -#define LSM6DS33_WHO_AM_I_ADDR 0x0F -#define LSM6DS33_CTRL1_XL_ADDR 0x10 -#define LSM6DS33_CTRL2_G_ADDR 0x11 -#define LSM6DS33_CTRL3_C_ADDR 0x12 -#define LSM6DS33_CTRL4_C_ADDR 0x13 -#define LSM6DS33_CTRL5_C_ADDR 0x14 -#define LSM6DS33_CTRL6_C_ADDR 0x15 -#define LSM6DS33_CTRL7_G_ADDR 0x16 -#define LSM6DS33_CTRL8_XL_ADDR 0x17 -#define LSM6DS33_CTRL9_XL_ADDR 0x18 -#define LSM6DS33_CTRL10_C_ADDR 0x19 -#define LSM6DS33_WAKE_UP_SRC_ADDR 0x1B -#define LSM6DS33_TAP_SRC_ADDR 0x1C -#define LSM6DS33_D6D_SRC_ADDR 0x1D -#define LSM6DS33_STATUS_REG_ADDR 0x1E -#define LSM6DS33_OUT_TEMP_L_ADDR 0x20 -#define LSM6DS33_OUT_TEMP_H_ADDR 0x21 -#define LSM6DS33_OUTX_L_G_ADDR 0x22 -#define LSM6DS33_OUTX_H_G_ADDR 0x23 -#define LSM6DS33_OUTY_L_G_ADDR 0x24 -#define LSM6DS33_OUTY_H_G_ADDR 0x25 -#define LSM6DS33_OUTZ_L_G_ADDR 0x26 -#define LSM6DS33_OUTZ_H_G_ADDR 0x27 -#define LSM6DS33_OUTX_L_XL_ADDR 0x28 -#define LSM6DS33_OUTX_H_XL_ADDR 0x29 -#define LSM6DS33_OUTY_L_XL_ADDR 0x2A -#define LSM6DS33_OUTY_H_XL_ADDR 0x2B -#define LSM6DS33_OUTZ_L_XL_ADDR 0x2C -#define LSM6DS33_OUTZ_H_XL_ADDR 0x2D -#define LSM6DS33_FIFO_STATUS1_ADDR 0x3A -#define LSM6DS33_FIFO_STATUS2_ADDR 0x3B -#define LSM6DS33_FIFO_STATUS3_ADDR 0x3C -#define LSM6DS33_FIFO_STATUS4_ADDR 0x3D -#define LSM6DS33_FIFO_DATA_OUT_L_ADDR 0x3E -#define LSM6DS33_FIFO_DATA_OUT_H_ADDR 0x3F -#define LSM6DS33_TIMESTAMP0_REG_ADDR 0x40 -#define LSM6DS33_TIMESTAMP1_REG_ADDR 0x41 -#define LSM6DS33_TIMESTAMP2_REG_ADDR 0x42 -#define LSM6DS33_STEP_TIMESTAMP_L_ADDR 0x49 -#define LSM6DS33_STEP_TIMESTAMP_H_ADDR 0x4A -#define LSM6DS33_STEP_COUNTER_L_ADDR 0x4B -#define LSM6DS33_STEP_COUNTER_H_ADDR 0x4C -#define LSM6DS33_FUNC_SRC_ADDR 0x53 -#define LSM6DS33_TAP_CFG_ADDR 0x58 -#define LSM6DS33_TAP_THS_6D_ADDR 0x59 -#define LSM6DS33_INT_DUR2_ADDR 0x5A -#define LSM6DS33_WAKE_UP_THS_ADDR 0x5B -#define LSM6DS33_WAKE_UP_DUR_ADDR 0x5C -#define LSM6DS33_FREE_FALL_ADDR 0x5D -#define LSM6DS33_MD1_CFG_ADDR 0x5E -#define LSM6DS33_MD2_CFG_ADDR 0x5F - -#define LSM6DS33_ODR_0Hz 0x00 -#define LSM6DS33_ODR_12_5Hz 0x01 -#define LSM6DS33_ODR_26Hz 0x02 -#define LSM6DS33_ODR_52Hz 0x03 -#define LSM6DS33_ODR_104Hz 0x04 -#define LSM6DS33_ODR_208Hz 0x05 -#define LSM6DS33_ODR_416Hz 0x06 -#define LSM6DS33_ODR_833Hz 0x07 -#define LSM6DS33_ODR_1_66kHz 0x08 -#define LSM6DS33_ODR_3_33kHz 0x09 -#define LSM6DS33_ODR_6_66kHz 0x0A - -#define LSM6DS33_LA_FS_2G 0x00 -#define LSM6DS33_LA_FS_16G 0x01 -#define LSM6DS33_LA_FS_4G 0x02 -#define LSM6DS33_LA_FS_8G 0x03 - -#define LSM6DS33_LA_AABW_400Hz 0x00 -#define LSM6DS33_LA_AABW_200Hz 0x01 -#define LSM6DS33_LA_AABW_100Hz 0x02 -#define LSM6DS33_LA_AABW_50Hz 0x03 - -#define LSM6DS33_GY_FS_125dps 0x01 -#define LSM6DS33_GY_FS_250dps 0x00 -#define LSM6DS33_GY_FS_500dps 0x02 -#define LSM6DS33_GY_FS_1000dps 0x04 -#define LSM6DS33_GY_FS_2000dps 0x05 - -typedef struct { - int16_t linacc_odr; - float linacc_mG; // milli G per Bit - int16_t linacc_aabw; - int16_t gyro_odr; - float gyro_mDPS; // milli degrees per second per Bit -} sIMUsettings; - -typedef struct { - float fTemperatureDegC; //°C - float fAccX, fAccY, fAccZ; // m/s^2 - float fGyroXradps, fGyroYradps, fGyroZradps; // rad/s -} sIMUoutput; - -extern sIMUoutput IMUoutput; - -bool imu_lsm6ds33_init(void); -bool imu_lsm6ds33_read(); diff --git a/radio/src/targets/pa01/CMakeLists.txt b/radio/src/targets/pa01/CMakeLists.txt index 0caeabfb4..393cb3a7b 100644 --- a/radio/src/targets/pa01/CMakeLists.txt +++ b/radio/src/targets/pa01/CMakeLists.txt @@ -146,7 +146,7 @@ add_library(board OBJECT EXCLUDE_FROM_ALL ${TARGET_SRC_DIR}/battery_driver.cpp targets/common/arm/stm32/audio_dac_driver.cpp targets/common/arm/stm32/heartbeat_driver.cpp - targets/common/arm/stm32/lsm6ds_driver.cpp + drivers/lsm6ds.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/module_timer_driver.cpp targets/common/arm/stm32/stm32_pulse_driver.cpp diff --git a/radio/src/targets/pa01/board.cpp b/radio/src/targets/pa01/board.cpp index 9eca340dd..19fb21756 100644 --- a/radio/src/targets/pa01/board.cpp +++ b/radio/src/targets/pa01/board.cpp @@ -47,11 +47,13 @@ #include "sdcard.h" #include "debug.h" #include "keys.h" +#include "gyro.h" #include "flysky_gimbal_driver.h" #include "timers_driver.h" #include "battery_driver.h" +#include "drivers/lsm6ds.h" #include @@ -126,6 +128,14 @@ void boardBLInit() flashRegisterDriver(QSPI_BASE, 8 * 1024 * 1024, &extflash_driver); } +static void gyroInit() +{ + const etx_imu_t candidates[] = { + { &imu_lsm6ds_driver, IMU_I2C_BUS, IMU_I2C_ADDRESS }, + }; + gyroStart(imuDetect(candidates, DIM(candidates))); +} + bool pwrPressedDebounced() { static bool debouncedState = 0; @@ -377,6 +387,8 @@ void boardInit() #if defined(RTCLOCK) rtcInit(); // RTC must be initialized before rambackupRestore() is called #endif + + gyroInit(); } extern void rtcDisableBackupReg(); diff --git a/radio/src/targets/simu/CMakeLists.txt b/radio/src/targets/simu/CMakeLists.txt index f2c2ee523..0f71244e7 100644 --- a/radio/src/targets/simu/CMakeLists.txt +++ b/radio/src/targets/simu/CMakeLists.txt @@ -35,7 +35,6 @@ set(SIMU_DRIVERS module_drivers.cpp led_driver.cpp backlight_driver.cpp - gyro_driver.cpp bt_driver.cpp timers_driver.cpp abnormal_reboot.cpp diff --git a/radio/src/targets/st16/CMakeLists.txt b/radio/src/targets/st16/CMakeLists.txt index 76644ff4b..f02857a8d 100644 --- a/radio/src/targets/st16/CMakeLists.txt +++ b/radio/src/targets/st16/CMakeLists.txt @@ -149,7 +149,7 @@ add_library(board OBJECT EXCLUDE_FROM_ALL ${TARGET_SRC_DIR}/touch_driver.cpp ${TARGET_SRC_DIR}/battery_driver.cpp targets/common/arm/stm32/heartbeat_driver.cpp - targets/common/arm/stm32/lsm6ds_driver.cpp + drivers/lsm6ds.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/module_timer_driver.cpp targets/common/arm/stm32/stm32_pulse_driver.cpp diff --git a/radio/src/targets/st16/board.cpp b/radio/src/targets/st16/board.cpp index dd6f6aeeb..1b2dd36ae 100644 --- a/radio/src/targets/st16/board.cpp +++ b/radio/src/targets/st16/board.cpp @@ -48,11 +48,13 @@ #include "sdcard.h" #include "debug.h" #include "keys.h" +#include "gyro.h" #include "flysky_gimbal_driver.h" #include "timers_driver.h" #include "battery_driver.h" +#include "drivers/lsm6ds.h" #include "bitmapbuffer.h" #include "colors.h" @@ -173,6 +175,14 @@ void boardBLInit() flashRegisterDriver(QSPI_BASE, 8 * 1024 * 1024, &extflash_driver); } +static void gyroInit() +{ + const etx_imu_t candidates[] = { + { &imu_lsm6ds_driver, IMU_I2C_BUS, IMU_I2C_ADDRESS }, + }; + gyroStart(imuDetect(candidates, DIM(candidates))); +} + void boardInit() { // enable interrupts @@ -263,6 +273,8 @@ void boardInit() #if defined(RTCLOCK) rtcInit(); // RTC must be initialized before rambackupRestore() is called #endif + + gyroInit(); } extern void rtcDisableBackupReg(); diff --git a/radio/src/targets/stm32h7s78-dk/CMakeLists.txt b/radio/src/targets/stm32h7s78-dk/CMakeLists.txt index 2007cde17..edb3dc419 100644 --- a/radio/src/targets/stm32h7s78-dk/CMakeLists.txt +++ b/radio/src/targets/stm32h7s78-dk/CMakeLists.txt @@ -99,7 +99,6 @@ add_library(board OBJECT EXCLUDE_FROM_ALL ${TARGET_SRC_DIR}/tp_gt911.cpp ${TARGET_SRC_DIR}/audio_driver.cpp drivers/wm8904.cpp - targets/common/arm/stm32/lsm6ds_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/stm32_switch_driver.cpp targets/common/arm/stm32/stm32_i2s.cpp diff --git a/radio/src/targets/stm32h7s78-dk/board.cpp b/radio/src/targets/stm32h7s78-dk/board.cpp index 69e383ec5..5e5c7bfab 100644 --- a/radio/src/targets/stm32h7s78-dk/board.cpp +++ b/radio/src/targets/stm32h7s78-dk/board.cpp @@ -40,6 +40,7 @@ #include "sdcard.h" #include "touch.h" #include "debug.h" +#include "gyro.h" #include "timers_driver.h" #include "tp_gt911.h" diff --git a/radio/src/targets/t15pro/CMakeLists.txt b/radio/src/targets/t15pro/CMakeLists.txt index c306379ab..6dc29aa95 100644 --- a/radio/src/targets/t15pro/CMakeLists.txt +++ b/radio/src/targets/t15pro/CMakeLists.txt @@ -149,7 +149,6 @@ add_library(board OBJECT EXCLUDE_FROM_ALL ${BOARD_SRC_DIR}/touch_driver.cpp targets/common/arm/stm32/audio_dac_driver.cpp targets/common/arm/stm32/heartbeat_driver.cpp - targets/common/arm/stm32/lsm6ds_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/module_timer_driver.cpp targets/common/arm/stm32/stm32_pulse_driver.cpp diff --git a/radio/src/targets/taranis/CMakeLists.txt b/radio/src/targets/taranis/CMakeLists.txt index f3a71ec29..45b18e59d 100644 --- a/radio/src/targets/taranis/CMakeLists.txt +++ b/radio/src/targets/taranis/CMakeLists.txt @@ -627,7 +627,7 @@ if(USB_CHARGER) endif() if(IMU) - target_sources(board PRIVATE targets/common/arm/stm32/lsm6ds_driver.cpp) + target_sources(board PRIVATE drivers/lsm6ds.cpp) endif() if(AUTOUPDATE) diff --git a/radio/src/targets/taranis/board.cpp b/radio/src/targets/taranis/board.cpp index 1ecf9ce99..1866d70f8 100644 --- a/radio/src/targets/taranis/board.cpp +++ b/radio/src/targets/taranis/board.cpp @@ -125,6 +125,21 @@ void SDLEDpwrInit() } #endif +#if defined(IMU) && defined(IMU_I2C_BUS) && defined(IMU_I2C_BUS) +#include "drivers/lsm6ds.h" +#include "stm32_i2c_driver.h" + +#define HAS_IMU + +static void gyroInit() +{ + const etx_imu_t candidates[] = { + { &imu_lsm6ds_driver, IMU_I2C_BUS, IMU_I2C_ADDRESS }, + }; + gyroStart(imuDetect(candidates, DIM(candidates))); +} +#endif + void boardInit() { LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG); @@ -277,6 +292,10 @@ void boardInit() #if defined(RADIO_GX12) gpio_init(HALL_SYNC, GPIO_OUT, GPIO_PIN_SPEED_LOW); #endif + +#if defined(HAS_IMU) + gyroInit(); +#endif } #endif diff --git a/radio/src/targets/tx15/CMakeLists.txt b/radio/src/targets/tx15/CMakeLists.txt index 4317b994e..a61dd05bd 100644 --- a/radio/src/targets/tx15/CMakeLists.txt +++ b/radio/src/targets/tx15/CMakeLists.txt @@ -45,6 +45,7 @@ endif() # IMU support set(IMU ON) add_definitions(-DIMU_ICM4207C) +add_definitions(-DIMU_SC7U22) # for size report script set(CPU_TYPE_FULL STM32H750xB) @@ -144,6 +145,9 @@ set(BOARD_COMMON_SRC ${BOARD_SRC_DIR}/extflash_driver.cpp ${BOARD_SRC_DIR}/usb_charger_driver.cpp ${TARGET_SRC_DIR}/key_driver.cpp + drivers/pca95xx.cpp + drivers/icm42607C.cpp + drivers/sc7u22.cpp targets/common/arm/stm32/abnormal_reboot.cpp targets/common/arm/stm32/delays_driver.cpp targets/common/arm/stm32/dma2d.cpp @@ -152,7 +156,6 @@ set(BOARD_COMMON_SRC targets/common/arm/stm32/rotary_encoder_driver.cpp targets/common/arm/stm32/rtc_driver.cpp targets/common/arm/stm32/watchdog_driver.cpp - drivers/pca95xx.cpp ) if(BLUETOOTH) @@ -186,8 +189,6 @@ add_library(board OBJECT EXCLUDE_FROM_ALL ${BOARD_COMMON_SRC} ${BOARD_SRC_DIR}/tp_gt911.cpp ${BOARD_SRC_DIR}/audio_driver.cpp - drivers/icm42607C.cpp - drivers/imu_filter.cpp drivers/tas2505.cpp targets/common/arm/stm32/heartbeat_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp diff --git a/radio/src/targets/tx15/hal.h b/radio/src/targets/tx15/hal.h index 9e64ef5a1..a533c6b97 100644 --- a/radio/src/targets/tx15/hal.h +++ b/radio/src/targets/tx15/hal.h @@ -382,8 +382,8 @@ TIM17: ROTARY_ENCODER_TIMER // IMU #define IMU_I2C_BUS I2C_Bus_1 -#define IMU_I2C_ADDRESS 0x6A #define IMU_INT_GPIO GPIO_PIN(GPIOG, 13) // PG.13 + // IMU_INT_EXTI IRQ #if !defined(USE_EXTI15_10_IRQ) #define USE_EXTI15_10_IRQ diff --git a/radio/src/targets/tx16smk3/CMakeLists.txt b/radio/src/targets/tx16smk3/CMakeLists.txt index bc67a36c6..f6332280e 100644 --- a/radio/src/targets/tx16smk3/CMakeLists.txt +++ b/radio/src/targets/tx16smk3/CMakeLists.txt @@ -36,6 +36,7 @@ set(INTERNAL_GPS_BAUDRATE "9600" CACHE STRING "Baud rate for internal GPS") # IMU support set(IMU ON) add_definitions(-DIMU_ICM4207C) +add_definitions(-DIMU_SC7U22) # for size report script set(CPU_TYPE_FULL STM32H750xB) @@ -172,9 +173,9 @@ add_library(board OBJECT EXCLUDE_FROM_ALL ${BOARD_SRC_DIR}/tp_gt911.cpp ${BOARD_SRC_DIR}/audio_driver.cpp ${BOARD_SRC_DIR}/luminosity_sensor.cpp - drivers/icm42607C.cpp - drivers/imu_filter.cpp drivers/tas2505.cpp + drivers/icm42607C.cpp + drivers/sc7u22.cpp targets/common/arm/stm32/heartbeat_driver.cpp targets/common/arm/stm32/mixer_scheduler_driver.cpp targets/common/arm/stm32/module_timer_driver.cpp diff --git a/radio/src/targets/tx16smk3/hal.h b/radio/src/targets/tx16smk3/hal.h index 0178280a0..7e50bff91 100644 --- a/radio/src/targets/tx16smk3/hal.h +++ b/radio/src/targets/tx16smk3/hal.h @@ -572,8 +572,7 @@ USART6: INTMODULE_USART #endif #define IMU_I2C_BUS I2C_Bus_2 -#define IMU_I2C_ADDRESS 0x6A -#define IMU_INT_GPIO GPIO_PIN(GPIOG, 13) // PG.13 +#define IMU_INT_GPIO GPIO_PIN(GPIOG, 13) // PG.13 #if !defined(USE_EXTI15_10_IRQ) #define USE_EXTI15_10_IRQ #define EXTI15_10_IRQ_Priority 6 diff --git a/radio/src/tasks/mixer_task.cpp b/radio/src/tasks/mixer_task.cpp index e7b24297a..7be269956 100644 --- a/radio/src/tasks/mixer_task.cpp +++ b/radio/src/tasks/mixer_task.cpp @@ -128,7 +128,7 @@ constexpr uint8_t MIXER_MAX_PERIOD = MAX_REFRESH_RATE / 1000 /*ms*/; void execMixerFrequentActions() { #if defined(IMU) - gyro.wakeup(); + gyroWakeup(); #endif #if defined(BLUETOOTH) @@ -138,10 +138,6 @@ void execMixerFrequentActions() void mixerTask() { -#if defined(IMU) - gyroInit(); -#endif - while (task_running()) { int timeout = 0; diff --git a/radio/src/translations/i18n/cn.h b/radio/src/translations/i18n/cn.h index 77012ced5..9837c8bd1 100644 --- a/radio/src/translations/i18n/cn.h +++ b/radio/src/translations/i18n/cn.h @@ -1202,6 +1202,7 @@ #define TR_ALTSENSOR "Alt 传感器" #define TR_CELLSENSOR "Cell 传感器" #define TR_GPSSENSOR "GPS 传感器" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "传感器" #define TR_AUTOOFFSET "自动偏移值" #define TR_ONLYPOSITIVE "正向" diff --git a/radio/src/translations/i18n/cz.h b/radio/src/translations/i18n/cz.h index 31373e446..2ab0208dd 100644 --- a/radio/src/translations/i18n/cz.h +++ b/radio/src/translations/i18n/cz.h @@ -1205,6 +1205,7 @@ #define TR_ALTSENSOR "Senzor výšky" #define TR_CELLSENSOR "Senzor článků" #define TR_GPSSENSOR "GPS senzor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Senzor" #define TR_AUTOOFFSET "Auto offset" #define TR_ONLYPOSITIVE "Jen kladné" diff --git a/radio/src/translations/i18n/da.h b/radio/src/translations/i18n/da.h index f852735c2..9166bd009 100644 --- a/radio/src/translations/i18n/da.h +++ b/radio/src/translations/i18n/da.h @@ -1207,6 +1207,7 @@ #define TR_ALTSENSOR "Højde sensor" #define TR_CELLSENSOR "Cell sensor" #define TR_GPSSENSOR "GPS sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto offset" #define TR_ONLYPOSITIVE "Positive" diff --git a/radio/src/translations/i18n/de.h b/radio/src/translations/i18n/de.h index 9707d2a8b..ec873f890 100644 --- a/radio/src/translations/i18n/de.h +++ b/radio/src/translations/i18n/de.h @@ -1201,6 +1201,7 @@ #define TR_ALTSENSOR "Höhen Sensor" #define TR_CELLSENSOR "Zellen Sensor" #define TR_GPSSENSOR "GPS Sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto Offset" #define TR_ONLYPOSITIVE "Nur Positiv" diff --git a/radio/src/translations/i18n/en.h b/radio/src/translations/i18n/en.h index aefa0f2f3..618debff2 100644 --- a/radio/src/translations/i18n/en.h +++ b/radio/src/translations/i18n/en.h @@ -1203,6 +1203,7 @@ #define TR_ALTSENSOR "Alt sensor" #define TR_CELLSENSOR "Cell sensor" #define TR_GPSSENSOR "GPS sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto Offset" #define TR_ONLYPOSITIVE "Positive" diff --git a/radio/src/translations/i18n/es.h b/radio/src/translations/i18n/es.h index c88249068..c08ad3474 100644 --- a/radio/src/translations/i18n/es.h +++ b/radio/src/translations/i18n/es.h @@ -1203,6 +1203,7 @@ #define TR_ALTSENSOR "Alt sensor" #define TR_CELLSENSOR "Cell sensor" #define TR_GPSSENSOR "GPS sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto offset" #define TR_ONLYPOSITIVE "Positivo" diff --git a/radio/src/translations/i18n/fi.h b/radio/src/translations/i18n/fi.h index dcfe54ec2..49bbcbde3 100644 --- a/radio/src/translations/i18n/fi.h +++ b/radio/src/translations/i18n/fi.h @@ -1202,6 +1202,7 @@ #define TR_ALTSENSOR "Alt sensor" #define TR_CELLSENSOR "Cell sensor" #define TR_GPSSENSOR "GPS sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto Offset" #define TR_ONLYPOSITIVE "Positive" diff --git a/radio/src/translations/i18n/fr.h b/radio/src/translations/i18n/fr.h index 2ddb84a79..2544b973a 100644 --- a/radio/src/translations/i18n/fr.h +++ b/radio/src/translations/i18n/fr.h @@ -1205,6 +1205,7 @@ #define TR_ALTSENSOR "Capteur Alt." #define TR_CELLSENSOR "Capteur Elém." #define TR_GPSSENSOR "Capteur GPS" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Capteur" #define TR_AUTOOFFSET "Offset auto" #define TR_ONLYPOSITIVE "Positif" diff --git a/radio/src/translations/i18n/he.h b/radio/src/translations/i18n/he.h index 6bc93c6ca..b433767f3 100644 --- a/radio/src/translations/i18n/he.h +++ b/radio/src/translations/i18n/he.h @@ -1205,6 +1205,7 @@ #define TR_ALTSENSOR "Alt sensor" #define TR_CELLSENSOR "Cell sensor" #define TR_GPSSENSOR "GPS sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "חיישן" #define TR_AUTOOFFSET "Auto Offset" #define TR_ONLYPOSITIVE "חיובי" diff --git a/radio/src/translations/i18n/it.h b/radio/src/translations/i18n/it.h index f778f8a37..6cec0149e 100644 --- a/radio/src/translations/i18n/it.h +++ b/radio/src/translations/i18n/it.h @@ -1202,6 +1202,7 @@ #define TR_ALTSENSOR "Sensore Alt" #define TR_CELLSENSOR "Sensore Cell" #define TR_GPSSENSOR "Sensore GPS" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensore" #define TR_AUTOOFFSET "Offset Auto" #define TR_ONLYPOSITIVE "Positivo" diff --git a/radio/src/translations/i18n/jp.h b/radio/src/translations/i18n/jp.h index 3afcf3d1a..e36342a51 100644 --- a/radio/src/translations/i18n/jp.h +++ b/radio/src/translations/i18n/jp.h @@ -1201,6 +1201,7 @@ #define TR_ALTSENSOR "Altセンサー" #define TR_CELLSENSOR "セルセンサー" #define TR_GPSSENSOR "GPSセンサー" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "センサー" #define TR_AUTOOFFSET "自動オフセット" #define TR_ONLYPOSITIVE "ポジティブ" diff --git a/radio/src/translations/i18n/ko.h b/radio/src/translations/i18n/ko.h index ca837833f..fca1b999f 100644 --- a/radio/src/translations/i18n/ko.h +++ b/radio/src/translations/i18n/ko.h @@ -1248,6 +1248,7 @@ #define TR_ALTSENSOR "고도 센서" #define TR_CELLSENSOR "셀 전압 센서" #define TR_GPSSENSOR "GPS 센서" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "전류 센서" #define TR_AUTOOFFSET "자동 오프셋" #define TR_ONLYPOSITIVE "양수만" diff --git a/radio/src/translations/i18n/nl.h b/radio/src/translations/i18n/nl.h index e3f3b25b2..d9db8ed7b 100644 --- a/radio/src/translations/i18n/nl.h +++ b/radio/src/translations/i18n/nl.h @@ -1203,6 +1203,7 @@ #define TR_ALTSENSOR "Hoogte Sensor" #define TR_CELLSENSOR "Cellen Sensor" #define TR_GPSSENSOR "GPS Sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Stroomsensor" #define TR_AUTOOFFSET "Auto Offset" #define TR_ONLYPOSITIVE "Enkel positief" diff --git a/radio/src/translations/i18n/pl.h b/radio/src/translations/i18n/pl.h index 3e5bcacf0..c83aecf9f 100644 --- a/radio/src/translations/i18n/pl.h +++ b/radio/src/translations/i18n/pl.h @@ -1200,6 +1200,7 @@ #define TR_ALTSENSOR "Sensor wys." #define TR_CELLSENSOR "Sensor Cell" #define TR_GPSSENSOR "Sensor GPS" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto Ofset" #define TR_ONLYPOSITIVE "Dodatni" diff --git a/radio/src/translations/i18n/pt.h b/radio/src/translations/i18n/pt.h index 0d72cefb6..3f56949d4 100644 --- a/radio/src/translations/i18n/pt.h +++ b/radio/src/translations/i18n/pt.h @@ -1203,6 +1203,7 @@ #define TR_ALTSENSOR "Alt sensor" #define TR_CELLSENSOR "Cell sensor" #define TR_GPSSENSOR "GPS sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto Offset" #define TR_ONLYPOSITIVE "Positive" diff --git a/radio/src/translations/i18n/ru.h b/radio/src/translations/i18n/ru.h index f9493725a..fa731828f 100644 --- a/radio/src/translations/i18n/ru.h +++ b/radio/src/translations/i18n/ru.h @@ -1204,6 +1204,7 @@ #define TR_ALTSENSOR "Датчик высот" #define TR_CELLSENSOR "Датчик АКБ" #define TR_GPSSENSOR "Датчик GPS" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Датчик тока" #define TR_AUTOOFFSET "Авто смещ" #define TR_ONLYPOSITIVE "Положител" diff --git a/radio/src/translations/i18n/se.h b/radio/src/translations/i18n/se.h index f81049069..f8798164f 100644 --- a/radio/src/translations/i18n/se.h +++ b/radio/src/translations/i18n/se.h @@ -1213,6 +1213,7 @@ #define TR_ALTSENSOR "Höjdsensor" #define TR_CELLSENSOR "Cellsensor" #define TR_GPSSENSOR "GPS-sensor" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Sensor" #define TR_AUTOOFFSET "Auto offset" #define TR_ONLYPOSITIVE "Positiv" diff --git a/radio/src/translations/i18n/tw.h b/radio/src/translations/i18n/tw.h index f9d2630aa..9530fcd89 100644 --- a/radio/src/translations/i18n/tw.h +++ b/radio/src/translations/i18n/tw.h @@ -1200,6 +1200,7 @@ #define TR_ALTSENSOR "Alt 傳感器" #define TR_CELLSENSOR "Cell 傳感器" #define TR_GPSSENSOR "GPS 傳感器" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "傳感器" #define TR_AUTOOFFSET "自動偏移值" #define TR_ONLYPOSITIVE "正向" diff --git a/radio/src/translations/i18n/ua.h b/radio/src/translations/i18n/ua.h index 5490ff1cc..f80771fc2 100644 --- a/radio/src/translations/i18n/ua.h +++ b/radio/src/translations/i18n/ua.h @@ -1203,6 +1203,7 @@ #define TR_ALTSENSOR "Сенсор висоти" #define TR_CELLSENSOR "Сенсор комірки" #define TR_GPSSENSOR "GPS сенсор" +#define TR_GYRO "Gyro" #define TR_CURRENTSENSOR "Сенсор" #define TR_AUTOOFFSET "Авто зсув" #define TR_ONLYPOSITIVE "Позитив" diff --git a/radio/src/translations/sim_string_list.h b/radio/src/translations/sim_string_list.h index 6301b3e2d..2d132e9ec 100644 --- a/radio/src/translations/sim_string_list.h +++ b/radio/src/translations/sim_string_list.h @@ -586,6 +586,7 @@ #define STR_GPS_COORDS_FORMAT currentLangStrings->STR_GPS_COORDS_FORMAT #define STR_GPS currentLangStrings->STR_GPS #define STR_GPSSENSOR currentLangStrings->STR_GPSSENSOR +#define STR_GYRO currentLangStrings->STR_GYRO #define STR_GV currentLangStrings->STR_GV #define STR_GVARS currentLangStrings->STR_GVARS #define STR_HARDWARE currentLangStrings->STR_HARDWARE diff --git a/radio/src/translations/string_list.h b/radio/src/translations/string_list.h index 96ff7295a..8a4258d5d 100644 --- a/radio/src/translations/string_list.h +++ b/radio/src/translations/string_list.h @@ -585,6 +585,7 @@ STR(GLOBALVAR) STR(GPS_COORDS_FORMAT) STR(GPS) STR(GPSSENSOR) +STR(GYRO) STR(GV) STR(GVARS) STR(HARDWARE)