2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
26 #if defined(USE_IMU_BMI270)
28 #include "build/debug.h"
30 #include "common/axis.h"
31 #include "common/maths.h"
32 #include "common/utils.h"
34 #include "drivers/system.h"
35 #include "drivers/time.h"
36 #include "drivers/io.h"
37 #include "drivers/bus.h"
39 #include "drivers/sensor.h"
40 #include "drivers/accgyro/accgyro.h"
41 #include "drivers/accgyro/accgyro_bmi270.h"
43 #define BMI270_CONFIG_SIZE 328
45 // Declaration for the device config (microcode) that must be uploaded to the sensor
46 extern const uint8_t bmi270_maximum_fifo_config_file
[BMI270_CONFIG_SIZE
];
48 // BMI270 registers (not the complete list)
50 BMI270_REG_CHIP_ID
= 0x00,
51 BMI270_REG_ERR_REG
= 0x02,
52 BMI270_REG_STATUS
= 0x03,
53 BMI270_REG_ACC_DATA_X_LSB
= 0x0C,
54 BMI270_REG_GYR_DATA_X_LSB
= 0x12,
55 BMI270_REG_SENSORTIME_0
= 0x18,
56 BMI270_REG_SENSORTIME_1
= 0x19,
57 BMI270_REG_SENSORTIME_2
= 0x1A,
58 BMI270_REG_EVENT
= 0x1B,
59 BMI270_REG_INT_STATUS_0
= 0x1C,
60 BMI270_REG_INT_STATUS_1
= 0x1D,
61 BMI270_REG_INTERNAL_STATUS
= 0x21,
62 BMI270_REG_TEMPERATURE_LSB
= 0x22,
63 BMI270_REG_TEMPERATURE_MSB
= 0x23,
64 BMI270_REG_FIFO_LENGTH_LSB
= 0x24,
65 BMI270_REG_FIFO_LENGTH_MSB
= 0x25,
66 BMI270_REG_FIFO_DATA
= 0x26,
67 BMI270_REG_ACC_CONF
= 0x40,
68 BMI270_REG_ACC_RANGE
= 0x41,
69 BMI270_REG_GYRO_CONF
= 0x42,
70 BMI270_REG_GYRO_RANGE
= 0x43,
71 BMI270_REG_AUX_CONF
= 0x44,
72 BMI270_REG_FIFO_DOWNS
= 0x45,
73 BMI270_REG_FIFO_WTM_0
= 0x46,
74 BMI270_REG_FIFO_WTM_1
= 0x47,
75 BMI270_REG_FIFO_CONFIG_0
= 0x48,
76 BMI270_REG_FIFO_CONFIG_1
= 0x49,
77 BMI270_REG_SATURATION
= 0x4A,
78 BMI270_REG_INT1_IO_CTRL
= 0x53,
79 BMI270_REG_INT2_IO_CTRL
= 0x54,
80 BMI270_REG_INT_LATCH
= 0x55,
81 BMI270_REG_INT1_MAP_FEAT
= 0x56,
82 BMI270_REG_INT2_MAP_FEAT
= 0x57,
83 BMI270_REG_INT_MAP_DATA
= 0x58,
84 BMI270_REG_INIT_CTRL
= 0x59,
85 BMI270_REG_INIT_DATA
= 0x5E,
86 BMI270_REG_ACC_SELF_TEST
= 0x6D,
87 BMI270_REG_GYR_SELF_TEST_AXES
= 0x6E,
88 BMI270_REG_PWR_CONF
= 0x7C,
89 BMI270_REG_PWR_CTRL
= 0x7D,
90 BMI270_REG_CMD
= 0x7E,
93 #define BMI270_CHIP_ID 0x24
95 #define BMI270_CMD_SOFTRESET 0xB6
97 #define BMI270_PWR_CONF_HP 0x00
98 #define BMI270_PWR_CTRL_GYR_EN 0x02
99 #define BMI270_PWR_CTRL_ACC_EN 0x04
100 #define BMI270_PWR_CTRL_TEMP_EN 0x08
102 #define BMI270_ACC_CONF_HP 0x80
103 #define BMI270_ACC_RANGE_8G 0x02
104 #define BMI270_ACC_RANGE_16G 0x03
106 #define BMI270_GYRO_CONF_NOISE_PERF 0x40
107 #define BMI270_GYRO_CONF_FILTER_PERF 0x80
108 #define BMI270_GYRO_RANGE_2000DPS 0x08
110 #define BMI270_INT_MAP_DATA_DRDY_INT1 0x04
111 #define BMI270_INT1_IO_CTRL_ACTIVE_HIGH 0x02
112 #define BMI270_INT1_IO_CTRL_OUTPUT_EN 0x08
114 #define BMI270_ODR_400 0x0A
115 #define BMI270_ODR_800 0x0B
116 #define BMI270_ODR_1600 0x0C
117 #define BMI270_ODR_3200 0x0D
119 #define BMI270_BWP_OSR4 0x00
120 #define BMI270_BWP_OSR2 0x10
121 #define BMI270_BWP_NORM 0x20
123 typedef struct __attribute__ ((__packed__
)) bmi270ContextData_s
{
124 uint16_t chipMagicNumber
;
125 uint8_t lastReadStatus
;
126 uint8_t __padding_dummy
;
129 } bmi270ContextData_t
;
131 STATIC_ASSERT(sizeof(bmi270ContextData_t
) < BUS_SCRATCHPAD_MEMORY_SIZE
, busDevice_scratchpad_memory_too_small
);
133 static const gyroFilterAndRateConfig_t gyroConfigs
[] = {
134 { GYRO_LPF_256HZ
, 3200, { BMI270_BWP_OSR4
| BMI270_ODR_3200
} },
135 { GYRO_LPF_256HZ
, 1600, { BMI270_BWP_OSR2
| BMI270_ODR_1600
} },
136 { GYRO_LPF_256HZ
, 800, { BMI270_BWP_NORM
| BMI270_ODR_800
} },
139 // Toggle the CS to switch the device into SPI mode.
140 // Device switches initializes as I2C and switches to SPI on a low to high CS transition
141 static void bmi270EnableSPI(busDevice_t
*dev
)
143 IOLo(dev
->busdev
.spi
.csnPin
);
145 IOHi(dev
->busdev
.spi
.csnPin
);
150 static bool bmi270DeviceDetect(busDevice_t
* busDev
)
154 busSetSpeed(busDev
, BUS_SPEED_INITIALIZATION
);
155 bmi270EnableSPI(busDev
);
157 busReadBuf(busDev
, BMI270_REG_CHIP_ID
, &id
[0], 2);
158 if (id
[1] == BMI270_CHIP_ID
) {
165 static void bmi270UploadConfig(busDevice_t
* busDev
)
167 busWrite(busDev
, BMI270_REG_PWR_CONF
, 0);
169 busWrite(busDev
, BMI270_REG_INIT_CTRL
, 0);
172 // Transfer the config file
173 uint8_t reg
= BMI270_REG_INIT_DATA
;
174 busTransferDescriptor_t tfDesc
[] = {
175 {.rxBuf
= NULL
, .txBuf
=®
, .length
=1},
176 {.rxBuf
= NULL
, .txBuf
=(uint8_t *)bmi270_maximum_fifo_config_file
, .length
=sizeof(bmi270_maximum_fifo_config_file
)}
179 spiBusTransferMultiple(busDev
, tfDesc
, 2);
182 busWrite(busDev
, BMI270_REG_INIT_CTRL
, 1);
186 static void bmi270AccAndGyroInit(gyroDev_t
*gyro
)
188 busDevice_t
* busDev
= gyro
->busDev
;
190 // Perform a soft reset to set all configuration to default
191 // Delay 100ms before continuing configuration
192 busWrite(busDev
, BMI270_REG_CMD
, BMI270_CMD_SOFTRESET
);
195 // Use standard bus speed
196 busSetSpeed(busDev
, BUS_SPEED_STANDARD
);
198 // Toggle the chip into SPI mode
199 bmi270EnableSPI(busDev
);
201 bmi270UploadConfig(busDev
);
203 // Configure the accelerometer
204 busWrite(busDev
, BMI270_REG_ACC_CONF
, BMI270_ODR_1600
| BMI270_BWP_OSR4
| BMI270_ACC_CONF_HP
);
207 // Configure the accelerometer full-scale range
208 busWrite(busDev
, BMI270_REG_ACC_RANGE
, BMI270_ACC_RANGE_16G
);
211 // Configure the gyro
212 // Figure out suitable filter configuration
213 const gyroFilterAndRateConfig_t
* config
= chooseGyroConfig(gyro
->lpf
, 1000000 / gyro
->requestedSampleIntervalUs
, &gyroConfigs
[0], ARRAYLEN(gyroConfigs
));
215 gyro
->sampleRateIntervalUs
= 1000000 / config
->gyroRateHz
;
217 busWrite(busDev
, BMI270_REG_GYRO_CONF
, config
->gyroConfigValues
[0] | BMI270_GYRO_CONF_NOISE_PERF
| BMI270_GYRO_CONF_FILTER_PERF
);
220 // Configure the gyro full-range scale
221 busWrite(busDev
, BMI270_REG_GYRO_RANGE
, BMI270_GYRO_RANGE_2000DPS
);
224 // Configure the gyro data ready interrupt
225 busWrite(busDev
, BMI270_REG_INT_MAP_DATA
, BMI270_INT_MAP_DATA_DRDY_INT1
);
228 // Configure the behavior of the INT1 pin
229 busWrite(busDev
, BMI270_REG_INT1_IO_CTRL
, BMI270_INT1_IO_CTRL_ACTIVE_HIGH
| BMI270_INT1_IO_CTRL_OUTPUT_EN
);
232 // Configure the device for performance mode
233 busWrite(busDev
, BMI270_REG_PWR_CONF
, BMI270_PWR_CONF_HP
);
236 // Enable the gyro and accelerometer
237 busWrite(busDev
, BMI270_REG_PWR_CTRL
, BMI270_PWR_CTRL_GYR_EN
| BMI270_PWR_CTRL_ACC_EN
);
242 static bool bmi270yroReadScratchpad(gyroDev_t
*gyro
)
244 bmi270ContextData_t
* ctx
= busDeviceGetScratchpadMemory(gyro
->busDev
);
245 ctx
->lastReadStatus
= busReadBuf(gyro
->busDev
, BMI270_REG_ACC_DATA_X_LSB
, &ctx
->__padding_dummy
, 6 + 6 + 1);
247 if (ctx
->lastReadStatus
) {
248 gyro
->gyroADCRaw
[X
] = (float) int16_val_little_endian(ctx
->gyroRaw
, 0);
249 gyro
->gyroADCRaw
[Y
] = (float) int16_val_little_endian(ctx
->gyroRaw
, 1);
250 gyro
->gyroADCRaw
[Z
] = (float) int16_val_little_endian(ctx
->gyroRaw
, 2);
258 static bool bmi270AccReadScratchpad(accDev_t
*acc
)
260 bmi270ContextData_t
* ctx
= busDeviceGetScratchpadMemory(acc
->busDev
);
262 if (ctx
->lastReadStatus
) {
263 acc
->ADCRaw
[X
] = (float) int16_val_little_endian(ctx
->accRaw
, 0);
264 acc
->ADCRaw
[Y
] = (float) int16_val_little_endian(ctx
->accRaw
, 1);
265 acc
->ADCRaw
[Z
] = (float) int16_val_little_endian(ctx
->accRaw
, 2);
272 static bool bmi270TemperatureRead(gyroDev_t
*gyro
, int16_t * data
)
276 bool readStatus
= busReadBuf(gyro
->busDev
, BMI270_REG_TEMPERATURE_LSB
, &buffer
[0], sizeof(buffer
));
279 // Convert to degC*10: degC = raw / 512 + 23
280 *data
= 230 + ((10 * (int32_t)((int16_t)((buffer
[2] << 8) | buffer
[1]))) >> 9);
287 static void bmi270GyroInit(gyroDev_t
*gyro
)
289 bmi270AccAndGyroInit(gyro
);
292 static void bmi270AccInit(accDev_t
*acc
)
294 // sensor is configured during gyro init
295 acc
->acc_1G
= 2048; // 16G sensor scale
298 bool bmi270AccDetect(accDev_t
*acc
)
300 acc
->busDev
= busDeviceOpen(BUSTYPE_SPI
, DEVHW_BMI270
, acc
->imuSensorToUse
);
301 if (acc
->busDev
== NULL
) {
305 bmi270ContextData_t
* ctx
= busDeviceGetScratchpadMemory(acc
->busDev
);
306 if (ctx
->chipMagicNumber
!= 0xB270) {
310 acc
->initFn
= bmi270AccInit
;
311 acc
->readFn
= bmi270AccReadScratchpad
;
312 acc
->accAlign
= acc
->busDev
->param
;
318 bool bmi270GyroDetect(gyroDev_t
*gyro
)
320 gyro
->busDev
= busDeviceInit(BUSTYPE_SPI
, DEVHW_BMI270
, gyro
->imuSensorToUse
, OWNER_MPU
);
321 if (gyro
->busDev
== NULL
) {
325 if (!bmi270DeviceDetect(gyro
->busDev
)) {
326 busDeviceDeInit(gyro
->busDev
);
330 // Magic number for ACC detection to indicate that we have detected BMI270 gyro
331 bmi270ContextData_t
* ctx
= busDeviceGetScratchpadMemory(gyro
->busDev
);
332 ctx
->chipMagicNumber
= 0xB270;
334 gyro
->initFn
= bmi270GyroInit
;
335 gyro
->readFn
= bmi270yroReadScratchpad
;
336 gyro
->temperatureFn
= bmi270TemperatureRead
;
337 gyro
->intStatusFn
= gyroCheckDataReady
;
338 gyro
->scale
= 1.0f
/ 16.4f
; // 2000 dps
339 gyro
->gyroAlign
= gyro
->busDev
->param
;
342 #endif // USE_IMU_BMI270