Skip to content

Commit 66463ec

Browse files
authored
feat(v16): add gyro support for HelloRadio V16 (#7232)
1 parent 0f5bc9b commit 66463ec

5 files changed

Lines changed: 281 additions & 6 deletions

File tree

radio/src/drivers/icm42627.cpp

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
/*
2+
* Copyright (C) EdgeTX
3+
*
4+
* Based on code named
5+
* opentx - https://github.com/opentx/opentx
6+
* th9x - http://code.google.com/p/th9x
7+
* er9x - http://code.google.com/p/er9x
8+
* gruvin9x - http://code.google.com/p/gruvin9x
9+
*
10+
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11+
*
12+
* This program is free software; you can redistribute it and/or modify
13+
* it under the terms of the GNU General Public License version 2 as
14+
* published by the Free Software Foundation.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU General Public License for more details.
20+
*/
21+
22+
#include "hal/i2c_driver.h"
23+
24+
#include "delays_driver.h"
25+
26+
#include "icm42627.h"
27+
28+
#include "debug.h"
29+
30+
static etx_i2c_bus_t s_i2c_bus;
31+
static uint16_t s_i2c_addr;
32+
33+
static constexpr uint32_t RESET_DELAY_MS = 150;
34+
static constexpr uint32_t READY_TIMEOUT_MS = 200;
35+
static constexpr uint32_t POWER_DELAY_MS = 20;
36+
static constexpr uint32_t CONFIG_DELAY_MS = 1;
37+
static constexpr uint8_t BURST_READ_LEN = 14;
38+
39+
static int write_cmd(uint8_t reg, uint8_t value)
40+
{
41+
return i2c_write(s_i2c_bus, s_i2c_addr, reg, 1, &value, 1);
42+
}
43+
44+
static int read_cmd(uint8_t reg, uint8_t *value)
45+
{
46+
return i2c_read(s_i2c_bus, s_i2c_addr, reg, 1, value, 1);
47+
}
48+
49+
static int wait_for_device_ready(uint32_t timeout_ms)
50+
{
51+
while (timeout_ms > 0) {
52+
if (i2c_dev_ready(s_i2c_bus, s_i2c_addr) >= 0) {
53+
return 0;
54+
}
55+
56+
delay_ms(10);
57+
if (timeout_ms < 10) {
58+
break;
59+
}
60+
timeout_ms -= 10;
61+
}
62+
63+
return -1;
64+
}
65+
66+
static int gyro42627Init(etx_i2c_bus_t bus, uint16_t addr)
67+
{
68+
s_i2c_bus = bus;
69+
s_i2c_addr = addr;
70+
71+
TRACE("ICM42627: probing I2C address 0x%02X", addr);
72+
73+
if (i2c_init(s_i2c_bus) < 0) {
74+
TRACE("ICM42627: i2c_init failed");
75+
return -1;
76+
}
77+
78+
if (i2c_dev_ready(s_i2c_bus, s_i2c_addr) < 0) {
79+
TRACE("ICM42627: device did not acknowledge on I2C");
80+
return -1;
81+
}
82+
83+
uint8_t who_am_i = 0;
84+
if (read_cmd(ICM42627_WHO_AM_I_REG, &who_am_i) < 0) {
85+
TRACE("ICM42627: failed to read WHO_AM_I");
86+
return -1;
87+
}
88+
89+
if (who_am_i != ICM42627_WHO_AM_I) {
90+
TRACE("ICM42627: unexpected WHO_AM_I 0x%02X, expected 0x%02X", who_am_i,
91+
ICM42627_WHO_AM_I);
92+
return -1;
93+
}
94+
95+
if (write_cmd(ICM42627_DEVICE_CONFIG_REG, ICM42627_RESET) < 0) {
96+
TRACE("ICM42627: failed to write reset command");
97+
}
98+
99+
delay_ms(RESET_DELAY_MS);
100+
101+
if (wait_for_device_ready(READY_TIMEOUT_MS) < 0) {
102+
TRACE("ICM42627: device did not become ready after reset");
103+
return -1;
104+
}
105+
106+
if (write_cmd(ICM42627_PWR_MGMT0_REG, ICM42627_PWR_STAGE1) < 0) {
107+
TRACE("ICM42627: failed to write PWR_MGMT0 stage 1");
108+
return -1;
109+
}
110+
delay_ms(POWER_DELAY_MS);
111+
112+
if (write_cmd(ICM42627_PWR_MGMT0_REG, ICM42627_PWR_STAGE2) < 0) {
113+
TRACE("ICM42627: failed to write PWR_MGMT0 stage 2");
114+
return -1;
115+
}
116+
delay_ms(POWER_DELAY_MS);
117+
118+
if (write_cmd(ICM42627_GYRO_CONFIG0_REG, ICM42627_GYRO_CONFIG) < 0) {
119+
TRACE("ICM42627: failed to write GYRO_CONFIG0");
120+
return -1;
121+
}
122+
delay_ms(CONFIG_DELAY_MS);
123+
124+
if (write_cmd(ICM42627_ACCEL_CONFIG0_REG, ICM42627_ACCEL_CONFIG) < 0) {
125+
TRACE("ICM42627: failed to write ACCEL_CONFIG0");
126+
return -1;
127+
}
128+
delay_ms(CONFIG_DELAY_MS);
129+
130+
if (write_cmd(ICM42627_GYRO_CONFIG1_REG, ICM42627_GYRO_FILTER) < 0) {
131+
TRACE("ICM42627: failed to write GYRO_CONFIG1");
132+
return -1;
133+
}
134+
delay_ms(CONFIG_DELAY_MS);
135+
136+
if (write_cmd(ICM42627_ACCEL_GYRO_BW_REG, ICM42627_ACCEL_GYRO_BW) < 0) {
137+
TRACE("ICM42627: failed to write ACCEL_GYRO_BW");
138+
return -1;
139+
}
140+
delay_ms(CONFIG_DELAY_MS);
141+
142+
if (write_cmd(ICM42627_ACCEL_CONFIG1_REG, ICM42627_ACCEL_FILTER) < 0) {
143+
TRACE("ICM42627: failed to write ACCEL_CONFIG1");
144+
return -1;
145+
}
146+
delay_ms(CONFIG_DELAY_MS);
147+
148+
if (write_cmd(ICM42627_BANK_SEL_REG, ICM42627_BANK1) < 0) {
149+
TRACE("ICM42627: failed to select register bank 1");
150+
return -1;
151+
}
152+
delay_ms(CONFIG_DELAY_MS);
153+
154+
if (write_cmd(ICM42627_GYRO_STATIC2_REG, ICM42627_GYRO_STATIC2) < 0) {
155+
TRACE("ICM42627: failed to write GYRO_STATIC2");
156+
return -1;
157+
}
158+
delay_ms(CONFIG_DELAY_MS);
159+
160+
if (write_cmd(ICM42627_BANK_SEL_REG, ICM42627_BANK0) < 0) {
161+
TRACE("ICM42627: failed to restore register bank 0");
162+
return -1;
163+
}
164+
delay_ms(CONFIG_DELAY_MS);
165+
166+
// Re-read WHO_AM_I after reset and banked configuration to catch a device
167+
// that stopped responding even though the initial probe succeeded.
168+
if (read_cmd(ICM42627_WHO_AM_I_REG, &who_am_i) < 0 ||
169+
who_am_i != ICM42627_WHO_AM_I) {
170+
TRACE("ICM42627: final WHO_AM_I check failed (0x%02X)", who_am_i);
171+
return -1;
172+
}
173+
174+
TRACE("ICM42627: init complete");
175+
return 0;
176+
}
177+
178+
static int gyro42627Read(etx_imu_data_t *data)
179+
{
180+
uint8_t buf[BURST_READ_LEN] = {0};
181+
182+
if (i2c_read(s_i2c_bus, s_i2c_addr, ICM42627_DATA_REG, 1, buf, sizeof(buf)) < 0) {
183+
TRACE("ICM42627: failed to read sensor sample block");
184+
return -1;
185+
}
186+
187+
const int16_t accel_x = (int16_t)((buf[2] << 8) | buf[3]);
188+
const int16_t accel_y = (int16_t)((buf[4] << 8) | buf[5]);
189+
const int16_t accel_z = (int16_t)((buf[6] << 8) | buf[7]);
190+
const int16_t gyro_x = (int16_t)((buf[8] << 8) | buf[9]);
191+
const int16_t gyro_y = (int16_t)((buf[10] << 8) | buf[11]);
192+
const int16_t gyro_z = (int16_t)((buf[12] << 8) | buf[13]);
193+
194+
data->accel_x = accel_y;
195+
data->accel_y = accel_x;
196+
data->accel_z = -accel_z;
197+
data->gyro_x = gyro_y;
198+
data->gyro_y = gyro_x;
199+
data->gyro_z = -gyro_z;
200+
201+
return 0;
202+
}
203+
204+
const etx_imu_driver_t imu_icm42627_driver = {
205+
gyro42627Init,
206+
gyro42627Read,
207+
"ICM42627",
208+
};

radio/src/drivers/icm42627.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright (C) EdgeTX
3+
*
4+
* Based on code named
5+
* opentx - https://github.com/opentx/opentx
6+
* th9x - http://code.google.com/p/th9x
7+
* er9x - http://code.google.com/p/er9x
8+
* gruvin9x - http://code.google.com/p/gruvin9x
9+
*
10+
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11+
*
12+
* This program is free software; you can redistribute it and/or modify
13+
* it under the terms of the GNU General Public License version 2 as
14+
* published by the Free Software Foundation.
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU General Public License for more details.
20+
*/
21+
22+
#pragma once
23+
24+
#include "hal/imu.h"
25+
26+
#define ICM42627_WHO_AM_I_REG 0x75
27+
#define ICM42627_WHO_AM_I 0x20
28+
29+
#define ICM42627_DEVICE_CONFIG_REG 0x11
30+
#define ICM42627_PWR_MGMT0_REG 0x4E
31+
#define ICM42627_GYRO_CONFIG0_REG 0x4F
32+
#define ICM42627_ACCEL_CONFIG0_REG 0x50
33+
#define ICM42627_GYRO_CONFIG1_REG 0x51
34+
#define ICM42627_ACCEL_GYRO_BW_REG 0x52
35+
#define ICM42627_ACCEL_CONFIG1_REG 0x53
36+
#define ICM42627_BANK_SEL_REG 0x76
37+
38+
#define ICM42627_GYRO_STATIC2_REG 0x0B
39+
#define ICM42627_DATA_REG 0x1D
40+
41+
#define ICM42627_BANK0 0x00
42+
#define ICM42627_BANK1 0x01
43+
44+
#define ICM42627_RESET 0x01
45+
#define ICM42627_PWR_STAGE1 0x0F
46+
#define ICM42627_PWR_STAGE2 0x2F
47+
#define ICM42627_GYRO_CONFIG 0x07
48+
#define ICM42627_ACCEL_CONFIG 0x47
49+
#define ICM42627_GYRO_FILTER 0x0A
50+
#define ICM42627_ACCEL_GYRO_BW 0x22
51+
#define ICM42627_ACCEL_FILTER 0x14
52+
#define ICM42627_GYRO_STATIC2 0x00
53+
54+
extern const etx_imu_driver_t imu_icm42627_driver;

radio/src/targets/horus/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ elseif (PCB STREQUAL X12S)
147147
add_definitions(-DMANUFACTURER_FRSKY)
148148
endif()
149149

150-
# enable GPS support if there is AUX port available unless otherwise disabled
150+
# enable GPS support if there is AUX port available unless otherwise disabled
151151
if(AUX_SERIAL)
152152
option(INTERNAL_GPS "Support for internal GPS" ON)
153153
set(INTERNAL_GPS_BAUDRATE "9600" CACHE STRING "Baud rate for internal GPS")
@@ -284,6 +284,7 @@ add_library(board OBJECT EXCLUDE_FROM_ALL
284284
targets/common/arm/stm32/delays_driver.cpp
285285
targets/common/arm/stm32/heartbeat_driver.cpp
286286
drivers/lsm6ds.cpp
287+
drivers/icm42627.cpp
287288
targets/common/arm/stm32/mixer_scheduler_driver.cpp
288289
targets/common/arm/stm32/module_timer_driver.cpp
289290
targets/common/arm/stm32/sticks_pwm_driver.cpp

radio/src/targets/horus/board.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,23 @@ void audioInit()
133133
#endif
134134

135135
#if defined(HAS_IMU)
136-
#include "drivers/lsm6ds.h"
136+
#include "gyro.h"
137137
#include "stm32_i2c_driver.h"
138+
#include "drivers/icm42627.h"
139+
#include "drivers/lsm6ds.h"
138140

139141
static void gyroInit()
140142
{
143+
#if defined(RADIO_V16)
144+
const etx_imu_driver_t *driver = &imu_icm42627_driver;
145+
#else
146+
const etx_imu_driver_t *driver = &imu_lsm6ds_driver;
147+
#endif
148+
141149
const etx_imu_t candidates[] = {
142-
{ &imu_lsm6ds_driver, IMU_I2C_BUS, IMU_I2C_ADDRESS },
150+
{ driver, IMU_I2C_BUS, IMU_I2C_ADDRESS },
143151
};
152+
144153
gyroStart(imuDetect(candidates, DIM(candidates)));
145154
}
146155
#endif

radio/src/targets/horus/hal.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
#define DEFAULT_6POS_CALIB {3, 12, 21, 30, 38}
9191
#define DEFAULT_6POS_IDX 5
9292
#endif
93-
93+
9494
// Power
9595
#if defined(RADIO_T18)
9696
#define PWR_ON_GPIO GPIO_PIN(GPIOJ, 1) // PJ.01
@@ -355,7 +355,7 @@
355355
#define STORAGE_USE_SDIO // Use SD card for storage with SDIO driver
356356
//#define STORAGE_USE_SPI_FLASH // Use SPI flash for storage instead of SD card
357357

358-
// SPI NOR Flash
358+
// SPI NOR Flash
359359
#if defined(PCBX12S) && PCBREV >= 13
360360
#define FLASH_SPI SPI1
361361
#define FLASH_SPI_CS_GPIO GPIO_PIN(GPIOA, 15) // PA.15
@@ -374,7 +374,7 @@
374374
// #define FLASH_SPI_TX_DMA_IRQHandler DMA2_Stream3_IRQHandler
375375
// #define FLASH_SPI_TX_DMA_FLAG_TC DMA_IT_TCIF3
376376
// #define FLASH_SPI_TX_DMA_STATUS_REG HISR
377-
// SPI1_RX: DMA2 Stream 0 / Stream 2
377+
// SPI1_RX: DMA2 Stream 0 / Stream 2
378378
// #define FLASH_SPI_RX_DMA_CHANNEL DMA_Channel_3
379379
// #define FLASH_SPI_RX_DMA_STREAM DMA2_Stream5
380380
// #define FLASH_SPI_RX_DMA_IRQn DMA2_Stream5_IRQn
@@ -491,6 +491,9 @@
491491
#if defined(PCBX12S)
492492
#define IMU_I2C_BUS I2C_Bus_1
493493
#define IMU_I2C_ADDRESS 0x6A
494+
#elif defined(RADIO_V16)
495+
#define IMU_I2C_BUS I2C_Bus_1
496+
#define IMU_I2C_ADDRESS 0x69
494497
#elif !defined(AUX_SERIAL) && defined(IMU_LSM6DS33)
495498
#define IMU_I2C_BUS I2C_Bus_2
496499
#define IMU_I2C_ADDRESS 0x6A

0 commit comments

Comments
 (0)