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/>.
29 #include "build/debug.h"
31 #include "common/axis.h"
32 #include "common/maths.h"
33 #include "common/filter.h"
35 #include "config/feature.h"
38 #include "pg/pg_ids.h"
40 #include "drivers/accgyro/accgyro.h"
41 #include "drivers/accgyro/accgyro_fake.h"
42 #include "drivers/accgyro/accgyro_mpu.h"
43 #include "drivers/accgyro/accgyro_mpu3050.h"
44 #include "drivers/accgyro/accgyro_mpu6050.h"
45 #include "drivers/accgyro/accgyro_mpu6500.h"
46 #include "drivers/accgyro/accgyro_spi_bmi160.h"
47 #include "drivers/accgyro/accgyro_spi_icm20649.h"
48 #include "drivers/accgyro/accgyro_spi_icm20689.h"
49 #include "drivers/accgyro/accgyro_spi_mpu6000.h"
50 #include "drivers/accgyro/accgyro_spi_mpu6500.h"
51 #include "drivers/accgyro/accgyro_spi_mpu9250.h"
53 #ifdef USE_GYRO_L3G4200D
54 #include "drivers/accgyro_legacy/accgyro_l3g4200d.h"
57 #ifdef USE_GYRO_L3GD20
58 #include "drivers/accgyro_legacy/accgyro_l3gd20.h"
61 #include "drivers/accgyro/gyro_sync.h"
62 #include "drivers/bus_spi.h"
63 #include "drivers/io.h"
65 #include "fc/config.h"
66 #include "fc/runtime_config.h"
68 #include "io/beeper.h"
69 #include "io/statusindicator.h"
71 #include "scheduler/scheduler.h"
73 #include "sensors/boardalignment.h"
74 #include "sensors/gyro.h"
75 #ifdef USE_GYRO_DATA_ANALYSE
76 #include "sensors/gyroanalyse.h"
78 #include "sensors/sensors.h"
80 #ifdef USE_HARDWARE_REVISION_DETECTION
81 #include "hardware_revision.h"
84 #if ((FLASH_SIZE > 128) && (defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20689) || defined(USE_GYRO_SPI_MPU6500)))
85 #define USE_GYRO_SLEW_LIMITER
88 FAST_RAM_ZERO_INIT gyro_t gyro
;
89 static FAST_RAM_ZERO_INIT
uint8_t gyroDebugMode
;
91 static uint8_t gyroToUse
= 0;
93 #ifdef USE_GYRO_OVERFLOW_CHECK
94 static FAST_RAM_ZERO_INIT
uint8_t overflowAxisMask
;
96 static FAST_RAM_ZERO_INIT
float accumulatedMeasurements
[XYZ_AXIS_COUNT
];
97 static FAST_RAM_ZERO_INIT
float gyroPrevious
[XYZ_AXIS_COUNT
];
98 static FAST_RAM_ZERO_INIT timeUs_t accumulatedMeasurementTimeUs
;
99 static FAST_RAM_ZERO_INIT timeUs_t accumulationLastTimeSampledUs
;
101 static bool gyroHasOverflowProtection
= true;
103 typedef struct gyroCalibration_s
{
104 float sum
[XYZ_AXIS_COUNT
];
105 stdev_t var
[XYZ_AXIS_COUNT
];
106 int32_t cyclesRemaining
;
109 bool firstArmingCalibrationWasStarted
= false;
111 typedef union gyroLowpassFilter_u
{
112 pt1Filter_t pt1FilterState
;
113 biquadFilter_t biquadFilterState
;
114 } gyroLowpassFilter_t
;
116 typedef struct gyroSensor_s
{
118 gyroCalibration_t calibration
;
120 // lowpass gyro soft filter
121 filterApplyFnPtr lowpassFilterApplyFn
;
122 gyroLowpassFilter_t lowpassFilter
[XYZ_AXIS_COUNT
];
124 // lowpass2 gyro soft filter
125 filterApplyFnPtr lowpass2FilterApplyFn
;
126 gyroLowpassFilter_t lowpass2Filter
[XYZ_AXIS_COUNT
];
129 filterApplyFnPtr notchFilter1ApplyFn
;
130 biquadFilter_t notchFilter1
[XYZ_AXIS_COUNT
];
132 filterApplyFnPtr notchFilter2ApplyFn
;
133 biquadFilter_t notchFilter2
[XYZ_AXIS_COUNT
];
135 filterApplyFnPtr dynFilterApplyFn
;
136 gyroDynamicFilter_t dynFilter
[XYZ_AXIS_COUNT
];
138 // overflow and recovery
139 timeUs_t overflowTimeUs
;
140 bool overflowDetected
;
141 #ifdef USE_YAW_SPIN_RECOVERY
142 timeUs_t yawSpinTimeUs
;
143 bool yawSpinDetected
;
144 #endif // USE_YAW_SPIN_RECOVERY
146 #ifdef USE_GYRO_DATA_ANALYSE
147 #define DYNAMIC_LOWPASS_DEFAULT_CUTOFF_HZ 200
148 #define DYNAMIC_NOTCH_DEFAULT_CENTER_HZ 400
149 #define DYNAMIC_NOTCH_DEFAULT_CUTOFF_HZ 350
150 gyroAnalyseState_t gyroAnalyseState
;
155 STATIC_UNIT_TESTED FAST_RAM_ZERO_INIT gyroSensor_t gyroSensor1
;
157 STATIC_UNIT_TESTED FAST_RAM_ZERO_INIT gyroSensor_t gyroSensor2
;
161 STATIC_UNIT_TESTED gyroSensor_t
* const gyroSensorPtr
= &gyroSensor1
;
162 STATIC_UNIT_TESTED gyroDev_t
* const gyroDevPtr
= &gyroSensor1
.gyroDev
;
165 static void gyroInitSensorFilters(gyroSensor_t
*gyroSensor
);
166 static void gyroInitLowpassFilterLpf(gyroSensor_t
*gyroSensor
, int slot
, int type
, uint16_t lpfHz
);
168 #define DEBUG_GYRO_CALIBRATION 3
171 #define GYRO_SYNC_DENOM_DEFAULT 8
172 #elif defined(USE_GYRO_SPI_MPU6000) || defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) \
173 || defined(USE_GYRO_SPI_ICM20689)
174 #define GYRO_SYNC_DENOM_DEFAULT 1
176 #define GYRO_SYNC_DENOM_DEFAULT 3
179 #define GYRO_OVERFLOW_TRIGGER_THRESHOLD 31980 // 97.5% full scale (1950dps for 2000dps gyro)
180 #define GYRO_OVERFLOW_RESET_THRESHOLD 30340 // 92.5% full scale (1850dps for 2000dps gyro)
182 PG_REGISTER_WITH_RESET_TEMPLATE(gyroConfig_t
, gyroConfig
, PG_GYRO_CONFIG
, 4);
184 #ifndef GYRO_CONFIG_USE_GYRO_DEFAULT
185 #define GYRO_CONFIG_USE_GYRO_DEFAULT GYRO_CONFIG_USE_GYRO_1
188 PG_RESET_TEMPLATE(gyroConfig_t
, gyroConfig
,
189 .gyro_align
= ALIGN_DEFAULT
,
190 .gyroCalibrationDuration
= 125, // 1.25 seconds
191 .gyroMovementCalibrationThreshold
= 48,
192 .gyro_sync_denom
= GYRO_SYNC_DENOM_DEFAULT
,
193 .gyro_hardware_lpf
= GYRO_HARDWARE_LPF_NORMAL
,
194 .gyro_32khz_hardware_lpf
= GYRO_32KHZ_HARDWARE_LPF_NORMAL
,
195 .gyro_lowpass_type
= FILTER_PT1
,
196 .gyro_lowpass_hz
= 100,
197 .gyro_lowpass2_type
= FILTER_PT1
,
198 .gyro_lowpass2_hz
= 300,
199 .gyro_high_fsr
= false,
200 .gyro_use_32khz
= false,
201 .gyro_to_use
= GYRO_CONFIG_USE_GYRO_DEFAULT
,
202 .gyro_soft_notch_hz_1
= 0,
203 .gyro_soft_notch_cutoff_1
= 0,
204 .gyro_soft_notch_hz_2
= 0,
205 .gyro_soft_notch_cutoff_2
= 0,
206 .checkOverflow
= GYRO_OVERFLOW_CHECK_ALL_AXES
,
207 .gyro_offset_yaw
= 0,
208 .yaw_spin_recovery
= true,
209 .yaw_spin_threshold
= 1950,
210 .dyn_filter_type
= FILTER_BIQUAD
,
211 .dyn_filter_width_percent
= 40,
212 .dyn_fft_location
= DYN_FFT_AFTER_STATIC_FILTERS
,
213 .dyn_filter_range
= DYN_FILTER_RANGE_MEDIUM
,
217 const busDevice_t
*gyroSensorBus(void)
220 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
221 return &gyroSensor2
.gyroDev
.bus
;
223 return &gyroSensor1
.gyroDev
.bus
;
226 return &gyroSensor1
.gyroDev
.bus
;
230 #ifdef USE_GYRO_REGISTER_DUMP
231 const busDevice_t
*gyroSensorBusByDevice(uint8_t whichSensor
)
234 if (whichSensor
== GYRO_CONFIG_USE_GYRO_2
) {
235 return &gyroSensor2
.gyroDev
.bus
;
237 return &gyroSensor1
.gyroDev
.bus
;
241 return &gyroSensor1
.gyroDev
.bus
;
244 #endif // USE_GYRO_REGISTER_DUMP
246 const mpuConfiguration_t
*gyroMpuConfiguration(void)
249 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
250 return &gyroSensor2
.gyroDev
.mpuConfiguration
;
252 return &gyroSensor1
.gyroDev
.mpuConfiguration
;
255 return &gyroSensor1
.gyroDev
.mpuConfiguration
;
259 const mpuDetectionResult_t
*gyroMpuDetectionResult(void)
262 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
263 return &gyroSensor2
.gyroDev
.mpuDetectionResult
;
265 return &gyroSensor1
.gyroDev
.mpuDetectionResult
;
268 return &gyroSensor1
.gyroDev
.mpuDetectionResult
;
272 STATIC_UNIT_TESTED gyroSensor_e
gyroDetect(gyroDev_t
*dev
)
274 gyroSensor_e gyroHardware
= GYRO_DEFAULT
;
276 switch (gyroHardware
) {
280 #ifdef USE_GYRO_MPU6050
282 if (mpu6050GyroDetect(dev
)) {
283 gyroHardware
= GYRO_MPU6050
;
284 #ifdef GYRO_MPU6050_ALIGN
285 dev
->gyroAlign
= GYRO_MPU6050_ALIGN
;
292 #ifdef USE_GYRO_L3G4200D
294 if (l3g4200dDetect(dev
)) {
295 gyroHardware
= GYRO_L3G4200D
;
296 #ifdef GYRO_L3G4200D_ALIGN
297 dev
->gyroAlign
= GYRO_L3G4200D_ALIGN
;
304 #ifdef USE_GYRO_MPU3050
306 if (mpu3050Detect(dev
)) {
307 gyroHardware
= GYRO_MPU3050
;
308 #ifdef GYRO_MPU3050_ALIGN
309 dev
->gyroAlign
= GYRO_MPU3050_ALIGN
;
316 #ifdef USE_GYRO_L3GD20
318 if (l3gd20Detect(dev
)) {
319 gyroHardware
= GYRO_L3GD20
;
320 #ifdef GYRO_L3GD20_ALIGN
321 dev
->gyroAlign
= GYRO_L3GD20_ALIGN
;
328 #ifdef USE_GYRO_SPI_MPU6000
330 if (mpu6000SpiGyroDetect(dev
)) {
331 gyroHardware
= GYRO_MPU6000
;
332 #ifdef GYRO_MPU6000_ALIGN
333 dev
->gyroAlign
= GYRO_MPU6000_ALIGN
;
340 #if defined(USE_GYRO_MPU6500) || defined(USE_GYRO_SPI_MPU6500)
345 #ifdef USE_GYRO_SPI_MPU6500
346 if (mpu6500GyroDetect(dev
) || mpu6500SpiGyroDetect(dev
)) {
348 if (mpu6500GyroDetect(dev
)) {
350 switch (dev
->mpuDetectionResult
.sensor
) {
352 gyroHardware
= GYRO_MPU9250
;
355 gyroHardware
= GYRO_ICM20601
;
358 gyroHardware
= GYRO_ICM20602
;
361 gyroHardware
= GYRO_ICM20608G
;
364 gyroHardware
= GYRO_MPU6500
;
366 #ifdef GYRO_MPU6500_ALIGN
367 dev
->gyroAlign
= GYRO_MPU6500_ALIGN
;
374 #ifdef USE_GYRO_SPI_MPU9250
376 if (mpu9250SpiGyroDetect(dev
)) {
377 gyroHardware
= GYRO_MPU9250
;
378 #ifdef GYRO_MPU9250_ALIGN
379 dev
->gyroAlign
= GYRO_MPU9250_ALIGN
;
386 #ifdef USE_GYRO_SPI_ICM20649
388 if (icm20649SpiGyroDetect(dev
)) {
389 gyroHardware
= GYRO_ICM20649
;
390 #ifdef GYRO_ICM20649_ALIGN
391 dev
->gyroAlign
= GYRO_ICM20649_ALIGN
;
398 #ifdef USE_GYRO_SPI_ICM20689
400 if (icm20689SpiGyroDetect(dev
)) {
401 gyroHardware
= GYRO_ICM20689
;
402 #ifdef GYRO_ICM20689_ALIGN
403 dev
->gyroAlign
= GYRO_ICM20689_ALIGN
;
410 #ifdef USE_ACCGYRO_BMI160
412 if (bmi160SpiGyroDetect(dev
)) {
413 gyroHardware
= GYRO_BMI160
;
414 #ifdef GYRO_BMI160_ALIGN
415 dev
->gyroAlign
= GYRO_BMI160_ALIGN
;
424 if (fakeGyroDetect(dev
)) {
425 gyroHardware
= GYRO_FAKE
;
432 gyroHardware
= GYRO_NONE
;
435 if (gyroHardware
!= GYRO_NONE
) {
436 detectedSensors
[SENSOR_INDEX_GYRO
] = gyroHardware
;
437 sensorsSet(SENSOR_GYRO
);
444 static bool gyroInitSensor(gyroSensor_t
*gyroSensor
)
446 gyroSensor
->gyroDev
.gyro_high_fsr
= gyroConfig()->gyro_high_fsr
;
448 #if defined(USE_GYRO_MPU6050) || defined(USE_GYRO_MPU3050) || defined(USE_GYRO_MPU6500) || defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU6000) \
449 || defined(USE_ACC_MPU6050) || defined(USE_GYRO_SPI_MPU9250) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) || defined(USE_GYRO_SPI_ICM20689)
451 mpuDetect(&gyroSensor
->gyroDev
);
452 mpuResetFn
= gyroSensor
->gyroDev
.mpuConfiguration
.resetFn
; // must be set after mpuDetect
455 const gyroSensor_e gyroHardware
= gyroDetect(&gyroSensor
->gyroDev
);
456 gyroSensor
->gyroDev
.gyroHardware
= gyroHardware
;
457 if (gyroHardware
== GYRO_NONE
) {
461 switch (gyroHardware
) {
468 // do nothing, as gyro supports 32kHz
471 // gyro does not support 32kHz
472 gyroConfigMutable()->gyro_use_32khz
= false;
476 // Must set gyro targetLooptime before gyroDev.init and initialisation of filters
477 gyro
.targetLooptime
= gyroSetSampleRate(&gyroSensor
->gyroDev
, gyroConfig()->gyro_hardware_lpf
, gyroConfig()->gyro_sync_denom
, gyroConfig()->gyro_use_32khz
);
478 gyroSensor
->gyroDev
.hardware_lpf
= gyroConfig()->gyro_hardware_lpf
;
479 gyroSensor
->gyroDev
.hardware_32khz_lpf
= gyroConfig()->gyro_32khz_hardware_lpf
;
480 gyroSensor
->gyroDev
.initFn(&gyroSensor
->gyroDev
);
481 if (gyroConfig()->gyro_align
!= ALIGN_DEFAULT
) {
482 gyroSensor
->gyroDev
.gyroAlign
= gyroConfig()->gyro_align
;
485 // As new gyros are supported, be sure to add them below based on whether they are subject to the overflow/inversion bug
486 // Any gyro not explicitly defined will default to not having built-in overflow protection as a safe alternative.
487 switch (gyroHardware
) {
488 case GYRO_NONE
: // Won't ever actually get here, but included to account for all gyro types
499 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= true;
505 case GYRO_ICM20649
: // we don't actually know if this is affected, but as there are currently no flight controllers using it we err on the side of caution
507 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= false;
511 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= false; // default catch for newly added gyros until proven to be unaffected
515 gyroInitSensorFilters(gyroSensor
);
517 #ifdef USE_GYRO_DATA_ANALYSE
518 gyroDataAnalyseStateInit(&gyroSensor
->gyroAnalyseState
, gyro
.targetLooptime
);
527 #ifdef USE_GYRO_OVERFLOW_CHECK
528 if (gyroConfig()->checkOverflow
== GYRO_OVERFLOW_CHECK_YAW
) {
529 overflowAxisMask
= GYRO_OVERFLOW_Z
;
530 } else if (gyroConfig()->checkOverflow
== GYRO_OVERFLOW_CHECK_ALL_AXES
) {
531 overflowAxisMask
= GYRO_OVERFLOW_X
| GYRO_OVERFLOW_Y
| GYRO_OVERFLOW_Z
;
533 overflowAxisMask
= 0;
541 case DEBUG_GYRO_SCALED
:
542 case DEBUG_GYRO_FILTERED
:
543 gyroDebugMode
= debugMode
;
546 // debugMode is not gyro-related
547 gyroDebugMode
= DEBUG_NONE
;
550 firstArmingCalibrationWasStarted
= false;
553 gyroToUse
= gyroConfig()->gyro_to_use
;
555 #if defined(USE_DUAL_GYRO) && defined(GYRO_1_CS_PIN)
556 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_1
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
557 gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
= IOGetByTag(IO_TAG(GYRO_1_CS_PIN
));
558 IOInit(gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, OWNER_MPU_CS
, RESOURCE_INDEX(0));
559 IOHi(gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
); // Ensure device is disabled, important when two devices are on the same bus.
560 IOConfigGPIO(gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, SPI_IO_CS_CFG
);
564 #if defined(USE_DUAL_GYRO) && defined(GYRO_2_CS_PIN)
565 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
566 gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
= IOGetByTag(IO_TAG(GYRO_2_CS_PIN
));
567 IOInit(gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, OWNER_MPU_CS
, RESOURCE_INDEX(1));
568 IOHi(gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
); // Ensure device is disabled, important when two devices are on the same bus.
569 IOConfigGPIO(gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, SPI_IO_CS_CFG
);
573 gyroSensor1
.gyroDev
.gyroAlign
= ALIGN_DEFAULT
;
575 #if defined(GYRO_1_EXTI_PIN)
576 gyroSensor1
.gyroDev
.mpuIntExtiTag
= IO_TAG(GYRO_1_EXTI_PIN
);
577 #elif defined(MPU_INT_EXTI)
578 gyroSensor1
.gyroDev
.mpuIntExtiTag
= IO_TAG(MPU_INT_EXTI
);
579 #elif defined(USE_HARDWARE_REVISION_DETECTION)
580 gyroSensor1
.gyroDev
.mpuIntExtiTag
= selectMPUIntExtiConfigByHardwareRevision();
582 gyroSensor1
.gyroDev
.mpuIntExtiTag
= IO_TAG_NONE
;
583 #endif // GYRO_1_EXTI_PIN
586 gyroSensor1
.gyroDev
.gyroAlign
= GYRO_1_ALIGN
;
588 gyroSensor1
.gyroDev
.bus
.bustype
= BUSTYPE_SPI
;
589 spiBusSetInstance(&gyroSensor1
.gyroDev
.bus
, GYRO_1_SPI_INSTANCE
);
590 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_1
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
591 ret
= gyroInitSensor(&gyroSensor1
);
593 return false; // TODO handle failure of first gyro detection better. - Perhaps update the config to use second gyro then indicate a new failure mode and reboot.
595 gyroHasOverflowProtection
= gyroHasOverflowProtection
&& gyroSensor1
.gyroDev
.gyroHasOverflowProtection
;
597 #else // USE_DUAL_GYRO
598 ret
= gyroInitSensor(&gyroSensor1
);
599 gyroHasOverflowProtection
= gyroHasOverflowProtection
&& gyroSensor1
.gyroDev
.gyroHasOverflowProtection
;
600 #endif // USE_DUAL_GYRO
604 gyroSensor2
.gyroDev
.gyroAlign
= ALIGN_DEFAULT
;
606 #if defined(GYRO_2_EXTI_PIN)
607 gyroSensor2
.gyroDev
.mpuIntExtiTag
= IO_TAG(GYRO_2_EXTI_PIN
);
608 #elif defined(USE_HARDWARE_REVISION_DETECTION)
609 gyroSensor2
.gyroDev
.mpuIntExtiTag
= selectMPUIntExtiConfigByHardwareRevision();
611 gyroSensor2
.gyroDev
.mpuIntExtiTag
= IO_TAG_NONE
;
612 #endif // GYRO_2_EXTI_PIN
614 gyroSensor2
.gyroDev
.gyroAlign
= GYRO_2_ALIGN
;
616 gyroSensor2
.gyroDev
.bus
.bustype
= BUSTYPE_SPI
;
617 spiBusSetInstance(&gyroSensor2
.gyroDev
.bus
, GYRO_2_SPI_INSTANCE
);
618 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
619 ret
= gyroInitSensor(&gyroSensor2
);
621 return false; // TODO handle failure of second gyro detection better. - Perhaps update the config to use first gyro then indicate a new failure mode and reboot.
623 gyroHasOverflowProtection
= gyroHasOverflowProtection
&& gyroSensor2
.gyroDev
.gyroHasOverflowProtection
;
625 #endif // USE_DUAL_GYRO
628 // Only allow using both gyros simultaneously if they are the same hardware type.
629 // If the user selected "BOTH" and they are not the same type, then reset to using only the first gyro.
630 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
631 if (gyroSensor1
.gyroDev
.gyroHardware
!= gyroSensor2
.gyroDev
.gyroHardware
) {
632 gyroToUse
= GYRO_CONFIG_USE_GYRO_1
;
633 gyroConfigMutable()->gyro_to_use
= GYRO_CONFIG_USE_GYRO_1
;
634 detectedSensors
[SENSOR_INDEX_GYRO
] = gyroSensor1
.gyroDev
.gyroHardware
;
635 sensorsSet(SENSOR_GYRO
);
639 #endif // USE_DUAL_GYRO
643 void gyroInitLowpassFilterLpf(gyroSensor_t
*gyroSensor
, int slot
, int type
, uint16_t lpfHz
)
645 filterApplyFnPtr
*lowpassFilterApplyFn
;
646 gyroLowpassFilter_t
*lowpassFilter
= NULL
;
650 lowpassFilterApplyFn
= &gyroSensor
->lowpassFilterApplyFn
;
651 lowpassFilter
= gyroSensor
->lowpassFilter
;
654 case FILTER_LOWPASS2
:
655 lowpassFilterApplyFn
= &gyroSensor
->lowpass2FilterApplyFn
;
656 lowpassFilter
= gyroSensor
->lowpass2Filter
;
663 // Establish some common constants
664 const uint32_t gyroFrequencyNyquist
= 1000000 / 2 / gyro
.targetLooptime
;
665 const float gyroDt
= gyro
.targetLooptime
* 1e-6f
;
667 // Gain could be calculated a little later as it is specific to the pt1/bqrcf2/fkf branches
668 const float gain
= pt1FilterGain(lpfHz
, gyroDt
);
670 // Dereference the pointer to null before checking valid cutoff and filter
671 // type. It will be overridden for positive cases.
672 *lowpassFilterApplyFn
= nullFilterApply
;
674 // If lowpass cutoff has been specified and is less than the Nyquist frequency
675 if (lpfHz
&& lpfHz
<= gyroFrequencyNyquist
) {
678 *lowpassFilterApplyFn
= (filterApplyFnPtr
) pt1FilterApply
;
679 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
680 pt1FilterInit(&lowpassFilter
[axis
].pt1FilterState
, gain
);
684 *lowpassFilterApplyFn
= (filterApplyFnPtr
) biquadFilterApply
;
685 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
686 biquadFilterInitLPF(&lowpassFilter
[axis
].biquadFilterState
, lpfHz
, gyro
.targetLooptime
);
693 static uint16_t calculateNyquistAdjustedNotchHz(uint16_t notchHz
, uint16_t notchCutoffHz
)
695 const uint32_t gyroFrequencyNyquist
= 1000000 / 2 / gyro
.targetLooptime
;
696 if (notchHz
> gyroFrequencyNyquist
) {
697 if (notchCutoffHz
< gyroFrequencyNyquist
) {
698 notchHz
= gyroFrequencyNyquist
;
707 #if defined(USE_GYRO_SLEW_LIMITER)
708 void gyroInitSlewLimiter(gyroSensor_t
*gyroSensor
) {
710 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
711 gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
] = 0;
716 static void gyroInitFilterNotch1(gyroSensor_t
*gyroSensor
, uint16_t notchHz
, uint16_t notchCutoffHz
)
718 gyroSensor
->notchFilter1ApplyFn
= nullFilterApply
;
720 notchHz
= calculateNyquistAdjustedNotchHz(notchHz
, notchCutoffHz
);
722 if (notchHz
!= 0 && notchCutoffHz
!= 0) {
723 gyroSensor
->notchFilter1ApplyFn
= (filterApplyFnPtr
)biquadFilterApply
;
724 const float notchQ
= filterGetNotchQ(notchHz
, notchCutoffHz
);
725 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
726 biquadFilterInit(&gyroSensor
->notchFilter1
[axis
], notchHz
, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
);
731 static void gyroInitFilterNotch2(gyroSensor_t
*gyroSensor
, uint16_t notchHz
, uint16_t notchCutoffHz
)
733 gyroSensor
->notchFilter2ApplyFn
= nullFilterApply
;
735 notchHz
= calculateNyquistAdjustedNotchHz(notchHz
, notchCutoffHz
);
737 if (notchHz
!= 0 && notchCutoffHz
!= 0) {
738 gyroSensor
->notchFilter2ApplyFn
= (filterApplyFnPtr
)biquadFilterApply
;
739 const float notchQ
= filterGetNotchQ(notchHz
, notchCutoffHz
);
740 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
741 biquadFilterInit(&gyroSensor
->notchFilter2
[axis
], notchHz
, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
);
746 #ifdef USE_GYRO_DATA_ANALYSE
747 static bool isDynamicFilterActive(void)
749 return feature(FEATURE_DYNAMIC_FILTER
);
752 static void gyroInitFilterDynamic(gyroSensor_t
*gyroSensor
)
754 gyroSensor
->dynFilterApplyFn
= nullFilterApply
;
756 if (isDynamicFilterActive()) {
757 switch (gyroConfig()->dyn_filter_type
) {
759 const float gyroDt
= gyro
.targetLooptime
* 1e-6f
;
760 const float gain
= pt1FilterGain(DYNAMIC_LOWPASS_DEFAULT_CUTOFF_HZ
, gyroDt
);
762 gyroSensor
->dynFilterApplyFn
= (filterApplyFnPtr
) pt1FilterApply
;
764 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
765 pt1FilterInit(&gyroSensor
->dynFilter
[axis
].pt1FilterState
, gain
);
770 case FILTER_BIQUAD
: {
771 const float notchQ
= filterGetNotchQ(DYNAMIC_NOTCH_DEFAULT_CENTER_HZ
, DYNAMIC_NOTCH_DEFAULT_CUTOFF_HZ
);
773 gyroSensor
->dynFilterApplyFn
= (filterApplyFnPtr
) biquadFilterApplyDF1
;
775 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
776 biquadFilterInit(&gyroSensor
->dynFilter
[axis
].biquadFilterState
, DYNAMIC_NOTCH_DEFAULT_CENTER_HZ
, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
);
787 static void gyroInitSensorFilters(gyroSensor_t
*gyroSensor
)
789 #if defined(USE_GYRO_SLEW_LIMITER)
790 gyroInitSlewLimiter(gyroSensor
);
793 gyroInitLowpassFilterLpf(
796 gyroConfig()->gyro_lowpass_type
,
797 gyroConfig()->gyro_lowpass_hz
800 gyroInitLowpassFilterLpf(
803 gyroConfig()->gyro_lowpass2_type
,
804 gyroConfig()->gyro_lowpass2_hz
807 gyroInitFilterNotch1(gyroSensor
, gyroConfig()->gyro_soft_notch_hz_1
, gyroConfig()->gyro_soft_notch_cutoff_1
);
808 gyroInitFilterNotch2(gyroSensor
, gyroConfig()->gyro_soft_notch_hz_2
, gyroConfig()->gyro_soft_notch_cutoff_2
);
809 #ifdef USE_GYRO_DATA_ANALYSE
810 gyroInitFilterDynamic(gyroSensor
);
814 void gyroInitFilters(void)
816 gyroInitSensorFilters(&gyroSensor1
);
818 gyroInitSensorFilters(&gyroSensor2
);
822 FAST_CODE
bool isGyroSensorCalibrationComplete(const gyroSensor_t
*gyroSensor
)
824 return gyroSensor
->calibration
.cyclesRemaining
== 0;
827 FAST_CODE
bool isGyroCalibrationComplete(void)
832 case GYRO_CONFIG_USE_GYRO_1
: {
833 return isGyroSensorCalibrationComplete(&gyroSensor1
);
835 case GYRO_CONFIG_USE_GYRO_2
: {
836 return isGyroSensorCalibrationComplete(&gyroSensor2
);
838 case GYRO_CONFIG_USE_GYRO_BOTH
: {
839 return isGyroSensorCalibrationComplete(&gyroSensor1
) && isGyroSensorCalibrationComplete(&gyroSensor2
);
843 return isGyroSensorCalibrationComplete(&gyroSensor1
);
847 static bool isOnFinalGyroCalibrationCycle(const gyroCalibration_t
*gyroCalibration
)
849 return gyroCalibration
->cyclesRemaining
== 1;
852 static int32_t gyroCalculateCalibratingCycles(void)
854 return (gyroConfig()->gyroCalibrationDuration
* 10000) / gyro
.targetLooptime
;
857 static bool isOnFirstGyroCalibrationCycle(const gyroCalibration_t
*gyroCalibration
)
859 return gyroCalibration
->cyclesRemaining
== gyroCalculateCalibratingCycles();
862 static void gyroSetCalibrationCycles(gyroSensor_t
*gyroSensor
)
864 gyroSensor
->calibration
.cyclesRemaining
= gyroCalculateCalibratingCycles();
867 void gyroStartCalibration(bool isFirstArmingCalibration
)
869 if (!(isFirstArmingCalibration
&& firstArmingCalibrationWasStarted
)) {
870 gyroSetCalibrationCycles(&gyroSensor1
);
872 gyroSetCalibrationCycles(&gyroSensor2
);
875 if (isFirstArmingCalibration
) {
876 firstArmingCalibrationWasStarted
= true;
881 bool isFirstArmingGyroCalibrationRunning(void)
883 return firstArmingCalibrationWasStarted
&& !isGyroCalibrationComplete();
886 STATIC_UNIT_TESTED
void performGyroCalibration(gyroSensor_t
*gyroSensor
, uint8_t gyroMovementCalibrationThreshold
)
888 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
889 // Reset g[axis] at start of calibration
890 if (isOnFirstGyroCalibrationCycle(&gyroSensor
->calibration
)) {
891 gyroSensor
->calibration
.sum
[axis
] = 0.0f
;
892 devClear(&gyroSensor
->calibration
.var
[axis
]);
893 // gyroZero is set to zero until calibration complete
894 gyroSensor
->gyroDev
.gyroZero
[axis
] = 0.0f
;
897 // Sum up CALIBRATING_GYRO_TIME_US readings
898 gyroSensor
->calibration
.sum
[axis
] += gyroSensor
->gyroDev
.gyroADCRaw
[axis
];
899 devPush(&gyroSensor
->calibration
.var
[axis
], gyroSensor
->gyroDev
.gyroADCRaw
[axis
]);
901 if (isOnFinalGyroCalibrationCycle(&gyroSensor
->calibration
)) {
902 const float stddev
= devStandardDeviation(&gyroSensor
->calibration
.var
[axis
]);
903 // DEBUG_GYRO_CALIBRATION records the standard deviation of roll
904 // into the spare field - debug[3], in DEBUG_GYRO_RAW
906 DEBUG_SET(DEBUG_GYRO_RAW
, DEBUG_GYRO_CALIBRATION
, lrintf(stddev
));
909 // check deviation and startover in case the model was moved
910 if (gyroMovementCalibrationThreshold
&& stddev
> gyroMovementCalibrationThreshold
) {
911 gyroSetCalibrationCycles(gyroSensor
);
915 // please take care with exotic boardalignment !!
916 gyroSensor
->gyroDev
.gyroZero
[axis
] = gyroSensor
->calibration
.sum
[axis
] / gyroCalculateCalibratingCycles();
918 gyroSensor
->gyroDev
.gyroZero
[axis
] -= ((float)gyroConfig()->gyro_offset_yaw
/ 100);
923 if (isOnFinalGyroCalibrationCycle(&gyroSensor
->calibration
)) {
924 schedulerResetTaskStatistics(TASK_SELF
); // so calibration cycles do not pollute tasks statistics
925 if (!firstArmingCalibrationWasStarted
|| (getArmingDisableFlags() & ~ARMING_DISABLED_CALIBRATING
) == 0) {
926 beeper(BEEPER_GYRO_CALIBRATED
);
929 --gyroSensor
->calibration
.cyclesRemaining
;
933 #if defined(USE_GYRO_SLEW_LIMITER)
934 FAST_CODE
int32_t gyroSlewLimiter(gyroSensor_t
*gyroSensor
, int axis
)
936 int32_t ret
= (int32_t)gyroSensor
->gyroDev
.gyroADCRaw
[axis
];
937 if (gyroConfig()->checkOverflow
|| gyroHasOverflowProtection
) {
938 // don't use the slew limiter if overflow checking is on or gyro is not subject to overflow bug
941 if (abs(ret
- gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
]) > (1<<14)) {
942 // there has been a large change in value, so assume overflow has occurred and return the previous value
943 ret
= gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
];
945 gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
] = ret
;
951 #ifdef USE_GYRO_OVERFLOW_CHECK
952 static FAST_CODE_NOINLINE
void handleOverflow(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
954 const float gyroOverflowResetRate
= GYRO_OVERFLOW_RESET_THRESHOLD
* gyroSensor
->gyroDev
.scale
;
955 if ((abs(gyro
.gyroADCf
[X
]) < gyroOverflowResetRate
)
956 && (abs(gyro
.gyroADCf
[Y
]) < gyroOverflowResetRate
)
957 && (abs(gyro
.gyroADCf
[Z
]) < gyroOverflowResetRate
)) {
958 // if we have 50ms of consecutive OK gyro vales, then assume yaw readings are OK again and reset overflowDetected
959 // reset requires good OK values on all axes
960 if (cmpTimeUs(currentTimeUs
, gyroSensor
->overflowTimeUs
) > 50000) {
961 gyroSensor
->overflowDetected
= false;
964 // not a consecutive OK value, so reset the overflow time
965 gyroSensor
->overflowTimeUs
= currentTimeUs
;
969 static FAST_CODE
void checkForOverflow(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
971 // check for overflow to handle Yaw Spin To The Moon (YSTTM)
972 // ICM gyros are specified to +/- 2000 deg/sec, in a crash they can go out of spec.
973 // This can cause an overflow and sign reversal in the output.
974 // Overflow and sign reversal seems to result in a gyro value of +1996 or -1996.
975 if (gyroSensor
->overflowDetected
) {
976 handleOverflow(gyroSensor
, currentTimeUs
);
978 #ifndef SIMULATOR_BUILD
979 // check for overflow in the axes set in overflowAxisMask
980 gyroOverflow_e overflowCheck
= GYRO_OVERFLOW_NONE
;
981 const float gyroOverflowTriggerRate
= GYRO_OVERFLOW_TRIGGER_THRESHOLD
* gyroSensor
->gyroDev
.scale
;
982 if (abs(gyro
.gyroADCf
[X
]) > gyroOverflowTriggerRate
) {
983 overflowCheck
|= GYRO_OVERFLOW_X
;
985 if (abs(gyro
.gyroADCf
[Y
]) > gyroOverflowTriggerRate
) {
986 overflowCheck
|= GYRO_OVERFLOW_Y
;
988 if (abs(gyro
.gyroADCf
[Z
]) > gyroOverflowTriggerRate
) {
989 overflowCheck
|= GYRO_OVERFLOW_Z
;
991 if (overflowCheck
& overflowAxisMask
) {
992 gyroSensor
->overflowDetected
= true;
993 gyroSensor
->overflowTimeUs
= currentTimeUs
;
994 #ifdef USE_YAW_SPIN_RECOVERY
995 gyroSensor
->yawSpinDetected
= false;
996 #endif // USE_YAW_SPIN_RECOVERY
998 #endif // SIMULATOR_BUILD
1001 #endif // USE_GYRO_OVERFLOW_CHECK
1003 #ifdef USE_YAW_SPIN_RECOVERY
1004 static FAST_CODE_NOINLINE
void handleYawSpin(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
1006 const float yawSpinResetRate
= gyroConfig()->yaw_spin_threshold
- 100.0f
;
1007 if (abs(gyro
.gyroADCf
[Z
]) < yawSpinResetRate
) {
1008 // testing whether 20ms of consecutive OK gyro yaw values is enough
1009 if (cmpTimeUs(currentTimeUs
, gyroSensor
->yawSpinTimeUs
) > 20000) {
1010 gyroSensor
->yawSpinDetected
= false;
1013 // reset the yaw spin time
1014 gyroSensor
->yawSpinTimeUs
= currentTimeUs
;
1018 static FAST_CODE
void checkForYawSpin(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
1020 // if not in overflow mode, handle yaw spins above threshold
1021 #ifdef USE_GYRO_OVERFLOW_CHECK
1022 if (gyroSensor
->overflowDetected
) {
1023 gyroSensor
->yawSpinDetected
= false;
1026 #endif // USE_GYRO_OVERFLOW_CHECK
1028 if (gyroSensor
->yawSpinDetected
) {
1029 handleYawSpin(gyroSensor
, currentTimeUs
);
1031 #ifndef SIMULATOR_BUILD
1032 // check for spin on yaw axis only
1033 if (abs(gyro
.gyroADCf
[Z
]) > gyroConfig()->yaw_spin_threshold
) {
1034 gyroSensor
->yawSpinDetected
= true;
1035 gyroSensor
->yawSpinTimeUs
= currentTimeUs
;
1037 #endif // SIMULATOR_BUILD
1040 #endif // USE_YAW_SPIN_RECOVERY
1042 #define GYRO_FILTER_FUNCTION_NAME filterGyro
1043 #define GYRO_FILTER_DEBUG_SET(...)
1044 #include "gyro_filter_impl.h"
1045 #undef GYRO_FILTER_FUNCTION_NAME
1046 #undef GYRO_FILTER_DEBUG_SET
1048 #define GYRO_FILTER_FUNCTION_NAME filterGyroDebug
1049 #define GYRO_FILTER_DEBUG_SET DEBUG_SET
1050 #include "gyro_filter_impl.h"
1051 #undef GYRO_FILTER_FUNCTION_NAME
1052 #undef GYRO_FILTER_DEBUG_SET
1054 static FAST_CODE FAST_CODE_NOINLINE
void gyroUpdateSensor(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
1056 if (!gyroSensor
->gyroDev
.readFn(&gyroSensor
->gyroDev
)) {
1059 gyroSensor
->gyroDev
.dataReady
= false;
1061 if (isGyroSensorCalibrationComplete(gyroSensor
)) {
1062 // move 16-bit gyro data into 32-bit variables to avoid overflows in calculations
1064 #if defined(USE_GYRO_SLEW_LIMITER)
1065 gyroSensor
->gyroDev
.gyroADC
[X
] = gyroSlewLimiter(gyroSensor
, X
) - gyroSensor
->gyroDev
.gyroZero
[X
];
1066 gyroSensor
->gyroDev
.gyroADC
[Y
] = gyroSlewLimiter(gyroSensor
, Y
) - gyroSensor
->gyroDev
.gyroZero
[Y
];
1067 gyroSensor
->gyroDev
.gyroADC
[Z
] = gyroSlewLimiter(gyroSensor
, Z
) - gyroSensor
->gyroDev
.gyroZero
[Z
];
1069 gyroSensor
->gyroDev
.gyroADC
[X
] = gyroSensor
->gyroDev
.gyroADCRaw
[X
] - gyroSensor
->gyroDev
.gyroZero
[X
];
1070 gyroSensor
->gyroDev
.gyroADC
[Y
] = gyroSensor
->gyroDev
.gyroADCRaw
[Y
] - gyroSensor
->gyroDev
.gyroZero
[Y
];
1071 gyroSensor
->gyroDev
.gyroADC
[Z
] = gyroSensor
->gyroDev
.gyroADCRaw
[Z
] - gyroSensor
->gyroDev
.gyroZero
[Z
];
1074 alignSensors(gyroSensor
->gyroDev
.gyroADC
, gyroSensor
->gyroDev
.gyroAlign
);
1076 performGyroCalibration(gyroSensor
, gyroConfig()->gyroMovementCalibrationThreshold
);
1077 // still calibrating, so no need to further process gyro data
1081 const timeDelta_t sampleDeltaUs
= currentTimeUs
- accumulationLastTimeSampledUs
;
1082 accumulationLastTimeSampledUs
= currentTimeUs
;
1083 accumulatedMeasurementTimeUs
+= sampleDeltaUs
;
1085 #ifdef USE_GYRO_OVERFLOW_CHECK
1086 if (gyroConfig()->checkOverflow
&& !gyroHasOverflowProtection
) {
1087 checkForOverflow(gyroSensor
, currentTimeUs
);
1091 #ifdef USE_YAW_SPIN_RECOVERY
1092 if (gyroConfig()->yaw_spin_recovery
) {
1093 checkForYawSpin(gyroSensor
, currentTimeUs
);
1097 if (gyroDebugMode
== DEBUG_NONE
) {
1098 filterGyro(gyroSensor
, sampleDeltaUs
);
1100 filterGyroDebug(gyroSensor
, sampleDeltaUs
);
1103 #ifdef USE_GYRO_DATA_ANALYSE
1104 if (isDynamicFilterActive()) {
1105 gyroDataAnalyse(&gyroSensor
->gyroAnalyseState
, gyroSensor
->dynFilter
);
1110 FAST_CODE
void gyroUpdate(timeUs_t currentTimeUs
)
1112 #ifdef USE_DUAL_GYRO
1113 switch (gyroToUse
) {
1114 case GYRO_CONFIG_USE_GYRO_1
:
1115 gyroUpdateSensor(&gyroSensor1
, currentTimeUs
);
1116 if (isGyroSensorCalibrationComplete(&gyroSensor1
)) {
1117 gyro
.gyroADCf
[X
] = gyroSensor1
.gyroDev
.gyroADCf
[X
];
1118 gyro
.gyroADCf
[Y
] = gyroSensor1
.gyroDev
.gyroADCf
[Y
];
1119 gyro
.gyroADCf
[Z
] = gyroSensor1
.gyroDev
.gyroADCf
[Z
];
1121 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 0, gyroSensor1
.gyroDev
.gyroADCRaw
[X
]);
1122 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 1, gyroSensor1
.gyroDev
.gyroADCRaw
[Y
]);
1123 DEBUG_SET(DEBUG_DUAL_GYRO
, 0, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[X
]));
1124 DEBUG_SET(DEBUG_DUAL_GYRO
, 1, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Y
]));
1125 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 0, lrintf(gyro
.gyroADCf
[X
]));
1126 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 1, lrintf(gyro
.gyroADCf
[Y
]));
1128 case GYRO_CONFIG_USE_GYRO_2
:
1129 gyroUpdateSensor(&gyroSensor2
, currentTimeUs
);
1130 if (isGyroSensorCalibrationComplete(&gyroSensor2
)) {
1131 gyro
.gyroADCf
[X
] = gyroSensor2
.gyroDev
.gyroADCf
[X
];
1132 gyro
.gyroADCf
[Y
] = gyroSensor2
.gyroDev
.gyroADCf
[Y
];
1133 gyro
.gyroADCf
[Z
] = gyroSensor2
.gyroDev
.gyroADCf
[Z
];
1135 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 2, gyroSensor2
.gyroDev
.gyroADCRaw
[X
]);
1136 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 3, gyroSensor2
.gyroDev
.gyroADCRaw
[Y
]);
1137 DEBUG_SET(DEBUG_DUAL_GYRO
, 2, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[X
]));
1138 DEBUG_SET(DEBUG_DUAL_GYRO
, 3, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[Y
]));
1139 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 2, lrintf(gyro
.gyroADCf
[X
]));
1140 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 3, lrintf(gyro
.gyroADCf
[Y
]));
1142 case GYRO_CONFIG_USE_GYRO_BOTH
:
1143 gyroUpdateSensor(&gyroSensor1
, currentTimeUs
);
1144 gyroUpdateSensor(&gyroSensor2
, currentTimeUs
);
1145 if (isGyroSensorCalibrationComplete(&gyroSensor1
) && isGyroSensorCalibrationComplete(&gyroSensor2
)) {
1146 gyro
.gyroADCf
[X
] = (gyroSensor1
.gyroDev
.gyroADCf
[X
] + gyroSensor2
.gyroDev
.gyroADCf
[X
]) / 2.0f
;
1147 gyro
.gyroADCf
[Y
] = (gyroSensor1
.gyroDev
.gyroADCf
[Y
] + gyroSensor2
.gyroDev
.gyroADCf
[Y
]) / 2.0f
;
1148 gyro
.gyroADCf
[Z
] = (gyroSensor1
.gyroDev
.gyroADCf
[Z
] + gyroSensor2
.gyroDev
.gyroADCf
[Z
]) / 2.0f
;
1150 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 0, gyroSensor1
.gyroDev
.gyroADCRaw
[X
]);
1151 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 1, gyroSensor1
.gyroDev
.gyroADCRaw
[Y
]);
1152 DEBUG_SET(DEBUG_DUAL_GYRO
, 0, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[X
]));
1153 DEBUG_SET(DEBUG_DUAL_GYRO
, 1, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Y
]));
1154 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 2, gyroSensor2
.gyroDev
.gyroADCRaw
[X
]);
1155 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 3, gyroSensor2
.gyroDev
.gyroADCRaw
[Y
]);
1156 DEBUG_SET(DEBUG_DUAL_GYRO
, 2, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[X
]));
1157 DEBUG_SET(DEBUG_DUAL_GYRO
, 3, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[Y
]));
1158 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 1, lrintf(gyro
.gyroADCf
[X
]));
1159 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 2, lrintf(gyro
.gyroADCf
[Y
]));
1160 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF
, 0, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[X
] - gyroSensor2
.gyroDev
.gyroADCf
[X
]));
1161 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF
, 1, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Y
] - gyroSensor2
.gyroDev
.gyroADCf
[Y
]));
1162 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF
, 2, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Z
] - gyroSensor2
.gyroDev
.gyroADCf
[Z
]));
1166 gyroUpdateSensor(&gyroSensor1
, currentTimeUs
);
1167 gyro
.gyroADCf
[X
] = gyroSensor1
.gyroDev
.gyroADCf
[X
];
1168 gyro
.gyroADCf
[Y
] = gyroSensor1
.gyroDev
.gyroADCf
[Y
];
1169 gyro
.gyroADCf
[Z
] = gyroSensor1
.gyroDev
.gyroADCf
[Z
];
1173 bool gyroGetAccumulationAverage(float *accumulationAverage
)
1175 if (accumulatedMeasurementTimeUs
> 0) {
1176 // If we have gyro data accumulated, calculate average rate that will yield the same rotation
1177 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
1178 accumulationAverage
[axis
] = accumulatedMeasurements
[axis
] / accumulatedMeasurementTimeUs
;
1179 accumulatedMeasurements
[axis
] = 0.0f
;
1181 accumulatedMeasurementTimeUs
= 0;
1184 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
1185 accumulationAverage
[axis
] = 0.0f
;
1191 void gyroReadTemperature(void)
1193 if (gyroSensor1
.gyroDev
.temperatureFn
) {
1194 gyroSensor1
.gyroDev
.temperatureFn(&gyroSensor1
.gyroDev
, &gyroSensor1
.gyroDev
.temperature
);
1198 int16_t gyroGetTemperature(void)
1200 return gyroSensor1
.gyroDev
.temperature
;
1203 int16_t gyroRateDps(int axis
)
1205 #ifdef USE_DUAL_GYRO
1206 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
1207 return lrintf(gyro
.gyroADCf
[axis
] / gyroSensor2
.gyroDev
.scale
);
1209 return lrintf(gyro
.gyroADCf
[axis
] / gyroSensor1
.gyroDev
.scale
);
1212 return lrintf(gyro
.gyroADCf
[axis
] / gyroSensor1
.gyroDev
.scale
);
1216 bool gyroOverflowDetected(void)
1218 return gyroSensor1
.overflowDetected
;
1221 #ifdef USE_YAW_SPIN_RECOVERY
1222 bool gyroYawSpinDetected(void)
1224 return gyroSensor1
.yawSpinDetected
;
1226 #endif // USE_YAW_SPIN_RECOVERY
1228 uint16_t gyroAbsRateDps(int axis
)
1230 return fabsf(gyro
.gyroADCf
[axis
]);
1233 #ifdef USE_GYRO_REGISTER_DUMP
1234 uint8_t gyroReadRegister(uint8_t whichSensor
, uint8_t reg
)
1236 return mpuGyroReadRegister(gyroSensorBusByDevice(whichSensor
), reg
);
1238 #endif // USE_GYRO_REGISTER_DUMP