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 #include "sensors/gyroanalyse.h"
76 #include "sensors/sensors.h"
78 #ifdef USE_HARDWARE_REVISION_DETECTION
79 #include "hardware_revision.h"
82 #if ((FLASH_SIZE > 128) && (defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20689) || defined(USE_GYRO_SPI_MPU6500)))
83 #define USE_GYRO_SLEW_LIMITER
86 FAST_RAM_ZERO_INIT gyro_t gyro
;
87 static FAST_RAM_ZERO_INIT
uint8_t gyroDebugMode
;
89 static uint8_t gyroToUse
= 0;
91 #ifdef USE_GYRO_OVERFLOW_CHECK
92 static FAST_RAM_ZERO_INIT
uint8_t overflowAxisMask
;
94 static FAST_RAM_ZERO_INIT
float accumulatedMeasurements
[XYZ_AXIS_COUNT
];
95 static FAST_RAM_ZERO_INIT
float gyroPrevious
[XYZ_AXIS_COUNT
];
96 static FAST_RAM_ZERO_INIT timeUs_t accumulatedMeasurementTimeUs
;
97 static FAST_RAM_ZERO_INIT timeUs_t accumulationLastTimeSampledUs
;
99 static bool gyroHasOverflowProtection
= true;
101 typedef struct gyroCalibration_s
{
102 float sum
[XYZ_AXIS_COUNT
];
103 stdev_t var
[XYZ_AXIS_COUNT
];
104 int32_t cyclesRemaining
;
107 bool firstArmingCalibrationWasStarted
= false;
109 typedef union gyroLowpassFilter_u
{
110 pt1Filter_t pt1FilterState
;
111 biquadFilter_t biquadFilterState
;
112 } gyroLowpassFilter_t
;
114 typedef struct gyroSensor_s
{
116 gyroCalibration_t calibration
;
118 // lowpass gyro soft filter
119 filterApplyFnPtr lowpassFilterApplyFn
;
120 gyroLowpassFilter_t lowpassFilter
[XYZ_AXIS_COUNT
];
122 // lowpass2 gyro soft filter
123 filterApplyFnPtr lowpass2FilterApplyFn
;
124 gyroLowpassFilter_t lowpass2Filter
[XYZ_AXIS_COUNT
];
127 filterApplyFnPtr notchFilter1ApplyFn
;
128 biquadFilter_t notchFilter1
[XYZ_AXIS_COUNT
];
130 filterApplyFnPtr notchFilter2ApplyFn
;
131 biquadFilter_t notchFilter2
[XYZ_AXIS_COUNT
];
133 filterApplyFnPtr notchFilterDynApplyFn
;
134 biquadFilter_t notchFilterDyn
[XYZ_AXIS_COUNT
];
136 // overflow and recovery
137 timeUs_t overflowTimeUs
;
138 bool overflowDetected
;
139 #ifdef USE_YAW_SPIN_RECOVERY
140 timeUs_t yawSpinTimeUs
;
141 bool yawSpinDetected
;
142 #endif // USE_YAW_SPIN_RECOVERY
145 STATIC_UNIT_TESTED FAST_RAM_ZERO_INIT gyroSensor_t gyroSensor1
;
147 STATIC_UNIT_TESTED FAST_RAM_ZERO_INIT gyroSensor_t gyroSensor2
;
151 STATIC_UNIT_TESTED gyroSensor_t
* const gyroSensorPtr
= &gyroSensor1
;
152 STATIC_UNIT_TESTED gyroDev_t
* const gyroDevPtr
= &gyroSensor1
.gyroDev
;
155 static void gyroInitSensorFilters(gyroSensor_t
*gyroSensor
);
156 static void gyroInitLowpassFilterLpf(gyroSensor_t
*gyroSensor
, int slot
, int type
, uint16_t lpfHz
);
158 #define DEBUG_GYRO_CALIBRATION 3
161 #define GYRO_SYNC_DENOM_DEFAULT 8
162 #elif defined(USE_GYRO_SPI_MPU6000) || defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) \
163 || defined(USE_GYRO_SPI_ICM20689)
164 #define GYRO_SYNC_DENOM_DEFAULT 1
166 #define GYRO_SYNC_DENOM_DEFAULT 4
169 #define GYRO_OVERFLOW_TRIGGER_THRESHOLD 31980 // 97.5% full scale (1950dps for 2000dps gyro)
170 #define GYRO_OVERFLOW_RESET_THRESHOLD 30340 // 92.5% full scale (1850dps for 2000dps gyro)
172 PG_REGISTER_WITH_RESET_TEMPLATE(gyroConfig_t
, gyroConfig
, PG_GYRO_CONFIG
, 4);
174 #ifndef GYRO_CONFIG_USE_GYRO_DEFAULT
175 #define GYRO_CONFIG_USE_GYRO_DEFAULT GYRO_CONFIG_USE_GYRO_1
178 PG_RESET_TEMPLATE(gyroConfig_t
, gyroConfig
,
179 .gyro_align
= ALIGN_DEFAULT
,
180 .gyroCalibrationDuration
= 125, // 1.25 seconds
181 .gyroMovementCalibrationThreshold
= 48,
182 .gyro_sync_denom
= GYRO_SYNC_DENOM_DEFAULT
,
183 .gyro_hardware_lpf
= GYRO_HARDWARE_LPF_NORMAL
,
184 .gyro_32khz_hardware_lpf
= GYRO_32KHZ_HARDWARE_LPF_NORMAL
,
185 .gyro_lowpass_type
= FILTER_PT1
,
186 .gyro_lowpass_hz
= 100,
187 .gyro_lowpass2_type
= FILTER_PT1
,
188 .gyro_lowpass2_hz
= 300,
189 .gyro_high_fsr
= false,
190 .gyro_use_32khz
= false,
191 .gyro_to_use
= GYRO_CONFIG_USE_GYRO_DEFAULT
,
192 .gyro_soft_notch_hz_1
= 0,
193 .gyro_soft_notch_cutoff_1
= 0,
194 .gyro_soft_notch_hz_2
= 0,
195 .gyro_soft_notch_cutoff_2
= 0,
196 .checkOverflow
= GYRO_OVERFLOW_CHECK_ALL_AXES
,
197 .gyro_offset_yaw
= 0,
198 .yaw_spin_recovery
= true,
199 .yaw_spin_threshold
= 1950,
203 const busDevice_t
*gyroSensorBus(void)
206 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
207 return &gyroSensor2
.gyroDev
.bus
;
209 return &gyroSensor1
.gyroDev
.bus
;
212 return &gyroSensor1
.gyroDev
.bus
;
216 #ifdef USE_GYRO_REGISTER_DUMP
217 const busDevice_t
*gyroSensorBusByDevice(uint8_t whichSensor
)
220 if (whichSensor
== GYRO_CONFIG_USE_GYRO_2
) {
221 return &gyroSensor2
.gyroDev
.bus
;
223 return &gyroSensor1
.gyroDev
.bus
;
227 return &gyroSensor1
.gyroDev
.bus
;
230 #endif // USE_GYRO_REGISTER_DUMP
232 const mpuConfiguration_t
*gyroMpuConfiguration(void)
235 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
236 return &gyroSensor2
.gyroDev
.mpuConfiguration
;
238 return &gyroSensor1
.gyroDev
.mpuConfiguration
;
241 return &gyroSensor1
.gyroDev
.mpuConfiguration
;
245 const mpuDetectionResult_t
*gyroMpuDetectionResult(void)
248 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
249 return &gyroSensor2
.gyroDev
.mpuDetectionResult
;
251 return &gyroSensor1
.gyroDev
.mpuDetectionResult
;
254 return &gyroSensor1
.gyroDev
.mpuDetectionResult
;
258 STATIC_UNIT_TESTED gyroSensor_e
gyroDetect(gyroDev_t
*dev
)
260 gyroSensor_e gyroHardware
= GYRO_DEFAULT
;
262 switch (gyroHardware
) {
266 #ifdef USE_GYRO_MPU6050
268 if (mpu6050GyroDetect(dev
)) {
269 gyroHardware
= GYRO_MPU6050
;
270 #ifdef GYRO_MPU6050_ALIGN
271 dev
->gyroAlign
= GYRO_MPU6050_ALIGN
;
278 #ifdef USE_GYRO_L3G4200D
280 if (l3g4200dDetect(dev
)) {
281 gyroHardware
= GYRO_L3G4200D
;
282 #ifdef GYRO_L3G4200D_ALIGN
283 dev
->gyroAlign
= GYRO_L3G4200D_ALIGN
;
290 #ifdef USE_GYRO_MPU3050
292 if (mpu3050Detect(dev
)) {
293 gyroHardware
= GYRO_MPU3050
;
294 #ifdef GYRO_MPU3050_ALIGN
295 dev
->gyroAlign
= GYRO_MPU3050_ALIGN
;
302 #ifdef USE_GYRO_L3GD20
304 if (l3gd20Detect(dev
)) {
305 gyroHardware
= GYRO_L3GD20
;
306 #ifdef GYRO_L3GD20_ALIGN
307 dev
->gyroAlign
= GYRO_L3GD20_ALIGN
;
314 #ifdef USE_GYRO_SPI_MPU6000
316 if (mpu6000SpiGyroDetect(dev
)) {
317 gyroHardware
= GYRO_MPU6000
;
318 #ifdef GYRO_MPU6000_ALIGN
319 dev
->gyroAlign
= GYRO_MPU6000_ALIGN
;
326 #if defined(USE_GYRO_MPU6500) || defined(USE_GYRO_SPI_MPU6500)
331 #ifdef USE_GYRO_SPI_MPU6500
332 if (mpu6500GyroDetect(dev
) || mpu6500SpiGyroDetect(dev
)) {
334 if (mpu6500GyroDetect(dev
)) {
336 switch (dev
->mpuDetectionResult
.sensor
) {
338 gyroHardware
= GYRO_MPU9250
;
341 gyroHardware
= GYRO_ICM20601
;
344 gyroHardware
= GYRO_ICM20602
;
347 gyroHardware
= GYRO_ICM20608G
;
350 gyroHardware
= GYRO_MPU6500
;
352 #ifdef GYRO_MPU6500_ALIGN
353 dev
->gyroAlign
= GYRO_MPU6500_ALIGN
;
360 #ifdef USE_GYRO_SPI_MPU9250
362 if (mpu9250SpiGyroDetect(dev
)) {
363 gyroHardware
= GYRO_MPU9250
;
364 #ifdef GYRO_MPU9250_ALIGN
365 dev
->gyroAlign
= GYRO_MPU9250_ALIGN
;
372 #ifdef USE_GYRO_SPI_ICM20649
374 if (icm20649SpiGyroDetect(dev
)) {
375 gyroHardware
= GYRO_ICM20649
;
376 #ifdef GYRO_ICM20649_ALIGN
377 dev
->gyroAlign
= GYRO_ICM20649_ALIGN
;
384 #ifdef USE_GYRO_SPI_ICM20689
386 if (icm20689SpiGyroDetect(dev
)) {
387 gyroHardware
= GYRO_ICM20689
;
388 #ifdef GYRO_ICM20689_ALIGN
389 dev
->gyroAlign
= GYRO_ICM20689_ALIGN
;
396 #ifdef USE_ACCGYRO_BMI160
398 if (bmi160SpiGyroDetect(dev
)) {
399 gyroHardware
= GYRO_BMI160
;
400 #ifdef GYRO_BMI160_ALIGN
401 dev
->gyroAlign
= GYRO_BMI160_ALIGN
;
410 if (fakeGyroDetect(dev
)) {
411 gyroHardware
= GYRO_FAKE
;
418 gyroHardware
= GYRO_NONE
;
421 if (gyroHardware
!= GYRO_NONE
) {
422 detectedSensors
[SENSOR_INDEX_GYRO
] = gyroHardware
;
423 sensorsSet(SENSOR_GYRO
);
430 static bool gyroInitSensor(gyroSensor_t
*gyroSensor
)
432 gyroSensor
->gyroDev
.gyro_high_fsr
= gyroConfig()->gyro_high_fsr
;
434 #if defined(USE_GYRO_MPU6050) || defined(USE_GYRO_MPU3050) || defined(USE_GYRO_MPU6500) || defined(USE_GYRO_SPI_MPU6500) || defined(USE_GYRO_SPI_MPU6000) \
435 || defined(USE_ACC_MPU6050) || defined(USE_GYRO_SPI_MPU9250) || defined(USE_GYRO_SPI_ICM20601) || defined(USE_GYRO_SPI_ICM20649) || defined(USE_GYRO_SPI_ICM20689)
437 mpuDetect(&gyroSensor
->gyroDev
);
438 mpuResetFn
= gyroSensor
->gyroDev
.mpuConfiguration
.resetFn
; // must be set after mpuDetect
441 const gyroSensor_e gyroHardware
= gyroDetect(&gyroSensor
->gyroDev
);
442 gyroSensor
->gyroDev
.gyroHardware
= gyroHardware
;
443 if (gyroHardware
== GYRO_NONE
) {
447 switch (gyroHardware
) {
454 // do nothing, as gyro supports 32kHz
457 // gyro does not support 32kHz
458 gyroConfigMutable()->gyro_use_32khz
= false;
462 // Must set gyro targetLooptime before gyroDev.init and initialisation of filters
463 gyro
.targetLooptime
= gyroSetSampleRate(&gyroSensor
->gyroDev
, gyroConfig()->gyro_hardware_lpf
, gyroConfig()->gyro_sync_denom
, gyroConfig()->gyro_use_32khz
);
464 gyroSensor
->gyroDev
.hardware_lpf
= gyroConfig()->gyro_hardware_lpf
;
465 gyroSensor
->gyroDev
.hardware_32khz_lpf
= gyroConfig()->gyro_32khz_hardware_lpf
;
466 gyroSensor
->gyroDev
.initFn(&gyroSensor
->gyroDev
);
467 if (gyroConfig()->gyro_align
!= ALIGN_DEFAULT
) {
468 gyroSensor
->gyroDev
.gyroAlign
= gyroConfig()->gyro_align
;
471 // As new gyros are supported, be sure to add them below based on whether they are subject to the overflow/inversion bug
472 // Any gyro not explicitly defined will default to not having built-in overflow protection as a safe alternative.
473 switch (gyroHardware
) {
474 case GYRO_NONE
: // Won't ever actually get here, but included to account for all gyro types
485 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= true;
491 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
493 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= false;
497 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= false; // default catch for newly added gyros until proven to be unaffected
501 gyroInitSensorFilters(gyroSensor
);
503 #ifdef USE_GYRO_DATA_ANALYSE
504 gyroDataAnalyseInit(gyro
.targetLooptime
);
511 #ifdef USE_GYRO_OVERFLOW_CHECK
512 if (gyroConfig()->checkOverflow
== GYRO_OVERFLOW_CHECK_YAW
) {
513 overflowAxisMask
= GYRO_OVERFLOW_Z
;
514 } else if (gyroConfig()->checkOverflow
== GYRO_OVERFLOW_CHECK_ALL_AXES
) {
515 overflowAxisMask
= GYRO_OVERFLOW_X
| GYRO_OVERFLOW_Y
| GYRO_OVERFLOW_Z
;
517 overflowAxisMask
= 0;
525 case DEBUG_GYRO_SCALED
:
526 case DEBUG_GYRO_FILTERED
:
527 gyroDebugMode
= debugMode
;
530 // debugMode is not gyro-related
531 gyroDebugMode
= DEBUG_NONE
;
534 firstArmingCalibrationWasStarted
= false;
537 memset(&gyro
, 0, sizeof(gyro
));
538 gyroToUse
= gyroConfig()->gyro_to_use
;
540 #if defined(USE_DUAL_GYRO) && defined(GYRO_1_CS_PIN)
541 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_1
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
542 gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
= IOGetByTag(IO_TAG(GYRO_1_CS_PIN
));
543 IOInit(gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, OWNER_MPU_CS
, RESOURCE_INDEX(0));
544 IOHi(gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
); // Ensure device is disabled, important when two devices are on the same bus.
545 IOConfigGPIO(gyroSensor1
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, SPI_IO_CS_CFG
);
549 #if defined(USE_DUAL_GYRO) && defined(GYRO_2_CS_PIN)
550 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
551 gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
= IOGetByTag(IO_TAG(GYRO_2_CS_PIN
));
552 IOInit(gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, OWNER_MPU_CS
, RESOURCE_INDEX(1));
553 IOHi(gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
); // Ensure device is disabled, important when two devices are on the same bus.
554 IOConfigGPIO(gyroSensor2
.gyroDev
.bus
.busdev_u
.spi
.csnPin
, SPI_IO_CS_CFG
);
558 gyroSensor1
.gyroDev
.gyroAlign
= ALIGN_DEFAULT
;
560 #if defined(GYRO_1_EXTI_PIN)
561 gyroSensor1
.gyroDev
.mpuIntExtiTag
= IO_TAG(GYRO_1_EXTI_PIN
);
562 #elif defined(MPU_INT_EXTI)
563 gyroSensor1
.gyroDev
.mpuIntExtiTag
= IO_TAG(MPU_INT_EXTI
);
564 #elif defined(USE_HARDWARE_REVISION_DETECTION)
565 gyroSensor1
.gyroDev
.mpuIntExtiTag
= selectMPUIntExtiConfigByHardwareRevision();
567 gyroSensor1
.gyroDev
.mpuIntExtiTag
= IO_TAG_NONE
;
568 #endif // GYRO_1_EXTI_PIN
571 gyroSensor1
.gyroDev
.gyroAlign
= GYRO_1_ALIGN
;
573 gyroSensor1
.gyroDev
.bus
.bustype
= BUSTYPE_SPI
;
574 spiBusSetInstance(&gyroSensor1
.gyroDev
.bus
, GYRO_1_SPI_INSTANCE
);
575 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_1
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
576 ret
= gyroInitSensor(&gyroSensor1
);
578 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.
580 gyroHasOverflowProtection
= gyroHasOverflowProtection
&& gyroSensor1
.gyroDev
.gyroHasOverflowProtection
;
582 #else // USE_DUAL_GYRO
583 ret
= gyroInitSensor(&gyroSensor1
);
584 gyroHasOverflowProtection
= gyroHasOverflowProtection
&& gyroSensor1
.gyroDev
.gyroHasOverflowProtection
;
585 #endif // USE_DUAL_GYRO
589 gyroSensor2
.gyroDev
.gyroAlign
= ALIGN_DEFAULT
;
591 #if defined(GYRO_2_EXTI_PIN)
592 gyroSensor2
.gyroDev
.mpuIntExtiTag
= IO_TAG(GYRO_2_EXTI_PIN
);
593 #elif defined(USE_HARDWARE_REVISION_DETECTION)
594 gyroSensor2
.gyroDev
.mpuIntExtiTag
= selectMPUIntExtiConfigByHardwareRevision();
596 gyroSensor2
.gyroDev
.mpuIntExtiTag
= IO_TAG_NONE
;
597 #endif // GYRO_2_EXTI_PIN
599 gyroSensor2
.gyroDev
.gyroAlign
= GYRO_2_ALIGN
;
601 gyroSensor2
.gyroDev
.bus
.bustype
= BUSTYPE_SPI
;
602 spiBusSetInstance(&gyroSensor2
.gyroDev
.bus
, GYRO_2_SPI_INSTANCE
);
603 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
|| gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
604 ret
= gyroInitSensor(&gyroSensor2
);
606 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.
608 gyroHasOverflowProtection
= gyroHasOverflowProtection
&& gyroSensor2
.gyroDev
.gyroHasOverflowProtection
;
610 #endif // USE_DUAL_GYRO
613 // Only allow using both gyros simultaneously if they are the same hardware type.
614 // If the user selected "BOTH" and they are not the same type, then reset to using only the first gyro.
615 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
616 if (gyroSensor1
.gyroDev
.gyroHardware
!= gyroSensor2
.gyroDev
.gyroHardware
) {
617 gyroToUse
= GYRO_CONFIG_USE_GYRO_1
;
618 gyroConfigMutable()->gyro_to_use
= GYRO_CONFIG_USE_GYRO_1
;
619 detectedSensors
[SENSOR_INDEX_GYRO
] = gyroSensor1
.gyroDev
.gyroHardware
;
620 sensorsSet(SENSOR_GYRO
);
624 #endif // USE_DUAL_GYRO
628 void gyroInitLowpassFilterLpf(gyroSensor_t
*gyroSensor
, int slot
, int type
, uint16_t lpfHz
)
630 filterApplyFnPtr
*lowpassFilterApplyFn
;
631 gyroLowpassFilter_t
*lowpassFilter
= NULL
;
635 lowpassFilterApplyFn
= &gyroSensor
->lowpassFilterApplyFn
;
636 lowpassFilter
= gyroSensor
->lowpassFilter
;
639 case FILTER_LOWPASS2
:
640 lowpassFilterApplyFn
= &gyroSensor
->lowpass2FilterApplyFn
;
641 lowpassFilter
= gyroSensor
->lowpass2Filter
;
648 // Establish some common constants
649 const uint32_t gyroFrequencyNyquist
= 1000000 / 2 / gyro
.targetLooptime
;
650 const float gyroDt
= gyro
.targetLooptime
* 1e-6f
;
652 // Gain could be calculated a little later as it is specific to the pt1/bqrcf2/fkf branches
653 const float gain
= pt1FilterGain(lpfHz
, gyroDt
);
655 // Dereference the pointer to null before checking valid cutoff and filter
656 // type. It will be overridden for positive cases.
657 *lowpassFilterApplyFn
= &nullFilterApply
;
659 // If lowpass cutoff has been specified and is less than the Nyquist frequency
660 if (lpfHz
&& lpfHz
<= gyroFrequencyNyquist
) {
663 *lowpassFilterApplyFn
= (filterApplyFnPtr
) pt1FilterApply
;
664 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
665 pt1FilterInit(&lowpassFilter
[axis
].pt1FilterState
, gain
);
669 *lowpassFilterApplyFn
= (filterApplyFnPtr
) biquadFilterApply
;
670 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
671 biquadFilterInitLPF(&lowpassFilter
[axis
].biquadFilterState
, lpfHz
, gyro
.targetLooptime
);
678 static uint16_t calculateNyquistAdjustedNotchHz(uint16_t notchHz
, uint16_t notchCutoffHz
)
680 const uint32_t gyroFrequencyNyquist
= 1000000 / 2 / gyro
.targetLooptime
;
681 if (notchHz
> gyroFrequencyNyquist
) {
682 if (notchCutoffHz
< gyroFrequencyNyquist
) {
683 notchHz
= gyroFrequencyNyquist
;
692 #if defined(USE_GYRO_SLEW_LIMITER)
693 void gyroInitSlewLimiter(gyroSensor_t
*gyroSensor
) {
695 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
696 gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
] = 0;
701 static void gyroInitFilterNotch1(gyroSensor_t
*gyroSensor
, uint16_t notchHz
, uint16_t notchCutoffHz
)
703 gyroSensor
->notchFilter1ApplyFn
= nullFilterApply
;
705 notchHz
= calculateNyquistAdjustedNotchHz(notchHz
, notchCutoffHz
);
707 if (notchHz
!= 0 && notchCutoffHz
!= 0) {
708 gyroSensor
->notchFilter1ApplyFn
= (filterApplyFnPtr
)biquadFilterApply
;
709 const float notchQ
= filterGetNotchQ(notchHz
, notchCutoffHz
);
710 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
711 biquadFilterInit(&gyroSensor
->notchFilter1
[axis
], notchHz
, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
);
716 static void gyroInitFilterNotch2(gyroSensor_t
*gyroSensor
, uint16_t notchHz
, uint16_t notchCutoffHz
)
718 gyroSensor
->notchFilter2ApplyFn
= nullFilterApply
;
720 notchHz
= calculateNyquistAdjustedNotchHz(notchHz
, notchCutoffHz
);
722 if (notchHz
!= 0 && notchCutoffHz
!= 0) {
723 gyroSensor
->notchFilter2ApplyFn
= (filterApplyFnPtr
)biquadFilterApply
;
724 const float notchQ
= filterGetNotchQ(notchHz
, notchCutoffHz
);
725 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
726 biquadFilterInit(&gyroSensor
->notchFilter2
[axis
], notchHz
, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
);
731 #ifdef USE_GYRO_DATA_ANALYSE
732 static bool isDynamicFilterActive(void)
734 return feature(FEATURE_DYNAMIC_FILTER
);
737 static void gyroInitFilterDynamicNotch(gyroSensor_t
*gyroSensor
)
739 gyroSensor
->notchFilterDynApplyFn
= nullFilterApply
;
741 if (isDynamicFilterActive()) {
742 gyroSensor
->notchFilterDynApplyFn
= (filterApplyFnPtr
)biquadFilterApplyDF1
; // must be this function, not DF2
743 const float notchQ
= filterGetNotchQ(400, 390); //just any init value
744 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
745 biquadFilterInit(&gyroSensor
->notchFilterDyn
[axis
], 400, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
);
752 static void gyroInitSensorFilters(gyroSensor_t
*gyroSensor
)
754 #if defined(USE_GYRO_SLEW_LIMITER)
755 gyroInitSlewLimiter(gyroSensor
);
758 gyroInitLowpassFilterLpf(
761 gyroConfig()->gyro_lowpass_type
,
762 gyroConfig()->gyro_lowpass_hz
765 gyroInitLowpassFilterLpf(
768 gyroConfig()->gyro_lowpass2_type
,
769 gyroConfig()->gyro_lowpass2_hz
772 gyroInitFilterNotch1(gyroSensor
, gyroConfig()->gyro_soft_notch_hz_1
, gyroConfig()->gyro_soft_notch_cutoff_1
);
773 gyroInitFilterNotch2(gyroSensor
, gyroConfig()->gyro_soft_notch_hz_2
, gyroConfig()->gyro_soft_notch_cutoff_2
);
774 #ifdef USE_GYRO_DATA_ANALYSE
775 gyroInitFilterDynamicNotch(gyroSensor
);
779 void gyroInitFilters(void)
781 gyroInitSensorFilters(&gyroSensor1
);
783 gyroInitSensorFilters(&gyroSensor2
);
787 FAST_CODE
bool isGyroSensorCalibrationComplete(const gyroSensor_t
*gyroSensor
)
789 return gyroSensor
->calibration
.cyclesRemaining
== 0;
792 FAST_CODE
bool isGyroCalibrationComplete(void)
797 case GYRO_CONFIG_USE_GYRO_1
: {
798 return isGyroSensorCalibrationComplete(&gyroSensor1
);
800 case GYRO_CONFIG_USE_GYRO_2
: {
801 return isGyroSensorCalibrationComplete(&gyroSensor2
);
803 case GYRO_CONFIG_USE_GYRO_BOTH
: {
804 return isGyroSensorCalibrationComplete(&gyroSensor1
) && isGyroSensorCalibrationComplete(&gyroSensor2
);
808 return isGyroSensorCalibrationComplete(&gyroSensor1
);
812 static bool isOnFinalGyroCalibrationCycle(const gyroCalibration_t
*gyroCalibration
)
814 return gyroCalibration
->cyclesRemaining
== 1;
817 static int32_t gyroCalculateCalibratingCycles(void)
819 return (gyroConfig()->gyroCalibrationDuration
* 10000) / gyro
.targetLooptime
;
822 static bool isOnFirstGyroCalibrationCycle(const gyroCalibration_t
*gyroCalibration
)
824 return gyroCalibration
->cyclesRemaining
== gyroCalculateCalibratingCycles();
827 static void gyroSetCalibrationCycles(gyroSensor_t
*gyroSensor
)
829 gyroSensor
->calibration
.cyclesRemaining
= gyroCalculateCalibratingCycles();
832 void gyroStartCalibration(bool isFirstArmingCalibration
)
834 if (!(isFirstArmingCalibration
&& firstArmingCalibrationWasStarted
)) {
835 gyroSetCalibrationCycles(&gyroSensor1
);
837 gyroSetCalibrationCycles(&gyroSensor2
);
840 if (isFirstArmingCalibration
) {
841 firstArmingCalibrationWasStarted
= true;
846 bool isFirstArmingGyroCalibrationRunning(void)
848 return firstArmingCalibrationWasStarted
&& !isGyroCalibrationComplete();
851 STATIC_UNIT_TESTED
void performGyroCalibration(gyroSensor_t
*gyroSensor
, uint8_t gyroMovementCalibrationThreshold
)
853 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
854 // Reset g[axis] at start of calibration
855 if (isOnFirstGyroCalibrationCycle(&gyroSensor
->calibration
)) {
856 gyroSensor
->calibration
.sum
[axis
] = 0.0f
;
857 devClear(&gyroSensor
->calibration
.var
[axis
]);
858 // gyroZero is set to zero until calibration complete
859 gyroSensor
->gyroDev
.gyroZero
[axis
] = 0.0f
;
862 // Sum up CALIBRATING_GYRO_TIME_US readings
863 gyroSensor
->calibration
.sum
[axis
] += gyroSensor
->gyroDev
.gyroADCRaw
[axis
];
864 devPush(&gyroSensor
->calibration
.var
[axis
], gyroSensor
->gyroDev
.gyroADCRaw
[axis
]);
866 if (isOnFinalGyroCalibrationCycle(&gyroSensor
->calibration
)) {
867 const float stddev
= devStandardDeviation(&gyroSensor
->calibration
.var
[axis
]);
868 // DEBUG_GYRO_CALIBRATION records the standard deviation of roll
869 // into the spare field - debug[3], in DEBUG_GYRO_RAW
871 DEBUG_SET(DEBUG_GYRO_RAW
, DEBUG_GYRO_CALIBRATION
, lrintf(stddev
));
874 // check deviation and startover in case the model was moved
875 if (gyroMovementCalibrationThreshold
&& stddev
> gyroMovementCalibrationThreshold
) {
876 gyroSetCalibrationCycles(gyroSensor
);
880 // please take care with exotic boardalignment !!
881 gyroSensor
->gyroDev
.gyroZero
[axis
] = gyroSensor
->calibration
.sum
[axis
] / gyroCalculateCalibratingCycles();
883 gyroSensor
->gyroDev
.gyroZero
[axis
] -= ((float)gyroConfig()->gyro_offset_yaw
/ 100);
888 if (isOnFinalGyroCalibrationCycle(&gyroSensor
->calibration
)) {
889 schedulerResetTaskStatistics(TASK_SELF
); // so calibration cycles do not pollute tasks statistics
890 if (!firstArmingCalibrationWasStarted
|| (getArmingDisableFlags() & ~ARMING_DISABLED_CALIBRATING
) == 0) {
891 beeper(BEEPER_GYRO_CALIBRATED
);
894 --gyroSensor
->calibration
.cyclesRemaining
;
898 #if defined(USE_GYRO_SLEW_LIMITER)
899 FAST_CODE
int32_t gyroSlewLimiter(gyroSensor_t
*gyroSensor
, int axis
)
901 int32_t ret
= (int32_t)gyroSensor
->gyroDev
.gyroADCRaw
[axis
];
902 if (gyroConfig()->checkOverflow
|| gyroHasOverflowProtection
) {
903 // don't use the slew limiter if overflow checking is on or gyro is not subject to overflow bug
906 if (abs(ret
- gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
]) > (1<<14)) {
907 // there has been a large change in value, so assume overflow has occurred and return the previous value
908 ret
= gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
];
910 gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
] = ret
;
916 #ifdef USE_GYRO_OVERFLOW_CHECK
917 static FAST_CODE_NOINLINE
void handleOverflow(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
919 const float gyroOverflowResetRate
= GYRO_OVERFLOW_RESET_THRESHOLD
* gyroSensor
->gyroDev
.scale
;
920 if ((abs(gyro
.gyroADCf
[X
]) < gyroOverflowResetRate
)
921 && (abs(gyro
.gyroADCf
[Y
]) < gyroOverflowResetRate
)
922 && (abs(gyro
.gyroADCf
[Z
]) < gyroOverflowResetRate
)) {
923 // if we have 50ms of consecutive OK gyro vales, then assume yaw readings are OK again and reset overflowDetected
924 // reset requires good OK values on all axes
925 if (cmpTimeUs(currentTimeUs
, gyroSensor
->overflowTimeUs
) > 50000) {
926 gyroSensor
->overflowDetected
= false;
929 // not a consecutive OK value, so reset the overflow time
930 gyroSensor
->overflowTimeUs
= currentTimeUs
;
934 static FAST_CODE
void checkForOverflow(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
936 // check for overflow to handle Yaw Spin To The Moon (YSTTM)
937 // ICM gyros are specified to +/- 2000 deg/sec, in a crash they can go out of spec.
938 // This can cause an overflow and sign reversal in the output.
939 // Overflow and sign reversal seems to result in a gyro value of +1996 or -1996.
940 if (gyroSensor
->overflowDetected
) {
941 handleOverflow(gyroSensor
, currentTimeUs
);
943 #ifndef SIMULATOR_BUILD
944 // check for overflow in the axes set in overflowAxisMask
945 gyroOverflow_e overflowCheck
= GYRO_OVERFLOW_NONE
;
946 const float gyroOverflowTriggerRate
= GYRO_OVERFLOW_TRIGGER_THRESHOLD
* gyroSensor
->gyroDev
.scale
;
947 if (abs(gyro
.gyroADCf
[X
]) > gyroOverflowTriggerRate
) {
948 overflowCheck
|= GYRO_OVERFLOW_X
;
950 if (abs(gyro
.gyroADCf
[Y
]) > gyroOverflowTriggerRate
) {
951 overflowCheck
|= GYRO_OVERFLOW_Y
;
953 if (abs(gyro
.gyroADCf
[Z
]) > gyroOverflowTriggerRate
) {
954 overflowCheck
|= GYRO_OVERFLOW_Z
;
956 if (overflowCheck
& overflowAxisMask
) {
957 gyroSensor
->overflowDetected
= true;
958 gyroSensor
->overflowTimeUs
= currentTimeUs
;
959 #ifdef USE_YAW_SPIN_RECOVERY
960 gyroSensor
->yawSpinDetected
= false;
961 #endif // USE_YAW_SPIN_RECOVERY
963 #endif // SIMULATOR_BUILD
966 #endif // USE_GYRO_OVERFLOW_CHECK
968 #ifdef USE_YAW_SPIN_RECOVERY
969 static FAST_CODE_NOINLINE
void handleYawSpin(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
971 const float yawSpinResetRate
= gyroConfig()->yaw_spin_threshold
- 100.0f
;
972 if (abs(gyro
.gyroADCf
[Z
]) < yawSpinResetRate
) {
973 // testing whether 20ms of consecutive OK gyro yaw values is enough
974 if (cmpTimeUs(currentTimeUs
, gyroSensor
->yawSpinTimeUs
) > 20000) {
975 gyroSensor
->yawSpinDetected
= false;
978 // reset the yaw spin time
979 gyroSensor
->yawSpinTimeUs
= currentTimeUs
;
983 static FAST_CODE
void checkForYawSpin(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
985 // if not in overflow mode, handle yaw spins above threshold
986 #ifdef USE_GYRO_OVERFLOW_CHECK
987 if (gyroSensor
->overflowDetected
) {
988 gyroSensor
->yawSpinDetected
= false;
991 #endif // USE_GYRO_OVERFLOW_CHECK
993 if (gyroSensor
->yawSpinDetected
) {
994 handleYawSpin(gyroSensor
, currentTimeUs
);
996 #ifndef SIMULATOR_BUILD
997 // check for spin on yaw axis only
998 if (abs(gyro
.gyroADCf
[Z
]) > gyroConfig()->yaw_spin_threshold
) {
999 gyroSensor
->yawSpinDetected
= true;
1000 gyroSensor
->yawSpinTimeUs
= currentTimeUs
;
1002 #endif // SIMULATOR_BUILD
1005 #endif // USE_YAW_SPIN_RECOVERY
1007 #define GYRO_FILTER_FUNCTION_NAME filterGyro
1008 #define GYRO_FILTER_DEBUG_SET(...)
1009 #include "gyro_filter_impl.h"
1010 #undef GYRO_FILTER_FUNCTION_NAME
1011 #undef GYRO_FILTER_DEBUG_SET
1013 #define GYRO_FILTER_FUNCTION_NAME filterGyroDebug
1014 #define GYRO_FILTER_DEBUG_SET DEBUG_SET
1015 #include "gyro_filter_impl.h"
1016 #undef GYRO_FILTER_FUNCTION_NAME
1017 #undef GYRO_FILTER_DEBUG_SET
1019 static FAST_CODE FAST_CODE_NOINLINE
void gyroUpdateSensor(gyroSensor_t
*gyroSensor
, timeUs_t currentTimeUs
)
1021 if (!gyroSensor
->gyroDev
.readFn(&gyroSensor
->gyroDev
)) {
1024 gyroSensor
->gyroDev
.dataReady
= false;
1026 if (isGyroSensorCalibrationComplete(gyroSensor
)) {
1027 // move 16-bit gyro data into 32-bit variables to avoid overflows in calculations
1029 #if defined(USE_GYRO_SLEW_LIMITER)
1030 gyroSensor
->gyroDev
.gyroADC
[X
] = gyroSlewLimiter(gyroSensor
, X
) - gyroSensor
->gyroDev
.gyroZero
[X
];
1031 gyroSensor
->gyroDev
.gyroADC
[Y
] = gyroSlewLimiter(gyroSensor
, Y
) - gyroSensor
->gyroDev
.gyroZero
[Y
];
1032 gyroSensor
->gyroDev
.gyroADC
[Z
] = gyroSlewLimiter(gyroSensor
, Z
) - gyroSensor
->gyroDev
.gyroZero
[Z
];
1034 gyroSensor
->gyroDev
.gyroADC
[X
] = gyroSensor
->gyroDev
.gyroADCRaw
[X
] - gyroSensor
->gyroDev
.gyroZero
[X
];
1035 gyroSensor
->gyroDev
.gyroADC
[Y
] = gyroSensor
->gyroDev
.gyroADCRaw
[Y
] - gyroSensor
->gyroDev
.gyroZero
[Y
];
1036 gyroSensor
->gyroDev
.gyroADC
[Z
] = gyroSensor
->gyroDev
.gyroADCRaw
[Z
] - gyroSensor
->gyroDev
.gyroZero
[Z
];
1039 alignSensors(gyroSensor
->gyroDev
.gyroADC
, gyroSensor
->gyroDev
.gyroAlign
);
1041 performGyroCalibration(gyroSensor
, gyroConfig()->gyroMovementCalibrationThreshold
);
1042 // still calibrating, so no need to further process gyro data
1046 const timeDelta_t sampleDeltaUs
= currentTimeUs
- accumulationLastTimeSampledUs
;
1047 accumulationLastTimeSampledUs
= currentTimeUs
;
1048 accumulatedMeasurementTimeUs
+= sampleDeltaUs
;
1050 #ifdef USE_GYRO_OVERFLOW_CHECK
1051 if (gyroConfig()->checkOverflow
&& !gyroHasOverflowProtection
) {
1052 checkForOverflow(gyroSensor
, currentTimeUs
);
1056 #ifdef USE_YAW_SPIN_RECOVERY
1057 if (gyroConfig()->yaw_spin_recovery
) {
1058 checkForYawSpin(gyroSensor
, currentTimeUs
);
1062 if (gyroDebugMode
== DEBUG_NONE
) {
1063 filterGyro(gyroSensor
, sampleDeltaUs
);
1065 filterGyroDebug(gyroSensor
, sampleDeltaUs
);
1067 #ifdef USE_GYRO_DATA_ANALYSE
1068 if (isDynamicFilterActive()) {
1069 gyroDataAnalyse(gyroSensor
->notchFilterDyn
);
1074 FAST_CODE
void gyroUpdate(timeUs_t currentTimeUs
)
1076 #ifdef USE_DUAL_GYRO
1077 switch (gyroToUse
) {
1078 case GYRO_CONFIG_USE_GYRO_1
:
1079 gyroUpdateSensor(&gyroSensor1
, currentTimeUs
);
1080 if (isGyroSensorCalibrationComplete(&gyroSensor1
)) {
1081 gyro
.gyroADCf
[X
] = gyroSensor1
.gyroDev
.gyroADCf
[X
];
1082 gyro
.gyroADCf
[Y
] = gyroSensor1
.gyroDev
.gyroADCf
[Y
];
1083 gyro
.gyroADCf
[Z
] = gyroSensor1
.gyroDev
.gyroADCf
[Z
];
1085 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 0, gyroSensor1
.gyroDev
.gyroADCRaw
[X
]);
1086 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 1, gyroSensor1
.gyroDev
.gyroADCRaw
[Y
]);
1087 DEBUG_SET(DEBUG_DUAL_GYRO
, 0, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[X
]));
1088 DEBUG_SET(DEBUG_DUAL_GYRO
, 1, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Y
]));
1089 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 0, lrintf(gyro
.gyroADCf
[X
]));
1090 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 1, lrintf(gyro
.gyroADCf
[Y
]));
1092 case GYRO_CONFIG_USE_GYRO_2
:
1093 gyroUpdateSensor(&gyroSensor2
, currentTimeUs
);
1094 if (isGyroSensorCalibrationComplete(&gyroSensor2
)) {
1095 gyro
.gyroADCf
[X
] = gyroSensor2
.gyroDev
.gyroADCf
[X
];
1096 gyro
.gyroADCf
[Y
] = gyroSensor2
.gyroDev
.gyroADCf
[Y
];
1097 gyro
.gyroADCf
[Z
] = gyroSensor2
.gyroDev
.gyroADCf
[Z
];
1099 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 2, gyroSensor2
.gyroDev
.gyroADCRaw
[X
]);
1100 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 3, gyroSensor2
.gyroDev
.gyroADCRaw
[Y
]);
1101 DEBUG_SET(DEBUG_DUAL_GYRO
, 2, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[X
]));
1102 DEBUG_SET(DEBUG_DUAL_GYRO
, 3, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[Y
]));
1103 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 2, lrintf(gyro
.gyroADCf
[X
]));
1104 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 3, lrintf(gyro
.gyroADCf
[Y
]));
1106 case GYRO_CONFIG_USE_GYRO_BOTH
:
1107 gyroUpdateSensor(&gyroSensor1
, currentTimeUs
);
1108 gyroUpdateSensor(&gyroSensor2
, currentTimeUs
);
1109 if (isGyroSensorCalibrationComplete(&gyroSensor1
) && isGyroSensorCalibrationComplete(&gyroSensor2
)) {
1110 gyro
.gyroADCf
[X
] = (gyroSensor1
.gyroDev
.gyroADCf
[X
] + gyroSensor2
.gyroDev
.gyroADCf
[X
]) / 2.0f
;
1111 gyro
.gyroADCf
[Y
] = (gyroSensor1
.gyroDev
.gyroADCf
[Y
] + gyroSensor2
.gyroDev
.gyroADCf
[Y
]) / 2.0f
;
1112 gyro
.gyroADCf
[Z
] = (gyroSensor1
.gyroDev
.gyroADCf
[Z
] + gyroSensor2
.gyroDev
.gyroADCf
[Z
]) / 2.0f
;
1114 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 0, gyroSensor1
.gyroDev
.gyroADCRaw
[X
]);
1115 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 1, gyroSensor1
.gyroDev
.gyroADCRaw
[Y
]);
1116 DEBUG_SET(DEBUG_DUAL_GYRO
, 0, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[X
]));
1117 DEBUG_SET(DEBUG_DUAL_GYRO
, 1, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Y
]));
1118 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 2, gyroSensor2
.gyroDev
.gyroADCRaw
[X
]);
1119 DEBUG_SET(DEBUG_DUAL_GYRO_RAW
, 3, gyroSensor2
.gyroDev
.gyroADCRaw
[Y
]);
1120 DEBUG_SET(DEBUG_DUAL_GYRO
, 2, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[X
]));
1121 DEBUG_SET(DEBUG_DUAL_GYRO
, 3, lrintf(gyroSensor2
.gyroDev
.gyroADCf
[Y
]));
1122 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 1, lrintf(gyro
.gyroADCf
[X
]));
1123 DEBUG_SET(DEBUG_DUAL_GYRO_COMBINE
, 2, lrintf(gyro
.gyroADCf
[Y
]));
1124 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF
, 0, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[X
] - gyroSensor2
.gyroDev
.gyroADCf
[X
]));
1125 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF
, 1, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Y
] - gyroSensor2
.gyroDev
.gyroADCf
[Y
]));
1126 DEBUG_SET(DEBUG_DUAL_GYRO_DIFF
, 2, lrintf(gyroSensor1
.gyroDev
.gyroADCf
[Z
] - gyroSensor2
.gyroDev
.gyroADCf
[Z
]));
1130 gyroUpdateSensor(&gyroSensor1
, currentTimeUs
);
1131 gyro
.gyroADCf
[X
] = gyroSensor1
.gyroDev
.gyroADCf
[X
];
1132 gyro
.gyroADCf
[Y
] = gyroSensor1
.gyroDev
.gyroADCf
[Y
];
1133 gyro
.gyroADCf
[Z
] = gyroSensor1
.gyroDev
.gyroADCf
[Z
];
1137 bool gyroGetAccumulationAverage(float *accumulationAverage
)
1139 if (accumulatedMeasurementTimeUs
> 0) {
1140 // If we have gyro data accumulated, calculate average rate that will yield the same rotation
1141 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
1142 accumulationAverage
[axis
] = accumulatedMeasurements
[axis
] / accumulatedMeasurementTimeUs
;
1143 accumulatedMeasurements
[axis
] = 0.0f
;
1145 accumulatedMeasurementTimeUs
= 0;
1148 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
1149 accumulationAverage
[axis
] = 0.0f
;
1155 void gyroReadTemperature(void)
1157 if (gyroSensor1
.gyroDev
.temperatureFn
) {
1158 gyroSensor1
.gyroDev
.temperatureFn(&gyroSensor1
.gyroDev
, &gyroSensor1
.gyroDev
.temperature
);
1162 int16_t gyroGetTemperature(void)
1164 return gyroSensor1
.gyroDev
.temperature
;
1167 int16_t gyroRateDps(int axis
)
1169 #ifdef USE_DUAL_GYRO
1170 if (gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
1171 return lrintf(gyro
.gyroADCf
[axis
] / gyroSensor2
.gyroDev
.scale
);
1173 return lrintf(gyro
.gyroADCf
[axis
] / gyroSensor1
.gyroDev
.scale
);
1176 return lrintf(gyro
.gyroADCf
[axis
] / gyroSensor1
.gyroDev
.scale
);
1180 bool gyroOverflowDetected(void)
1182 return gyroSensor1
.overflowDetected
;
1185 #ifdef USE_YAW_SPIN_RECOVERY
1186 bool gyroYawSpinDetected(void)
1188 return gyroSensor1
.yawSpinDetected
;
1190 #endif // USE_YAW_SPIN_RECOVERY
1192 uint16_t gyroAbsRateDps(int axis
)
1194 return fabsf(gyro
.gyroADCf
[axis
]);
1197 #ifdef USE_GYRO_REGISTER_DUMP
1198 uint8_t gyroReadRegister(uint8_t whichSensor
, uint8_t reg
)
1200 return mpuGyroReadRegister(gyroSensorBusByDevice(whichSensor
), reg
);
1202 #endif // USE_GYRO_REGISTER_DUMP