Removed excess trailing spaces before new lines on licenses.
[betaflight.git] / src / main / drivers / accgyro / accgyro_mpu.c
bloba9030e1f11fe7ebd5705df6634e587f6f9dcc736
1 /*
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)
8 * any later version.
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include "platform.h"
28 #include "build/atomic.h"
29 #include "build/build_config.h"
30 #include "build/debug.h"
32 #include "common/maths.h"
33 #include "common/utils.h"
35 #include "drivers/bus.h"
36 #include "drivers/bus_i2c.h"
37 #include "drivers/bus_spi.h"
38 #include "drivers/exti.h"
39 #include "drivers/io.h"
40 #include "drivers/nvic.h"
41 #include "drivers/sensor.h"
42 #include "drivers/system.h"
43 #include "drivers/time.h"
45 #include "drivers/accgyro/accgyro.h"
46 #include "drivers/accgyro/accgyro_mpu3050.h"
47 #include "drivers/accgyro/accgyro_mpu6050.h"
48 #include "drivers/accgyro/accgyro_mpu6500.h"
49 #include "drivers/accgyro/accgyro_spi_bmi160.h"
50 #include "drivers/accgyro/accgyro_spi_icm20649.h"
51 #include "drivers/accgyro/accgyro_spi_icm20689.h"
52 #include "drivers/accgyro/accgyro_spi_mpu6000.h"
53 #include "drivers/accgyro/accgyro_spi_mpu6500.h"
54 #include "drivers/accgyro/accgyro_spi_mpu9250.h"
55 #include "drivers/accgyro/accgyro_mpu.h"
58 mpuResetFnPtr mpuResetFn;
60 #ifndef MPU_I2C_INSTANCE
61 #define MPU_I2C_INSTANCE I2C_DEVICE
62 #endif
64 #ifndef MPU_ADDRESS
65 #define MPU_ADDRESS 0x68
66 #endif
68 #define MPU_INQUIRY_MASK 0x7E
70 #ifdef USE_I2C
71 static void mpu6050FindRevision(gyroDev_t *gyro)
73 // There is a map of revision contained in the android source tree which is quite comprehensive and may help to understand this code
74 // See https://android.googlesource.com/kernel/msm.git/+/eaf36994a3992b8f918c18e4f7411e8b2320a35f/drivers/misc/mpu6050/mldl_cfg.c
76 // determine product ID and revision
77 uint8_t readBuffer[6];
78 bool ack = busReadRegisterBuffer(&gyro->bus, MPU_RA_XA_OFFS_H, readBuffer, 6);
79 uint8_t revision = ((readBuffer[5] & 0x01) << 2) | ((readBuffer[3] & 0x01) << 1) | (readBuffer[1] & 0x01);
80 if (ack && revision) {
81 // Congrats, these parts are better
82 if (revision == 1) {
83 gyro->mpuDetectionResult.resolution = MPU_HALF_RESOLUTION;
84 } else if (revision == 2) {
85 gyro->mpuDetectionResult.resolution = MPU_FULL_RESOLUTION;
86 } else if ((revision == 3) || (revision == 7)) {
87 gyro->mpuDetectionResult.resolution = MPU_FULL_RESOLUTION;
88 } else {
89 failureMode(FAILURE_ACC_INCOMPATIBLE);
91 } else {
92 uint8_t productId;
93 ack = busReadRegisterBuffer(&gyro->bus, MPU_RA_PRODUCT_ID, &productId, 1);
94 revision = productId & 0x0F;
95 if (!ack || revision == 0) {
96 failureMode(FAILURE_ACC_INCOMPATIBLE);
97 } else if (revision == 4) {
98 gyro->mpuDetectionResult.resolution = MPU_HALF_RESOLUTION;
99 } else {
100 gyro->mpuDetectionResult.resolution = MPU_FULL_RESOLUTION;
104 #endif
107 * Gyro interrupt service routine
109 #if defined(MPU_INT_EXTI)
110 static void mpuIntExtiHandler(extiCallbackRec_t *cb)
112 #ifdef DEBUG_MPU_DATA_READY_INTERRUPT
113 static uint32_t lastCalledAtUs = 0;
114 const uint32_t nowUs = micros();
115 debug[0] = (uint16_t)(nowUs - lastCalledAtUs);
116 lastCalledAtUs = nowUs;
117 #endif
118 gyroDev_t *gyro = container_of(cb, gyroDev_t, exti);
119 gyro->dataReady = true;
120 #ifdef DEBUG_MPU_DATA_READY_INTERRUPT
121 const uint32_t now2Us = micros();
122 debug[1] = (uint16_t)(now2Us - nowUs);
123 #endif
126 static void mpuIntExtiInit(gyroDev_t *gyro)
128 if (gyro->mpuIntExtiTag == IO_TAG_NONE) {
129 return;
132 const IO_t mpuIntIO = IOGetByTag(gyro->mpuIntExtiTag);
134 #ifdef ENSURE_MPU_DATA_READY_IS_LOW
135 uint8_t status = IORead(mpuIntIO);
136 if (status) {
137 return;
139 #endif
141 #if defined (STM32F7)
142 IOInit(mpuIntIO, OWNER_MPU_EXTI, 0);
143 EXTIHandlerInit(&gyro->exti, mpuIntExtiHandler);
144 EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EXTI, IO_CONFIG(GPIO_MODE_INPUT,0,GPIO_NOPULL)); // TODO - maybe pullup / pulldown ?
145 #else
146 IOInit(mpuIntIO, OWNER_MPU_EXTI, 0);
147 IOConfigGPIO(mpuIntIO, IOCFG_IN_FLOATING); // TODO - maybe pullup / pulldown ?
149 EXTIHandlerInit(&gyro->exti, mpuIntExtiHandler);
150 EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EXTI, EXTI_Trigger_Rising);
151 #endif
152 EXTIEnable(mpuIntIO, true);
154 #endif // MPU_INT_EXTI
156 bool mpuAccRead(accDev_t *acc)
158 uint8_t data[6];
160 const bool ack = busReadRegisterBuffer(&acc->bus, MPU_RA_ACCEL_XOUT_H, data, 6);
161 if (!ack) {
162 return false;
165 acc->ADCRaw[X] = (int16_t)((data[0] << 8) | data[1]);
166 acc->ADCRaw[Y] = (int16_t)((data[2] << 8) | data[3]);
167 acc->ADCRaw[Z] = (int16_t)((data[4] << 8) | data[5]);
169 return true;
172 bool mpuGyroRead(gyroDev_t *gyro)
174 uint8_t data[6];
176 const bool ack = busReadRegisterBuffer(&gyro->bus, MPU_RA_GYRO_XOUT_H, data, 6);
177 if (!ack) {
178 return false;
181 gyro->gyroADCRaw[X] = (int16_t)((data[0] << 8) | data[1]);
182 gyro->gyroADCRaw[Y] = (int16_t)((data[2] << 8) | data[3]);
183 gyro->gyroADCRaw[Z] = (int16_t)((data[4] << 8) | data[5]);
185 return true;
188 bool mpuGyroReadSPI(gyroDev_t *gyro)
190 static const uint8_t dataToSend[7] = {MPU_RA_GYRO_XOUT_H | 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
191 uint8_t data[7];
193 const bool ack = spiBusTransfer(&gyro->bus, dataToSend, data, 7);
194 if (!ack) {
195 return false;
198 gyro->gyroADCRaw[X] = (int16_t)((data[1] << 8) | data[2]);
199 gyro->gyroADCRaw[Y] = (int16_t)((data[3] << 8) | data[4]);
200 gyro->gyroADCRaw[Z] = (int16_t)((data[5] << 8) | data[6]);
202 return true;
205 #ifdef USE_SPI
206 static bool detectSPISensorsAndUpdateDetectionResult(gyroDev_t *gyro)
208 UNUSED(gyro); // since there are FCs which have gyro on I2C but other devices on SPI
210 uint8_t sensor = MPU_NONE;
211 UNUSED(sensor);
213 // note, when USE_DUAL_GYRO is enabled the gyro->bus must already be initialised.
215 #ifdef USE_GYRO_SPI_MPU6000
216 #ifndef USE_DUAL_GYRO
217 spiBusSetInstance(&gyro->bus, MPU6000_SPI_INSTANCE);
218 #endif
219 #ifdef MPU6000_CS_PIN
220 gyro->bus.busdev_u.spi.csnPin = gyro->bus.busdev_u.spi.csnPin == IO_NONE ? IOGetByTag(IO_TAG(MPU6000_CS_PIN)) : gyro->bus.busdev_u.spi.csnPin;
221 #endif
222 sensor = mpu6000SpiDetect(&gyro->bus);
223 if (sensor != MPU_NONE) {
224 gyro->mpuDetectionResult.sensor = sensor;
225 return true;
227 #endif
229 #ifdef USE_GYRO_SPI_MPU6500
230 #ifndef USE_DUAL_GYRO
231 spiBusSetInstance(&gyro->bus, MPU6500_SPI_INSTANCE);
232 #endif
233 #ifdef MPU6500_CS_PIN
234 gyro->bus.busdev_u.spi.csnPin = gyro->bus.busdev_u.spi.csnPin == IO_NONE ? IOGetByTag(IO_TAG(MPU6500_CS_PIN)) : gyro->bus.busdev_u.spi.csnPin;
235 #endif
236 sensor = mpu6500SpiDetect(&gyro->bus);
237 // some targets using MPU_9250_SPI, ICM_20608_SPI or ICM_20602_SPI state sensor is MPU_65xx_SPI
238 if (sensor != MPU_NONE) {
239 gyro->mpuDetectionResult.sensor = sensor;
240 return true;
242 #endif
244 #ifdef USE_GYRO_SPI_MPU9250
245 #ifndef USE_DUAL_GYRO
246 spiBusSetInstance(&gyro->bus, MPU9250_SPI_INSTANCE);
247 #endif
248 #ifdef MPU9250_CS_PIN
249 gyro->bus.busdev_u.spi.csnPin = gyro->bus.busdev_u.spi.csnPin == IO_NONE ? IOGetByTag(IO_TAG(MPU9250_CS_PIN)) : gyro->bus.busdev_u.spi.csnPin;
250 #endif
251 sensor = mpu9250SpiDetect(&gyro->bus);
252 if (sensor != MPU_NONE) {
253 gyro->mpuDetectionResult.sensor = sensor;
254 gyro->mpuConfiguration.resetFn = mpu9250SpiResetGyro;
255 return true;
257 #endif
259 #ifdef USE_GYRO_SPI_ICM20649
260 #ifdef ICM20649_SPI_INSTANCE
261 spiBusSetInstance(&gyro->bus, ICM20649_SPI_INSTANCE);
262 #endif
263 #ifdef ICM20649_CS_PIN
264 gyro->bus.busdev_u.spi.csnPin = gyro->bus.busdev_u.spi.csnPin == IO_NONE ? IOGetByTag(IO_TAG(ICM20649_CS_PIN)) : gyro->bus.busdev_u.spi.csnPin;
265 #endif
266 sensor = icm20649SpiDetect(&gyro->bus);
267 if (sensor != MPU_NONE) {
268 gyro->mpuDetectionResult.sensor = sensor;
269 return true;
271 #endif
273 #ifdef USE_GYRO_SPI_ICM20689
274 #ifndef USE_DUAL_GYRO
275 spiBusSetInstance(&gyro->bus, ICM20689_SPI_INSTANCE);
276 #endif
277 #ifdef ICM20689_CS_PIN
278 gyro->bus.busdev_u.spi.csnPin = gyro->bus.busdev_u.spi.csnPin == IO_NONE ? IOGetByTag(IO_TAG(ICM20689_CS_PIN)) : gyro->bus.busdev_u.spi.csnPin;
279 #endif
280 sensor = icm20689SpiDetect(&gyro->bus);
281 // icm20689SpiDetect detects ICM20602 and ICM20689
282 if (sensor != MPU_NONE) {
283 gyro->mpuDetectionResult.sensor = sensor;
284 return true;
286 #endif
288 #ifdef USE_ACCGYRO_BMI160
289 #ifndef USE_DUAL_GYRO
290 spiBusSetInstance(&gyro->bus, BMI160_SPI_INSTANCE);
291 #endif
292 #ifdef BMI160_CS_PIN
293 gyro->bus.busdev_u.spi.csnPin = gyro->bus.busdev_u.spi.csnPin == IO_NONE ? IOGetByTag(IO_TAG(BMI160_CS_PIN)) : gyro->bus.busdev_u.spi.csnPin;
294 #endif
295 sensor = bmi160Detect(&gyro->bus);
296 if (sensor != MPU_NONE) {
297 gyro->mpuDetectionResult.sensor = sensor;
298 return true;
300 #endif
302 return false;
304 #endif
306 void mpuDetect(gyroDev_t *gyro)
308 // MPU datasheet specifies 30ms.
309 delay(35);
311 #ifdef USE_I2C
312 if (gyro->bus.bustype == BUSTYPE_NONE) {
313 // if no bustype is selected try I2C first.
314 gyro->bus.bustype = BUSTYPE_I2C;
317 if (gyro->bus.bustype == BUSTYPE_I2C) {
318 gyro->bus.busdev_u.i2c.device = MPU_I2C_INSTANCE;
319 gyro->bus.busdev_u.i2c.address = MPU_ADDRESS;
321 uint8_t sig = 0;
322 bool ack = busReadRegisterBuffer(&gyro->bus, MPU_RA_WHO_AM_I, &sig, 1);
324 if (ack) {
325 // If an MPU3050 is connected sig will contain 0.
326 uint8_t inquiryResult;
327 ack = busReadRegisterBuffer(&gyro->bus, MPU_RA_WHO_AM_I_LEGACY, &inquiryResult, 1);
328 inquiryResult &= MPU_INQUIRY_MASK;
329 if (ack && inquiryResult == MPUx0x0_WHO_AM_I_CONST) {
330 gyro->mpuDetectionResult.sensor = MPU_3050;
331 return;
334 sig &= MPU_INQUIRY_MASK;
335 if (sig == MPUx0x0_WHO_AM_I_CONST) {
336 gyro->mpuDetectionResult.sensor = MPU_60x0;
337 mpu6050FindRevision(gyro);
338 } else if (sig == MPU6500_WHO_AM_I_CONST) {
339 gyro->mpuDetectionResult.sensor = MPU_65xx_I2C;
341 return;
344 #endif
346 #ifdef USE_SPI
347 gyro->bus.bustype = BUSTYPE_SPI;
348 detectSPISensorsAndUpdateDetectionResult(gyro);
349 #endif
352 void mpuGyroInit(gyroDev_t *gyro)
354 #ifdef MPU_INT_EXTI
355 mpuIntExtiInit(gyro);
356 #else
357 UNUSED(gyro);
358 #endif
361 uint8_t mpuGyroDLPF(gyroDev_t *gyro)
363 uint8_t ret;
364 if (gyro->gyroRateKHz > GYRO_RATE_8_kHz) {
365 ret = 0; // If gyro is in 32KHz mode then the DLPF bits aren't used - set to 0
366 } else {
367 switch (gyro->hardware_lpf) {
368 case GYRO_HARDWARE_LPF_NORMAL:
369 ret = 0;
370 break;
371 case GYRO_HARDWARE_LPF_EXPERIMENTAL:
372 ret = 7;
373 break;
374 case GYRO_HARDWARE_LPF_1KHZ_SAMPLE:
375 ret = 1;
376 break;
377 default:
378 ret = 0;
379 break;
382 return ret;
385 uint8_t mpuGyroFCHOICE(gyroDev_t *gyro)
387 if (gyro->gyroRateKHz > GYRO_RATE_8_kHz) {
388 if (gyro->hardware_32khz_lpf == GYRO_32KHZ_HARDWARE_LPF_EXPERIMENTAL) {
389 return FCB_8800_32;
390 } else {
391 return FCB_3600_32;
393 } else {
394 return FCB_DISABLED; // Not in 32KHz mode, set FCHOICE to select 8KHz sampling
398 #ifdef USE_GYRO_REGISTER_DUMP
399 uint8_t mpuGyroReadRegister(const busDevice_t *bus, uint8_t reg)
401 uint8_t data;
402 const bool ack = busReadRegisterBuffer(bus, reg, &data, 1);
403 if (ack) {
404 return data;
405 } else {
406 return 0;
410 #endif