Co-authored-by: Malte Langermann <54738901+gagarinlg@users.noreply.github.com> Co-authored-by: 3djc <3djc@gh.com> Co-authored-by: raphaelcoeffic <1050031+raphaelcoeffic@users.noreply.github.com> Co-authored-by: philmoz <phil.a.mitchell@gmail.com> Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
183 lines
4.9 KiB
C++
183 lines
4.9 KiB
C++
/*
|
||
* 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.
|
||
*/
|
||
|
||
/*
|
||
WARNING: while this ICM42607C belong to the ICM426xx familly, it is NOT compatible
|
||
with code for generic ICM4267XX. All register have different addresses
|
||
*/
|
||
|
||
#include "edgetx.h"
|
||
#include "hal/i2c_driver.h"
|
||
#include "stm32_i2c_driver.h"
|
||
#include "icm42607C.h"
|
||
#include "imu_filter.h"
|
||
#include "stm32_gpio.h"
|
||
#include "inactivity_timer.h"
|
||
#include "hal.h"
|
||
|
||
int16_t getGyroTemperature()
|
||
{
|
||
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, 1000) < 0) {
|
||
TRACE("ICM426xx ERROR: TEMP_DATA_X0_REG i2c read error");
|
||
return -1;
|
||
}
|
||
|
||
return (((buf[0] << 8) | buf[1]) / 128) + 25;
|
||
}
|
||
|
||
int write_cmd(uint8_t reg, uint8_t val)
|
||
{
|
||
return i2c_write(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, &val, 1);
|
||
}
|
||
|
||
#if defined(IMU_INT_GPIO)
|
||
static void imu_exti_isr(void)
|
||
{
|
||
inactivityTimerReset(ActivitySource::MainControls);
|
||
}
|
||
#endif
|
||
|
||
static int write_mreg1(uint8_t reg, uint8_t val) {
|
||
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
|
||
return 0;
|
||
}
|
||
|
||
int gyroInit(void)
|
||
{
|
||
TRACE("ICM426xx I2C Init");
|
||
|
||
if (i2c_init(IMU_I2C_BUS) < 0) {
|
||
TRACE("ICM426xx ERROR: i2c_init bus error");
|
||
return -1;
|
||
}
|
||
|
||
if (i2c_dev_ready(IMU_I2C_BUS, ICM426xx_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, 1000) < 0) {
|
||
TRACE("ICM426xx ERROR: i2c read error");
|
||
return -1;
|
||
}
|
||
|
||
if (data != 0x61) {
|
||
TRACE("ICM426xx ERROR: this code only works on ICM42607C");
|
||
return -1;
|
||
}
|
||
|
||
if(write_cmd(SIGNAL_PATH_RESET, SOFT_RESET_CMD) < 0) {
|
||
TRACE("ICM426xx ERROR: SOFT_RESET_CMD error");
|
||
return -1;
|
||
}
|
||
delay_ms(100);
|
||
|
||
if(write_cmd(PWR_MGMT0_REG, PWR_MGMT0_ENABLE) < 0) {
|
||
TRACE("ICM426xx ERROR: PWR_MGMT0_REG error");
|
||
return -1;
|
||
}
|
||
delay_ms(10);
|
||
|
||
// Set gyro to 2000 dps, 1kHz 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
|
||
if (write_cmd(ACCEL_CONFIG0_REG, ACCEL_ODR_1KHZ) < 0) {
|
||
TRACE("ICM426xx ERROR: ACCEL_CONFIG0_REG error");
|
||
return -1;
|
||
}
|
||
delay_ms(1);
|
||
|
||
|
||
if (write_cmd(INT_CONFIG_REG, 0x00) < 0) {
|
||
TRACE("ICM426xx ERROR: INT_CONFIG_REG error");
|
||
return -1;
|
||
}
|
||
delay_ms(1);
|
||
|
||
#if defined(IMU_INT_GPIO)
|
||
// CCEL_WOM_X_THR:0-255(0-1g),0x10--16mg
|
||
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
|
||
if (write_cmd(WOM_CONFIG_REG, 0x03) < 0) return -1; // OR mode
|
||
delay_ms(1);
|
||
// enable INT1
|
||
if (write_cmd(INT_SOURCE1_REG, 0x07) < 0) return -1; // XYZ interrupt
|
||
delay_ms(1);
|
||
// config INT1 pin
|
||
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
|
||
|
||
return 0;
|
||
}
|
||
|
||
int gyroRead(uint8_t buffer[IMU_BUFFER_LENGTH])
|
||
{
|
||
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, 1000) < 0) {
|
||
TRACE("ICM426xx ERROR: i2c 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
|
||
|
||
reg = ACCEL_DATA_X0_REG;
|
||
if (stm32_i2c_read(IMU_I2C_BUS, ICM426xx_I2C_ADDR, reg, 1, buf, 6, 1000) < 0) {
|
||
TRACE("ICM426xx ERROR: i2c 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
|
||
|
||
return 0;
|
||
}
|