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/config.h"
37 #include "drivers/accgyro/accgyro.h"
38 #include "drivers/accgyro/accgyro_virtual.h"
39 #include "drivers/accgyro/accgyro_mpu.h"
40 #include "drivers/accgyro/accgyro_mpu3050.h"
41 #include "drivers/accgyro/accgyro_mpu6050.h"
42 #include "drivers/accgyro/accgyro_mpu6500.h"
43 #include "drivers/accgyro/accgyro_spi_bmi160.h"
44 #include "drivers/accgyro/accgyro_spi_bmi270.h"
45 #include "drivers/accgyro/accgyro_spi_icm20649.h"
46 #include "drivers/accgyro/accgyro_spi_icm20689.h"
47 #include "drivers/accgyro/accgyro_spi_icm426xx.h"
48 #include "drivers/accgyro/accgyro_spi_lsm6dso.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"
52 #include "drivers/accgyro/accgyro_spi_lsm6dsv16x.h"
54 #ifdef USE_GYRO_L3GD20
55 #include "drivers/accgyro/accgyro_spi_l3gd20.h"
58 #ifdef USE_GYRO_L3G4200D
59 #include "drivers/accgyro/legacy/accgyro_l3g4200d.h"
62 #include "drivers/accgyro/gyro_sync.h"
64 #include "fc/runtime_config.h"
66 #ifdef USE_DYN_NOTCH_FILTER
67 #include "flight/dyn_notch_filter.h"
70 #include "pg/gyrodev.h"
72 #include "sensors/gyro.h"
73 #include "sensors/sensors.h"
75 #if !defined(USE_GYRO_L3G4200D) && !defined(USE_GYRO_L3GD20) \
76 && !defined(USE_GYRO_MPU3050) && !defined(USE_GYRO_MPU6050) && !defined(USE_GYRO_MPU6500) \
77 && !defined(USE_GYRO_SPI_MPU6000) && !defined(USE_GYRO_SPI_MPU6500) && !defined(USE_GYRO_SPI_MPU9250) \
78 && !defined(USE_GYRO_SPI_ICM20602) && !defined(USE_GYRO_SPI_ICM20649) && !defined(USE_GYRO_SPI_ICM20689) \
79 && !defined(USE_ACCGYRO_BMI160) && !defined(USE_ACCGYRO_BMI270) \
80 && !defined(USE_GYRO_SPI_ICM42605) && !defined(USE_GYRO_SPI_ICM42688P) \
81 && !defined(USE_ACCGYRO_LSM6DSO) && !defined(USE_ACCGYRO_LSM6DSV16X) \
82 && !defined(USE_VIRTUAL_GYRO)
83 #error At least one USE_GYRO device definition required
87 #define ACTIVE_GYRO ((gyro.gyroToUse == GYRO_CONFIG_USE_GYRO_2) ? &gyro.gyroSensor2 : &gyro.gyroSensor1)
89 #define ACTIVE_GYRO (&gyro.gyroSensor1)
92 // The gyro buffer is split 50/50, the first half for the transmit buffer, the second half for the receive buffer
93 // This buffer is large enough for the gyros currently supported in accgyro_mpu.c but should be reviewed id other
94 // gyro types are supported with SPI DMA.
95 #define GYRO_BUF_SIZE 32
97 static gyroDetectionFlags_t gyroDetectionFlags
= GYRO_NONE_MASK
;
99 static uint16_t calculateNyquistAdjustedNotchHz(uint16_t notchHz
, uint16_t notchCutoffHz
)
101 const uint32_t gyroFrequencyNyquist
= 1000000 / 2 / gyro
.targetLooptime
;
102 if (notchHz
> gyroFrequencyNyquist
) {
103 if (notchCutoffHz
< gyroFrequencyNyquist
) {
104 notchHz
= gyroFrequencyNyquist
;
113 static void gyroInitFilterNotch1(uint16_t notchHz
, uint16_t notchCutoffHz
)
115 gyro
.notchFilter1ApplyFn
= nullFilterApply
;
117 notchHz
= calculateNyquistAdjustedNotchHz(notchHz
, notchCutoffHz
);
119 if (notchHz
!= 0 && notchCutoffHz
!= 0) {
120 gyro
.notchFilter1ApplyFn
= (filterApplyFnPtr
)biquadFilterApply
;
121 const float notchQ
= filterGetNotchQ(notchHz
, notchCutoffHz
);
122 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
123 biquadFilterInit(&gyro
.notchFilter1
[axis
], notchHz
, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
, 1.0f
);
128 static void gyroInitFilterNotch2(uint16_t notchHz
, uint16_t notchCutoffHz
)
130 gyro
.notchFilter2ApplyFn
= nullFilterApply
;
132 notchHz
= calculateNyquistAdjustedNotchHz(notchHz
, notchCutoffHz
);
134 if (notchHz
!= 0 && notchCutoffHz
!= 0) {
135 gyro
.notchFilter2ApplyFn
= (filterApplyFnPtr
)biquadFilterApply
;
136 const float notchQ
= filterGetNotchQ(notchHz
, notchCutoffHz
);
137 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
138 biquadFilterInit(&gyro
.notchFilter2
[axis
], notchHz
, gyro
.targetLooptime
, notchQ
, FILTER_NOTCH
, 1.0f
);
143 static bool gyroInitLowpassFilterLpf(int slot
, int type
, uint16_t lpfHz
, uint32_t looptime
)
145 filterApplyFnPtr
*lowpassFilterApplyFn
;
146 gyroLowpassFilter_t
*lowpassFilter
= NULL
;
150 lowpassFilterApplyFn
= &gyro
.lowpassFilterApplyFn
;
151 lowpassFilter
= gyro
.lowpassFilter
;
155 lowpassFilterApplyFn
= &gyro
.lowpass2FilterApplyFn
;
156 lowpassFilter
= gyro
.lowpass2Filter
;
165 // Establish some common constants
166 const uint32_t gyroFrequencyNyquist
= 1000000 / 2 / looptime
;
167 const float gyroDt
= looptime
* 1e-6f
;
169 // Dereference the pointer to null before checking valid cutoff and filter
170 // type. It will be overridden for positive cases.
171 *lowpassFilterApplyFn
= nullFilterApply
;
173 // If lowpass cutoff has been specified
177 *lowpassFilterApplyFn
= (filterApplyFnPtr
) pt1FilterApply
;
178 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
179 pt1FilterInit(&lowpassFilter
[axis
].pt1FilterState
, pt1FilterGain(lpfHz
, gyroDt
));
184 if (lpfHz
<= gyroFrequencyNyquist
) {
186 *lowpassFilterApplyFn
= (filterApplyFnPtr
) biquadFilterApplyDF1
;
188 *lowpassFilterApplyFn
= (filterApplyFnPtr
) biquadFilterApply
;
190 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
191 biquadFilterInitLPF(&lowpassFilter
[axis
].biquadFilterState
, lpfHz
, looptime
);
197 *lowpassFilterApplyFn
= (filterApplyFnPtr
) pt2FilterApply
;
198 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
199 pt2FilterInit(&lowpassFilter
[axis
].pt2FilterState
, pt2FilterGain(lpfHz
, gyroDt
));
204 *lowpassFilterApplyFn
= (filterApplyFnPtr
) pt3FilterApply
;
205 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
206 pt3FilterInit(&lowpassFilter
[axis
].pt3FilterState
, pt3FilterGain(lpfHz
, gyroDt
));
216 static void dynLpfFilterInit(void)
218 if (gyroConfig()->gyro_lpf1_dyn_min_hz
> 0) {
219 switch (gyroConfig()->gyro_lpf1_type
) {
221 gyro
.dynLpfFilter
= DYN_LPF_PT1
;
224 gyro
.dynLpfFilter
= DYN_LPF_BIQUAD
;
227 gyro
.dynLpfFilter
= DYN_LPF_PT2
;
230 gyro
.dynLpfFilter
= DYN_LPF_PT3
;
233 gyro
.dynLpfFilter
= DYN_LPF_NONE
;
237 gyro
.dynLpfFilter
= DYN_LPF_NONE
;
239 gyro
.dynLpfMin
= gyroConfig()->gyro_lpf1_dyn_min_hz
;
240 gyro
.dynLpfMax
= gyroConfig()->gyro_lpf1_dyn_max_hz
;
241 gyro
.dynLpfCurveExpo
= gyroConfig()->gyro_lpf1_dyn_expo
;
245 void gyroInitFilters(void)
247 uint16_t gyro_lpf1_init_hz
= gyroConfig()->gyro_lpf1_static_hz
;
250 if (gyroConfig()->gyro_lpf1_dyn_min_hz
> 0) {
251 gyro_lpf1_init_hz
= gyroConfig()->gyro_lpf1_dyn_min_hz
;
255 gyroInitLowpassFilterLpf(
257 gyroConfig()->gyro_lpf1_type
,
262 gyro
.downsampleFilterEnabled
= gyroInitLowpassFilterLpf(
264 gyroConfig()->gyro_lpf2_type
,
265 gyroConfig()->gyro_lpf2_static_hz
,
269 gyroInitFilterNotch1(gyroConfig()->gyro_soft_notch_hz_1
, gyroConfig()->gyro_soft_notch_cutoff_1
);
270 gyroInitFilterNotch2(gyroConfig()->gyro_soft_notch_hz_2
, gyroConfig()->gyro_soft_notch_cutoff_2
);
274 #ifdef USE_DYN_NOTCH_FILTER
275 dynNotchInit(dynNotchConfig(), gyro
.targetLooptime
);
278 const float k
= pt1FilterGain(GYRO_IMU_DOWNSAMPLE_CUTOFF_HZ
, gyro
.targetLooptime
* 1e-6f
);
279 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
280 pt1FilterInit(&gyro
.imuGyroFilter
[axis
], k
);
284 #if defined(USE_GYRO_SLEW_LIMITER)
285 void gyroInitSlewLimiter(gyroSensor_t
*gyroSensor
)
288 for (int axis
= 0; axis
< XYZ_AXIS_COUNT
; axis
++) {
289 gyroSensor
->gyroDev
.gyroADCRawPrevious
[axis
] = 0;
294 static void gyroInitSensorFilters(gyroSensor_t
*gyroSensor
)
296 #if defined(USE_GYRO_SLEW_LIMITER)
297 gyroInitSlewLimiter(gyroSensor
);
303 void gyroInitSensor(gyroSensor_t
*gyroSensor
, const gyroDeviceConfig_t
*config
)
305 gyroSensor
->gyroDev
.gyro_high_fsr
= gyroConfig()->gyro_high_fsr
;
306 gyroSensor
->gyroDev
.gyroAlign
= config
->alignment
;
307 buildRotationMatrixFromAngles(&gyroSensor
->gyroDev
.rotationMatrix
, &config
->customAlignment
);
308 gyroSensor
->gyroDev
.mpuIntExtiTag
= config
->extiTag
;
309 gyroSensor
->gyroDev
.hardware_lpf
= gyroConfig()->gyro_hardware_lpf
;
311 // The targetLooptime gets set later based on the active sensor's gyroSampleRateHz and pid_process_denom
312 gyroSensor
->gyroDev
.gyroSampleRateHz
= gyroSetSampleRate(&gyroSensor
->gyroDev
);
313 gyroSensor
->gyroDev
.initFn(&gyroSensor
->gyroDev
);
315 // As new gyros are supported, be sure to add them below based on whether they are subject to the overflow/inversion bug
316 // Any gyro not explicitly defined will default to not having built-in overflow protection as a safe alternative.
317 switch (gyroSensor
->gyroDev
.gyroHardware
) {
318 case GYRO_NONE
: // Won't ever actually get here, but included to account for all gyro types
331 case GYRO_LSM6DSV16X
:
334 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= true;
340 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
342 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= false;
346 gyroSensor
->gyroDev
.gyroHasOverflowProtection
= false; // default catch for newly added gyros until proven to be unaffected
350 gyroInitSensorFilters(gyroSensor
);
353 STATIC_UNIT_TESTED gyroHardware_e
gyroDetect(gyroDev_t
*dev
)
355 gyroHardware_e gyroHardware
= GYRO_DEFAULT
;
357 switch (gyroHardware
) {
361 #ifdef USE_GYRO_MPU6050
363 if (mpu6050GyroDetect(dev
)) {
364 gyroHardware
= GYRO_MPU6050
;
370 #ifdef USE_GYRO_L3G4200D
372 if (l3g4200dDetect(dev
)) {
373 gyroHardware
= GYRO_L3G4200D
;
379 #ifdef USE_GYRO_MPU3050
381 if (mpu3050Detect(dev
)) {
382 gyroHardware
= GYRO_MPU3050
;
388 #ifdef USE_GYRO_L3GD20
390 if (l3gd20GyroDetect(dev
)) {
391 gyroHardware
= GYRO_L3GD20
;
397 #ifdef USE_GYRO_SPI_MPU6000
399 if (mpu6000SpiGyroDetect(dev
)) {
400 gyroHardware
= GYRO_MPU6000
;
406 #if defined(USE_GYRO_MPU6500) || defined(USE_GYRO_SPI_MPU6500)
411 #ifdef USE_GYRO_SPI_MPU6500
412 if (mpu6500SpiGyroDetect(dev
)) {
414 if (mpu6500GyroDetect(dev
)) {
416 switch (dev
->mpuDetectionResult
.sensor
) {
418 gyroHardware
= GYRO_MPU9250
;
421 gyroHardware
= GYRO_ICM20601
;
424 gyroHardware
= GYRO_ICM20602
;
427 gyroHardware
= GYRO_ICM20608G
;
430 gyroHardware
= GYRO_MPU6500
;
437 #ifdef USE_GYRO_SPI_MPU9250
439 if (mpu9250SpiGyroDetect(dev
)) {
440 gyroHardware
= GYRO_MPU9250
;
446 #ifdef USE_GYRO_SPI_ICM20649
448 if (icm20649SpiGyroDetect(dev
)) {
449 gyroHardware
= GYRO_ICM20649
;
455 #ifdef USE_GYRO_SPI_ICM20689
457 if (icm20689SpiGyroDetect(dev
)) {
458 gyroHardware
= GYRO_ICM20689
;
464 #if defined(USE_GYRO_SPI_ICM42605) || defined(USE_GYRO_SPI_ICM42688P)
467 if (icm426xxSpiGyroDetect(dev
)) {
468 switch (dev
->mpuDetectionResult
.sensor
) {
470 gyroHardware
= GYRO_ICM42605
;
473 gyroHardware
= GYRO_ICM42688P
;
476 gyroHardware
= GYRO_NONE
;
484 #ifdef USE_ACCGYRO_BMI160
486 if (bmi160SpiGyroDetect(dev
)) {
487 gyroHardware
= GYRO_BMI160
;
493 #ifdef USE_ACCGYRO_BMI270
495 if (bmi270SpiGyroDetect(dev
)) {
496 gyroHardware
= GYRO_BMI270
;
502 #ifdef USE_ACCGYRO_LSM6DSO
504 if (lsm6dsoSpiGyroDetect(dev
)) {
505 gyroHardware
= GYRO_LSM6DSO
;
511 #ifdef USE_ACCGYRO_LSM6DSV16X
512 case GYRO_LSM6DSV16X
:
513 if (lsm6dsv16xSpiGyroDetect(dev
)) {
514 gyroHardware
= GYRO_LSM6DSV16X
;
520 #ifdef USE_VIRTUAL_GYRO
522 if (virtualGyroDetect(dev
)) {
523 gyroHardware
= GYRO_VIRTUAL
;
530 gyroHardware
= GYRO_NONE
;
533 if (gyroHardware
!= GYRO_NONE
) {
534 sensorsSet(SENSOR_GYRO
);
540 static bool gyroDetectSensor(gyroSensor_t
*gyroSensor
, const gyroDeviceConfig_t
*config
)
542 #ifdef USE_VIRTUAL_GYRO
545 bool gyroFound
= mpuDetect(&gyroSensor
->gyroDev
, config
);
551 const gyroHardware_e gyroHardware
= gyroDetect(&gyroSensor
->gyroDev
);
552 gyroSensor
->gyroDev
.gyroHardware
= gyroHardware
;
554 return gyroHardware
!= GYRO_NONE
;
557 static void gyroPreInitSensor(const gyroDeviceConfig_t
*config
)
559 #ifdef USE_VIRTUAL_GYRO
566 void gyroPreInit(void)
568 gyroPreInitSensor(gyroDeviceConfig(0));
569 #ifdef USE_MULTI_GYRO
570 gyroPreInitSensor(gyroDeviceConfig(1));
576 #ifdef USE_GYRO_OVERFLOW_CHECK
577 if (gyroConfig()->checkOverflow
== GYRO_OVERFLOW_CHECK_YAW
) {
578 gyro
.overflowAxisMask
= GYRO_OVERFLOW_Z
;
579 } else if (gyroConfig()->checkOverflow
== GYRO_OVERFLOW_CHECK_ALL_AXES
) {
580 gyro
.overflowAxisMask
= GYRO_OVERFLOW_X
| GYRO_OVERFLOW_Y
| GYRO_OVERFLOW_Z
;
582 gyro
.overflowAxisMask
= 0;
586 gyro
.gyroDebugMode
= DEBUG_NONE
;
587 gyro
.useDualGyroDebugging
= false;
588 gyro
.gyroHasOverflowProtection
= true;
594 case DEBUG_GYRO_FILTERED
:
596 case DEBUG_GYRO_SAMPLE
:
597 gyro
.gyroDebugMode
= debugMode
;
599 case DEBUG_DUAL_GYRO_DIFF
:
600 case DEBUG_DUAL_GYRO_RAW
:
601 case DEBUG_DUAL_GYRO_SCALED
:
602 gyro
.useDualGyroDebugging
= true;
606 gyroDetectionFlags
= GYRO_NONE_MASK
;
607 uint8_t gyrosToScan
= gyroConfig()->gyrosDetected
;
609 gyro
.gyroToUse
= gyroConfig()->gyro_to_use
;
610 gyro
.gyroDebugAxis
= gyroConfig()->gyro_filter_debug_axis
;
612 if ((!gyrosToScan
|| (gyrosToScan
& GYRO_1_MASK
)) && gyroDetectSensor(&gyro
.gyroSensor1
, gyroDeviceConfig(0))) {
613 gyroDetectionFlags
|= GYRO_1_MASK
;
616 #if defined(USE_MULTI_GYRO)
617 if ((!gyrosToScan
|| (gyrosToScan
& GYRO_2_MASK
)) && gyroDetectSensor(&gyro
.gyroSensor2
, gyroDeviceConfig(1))) {
618 gyroDetectionFlags
|= GYRO_2_MASK
;
622 if (gyroDetectionFlags
== GYRO_NONE_MASK
) {
626 bool eepromWriteRequired
= false;
628 gyroConfigMutable()->gyrosDetected
= gyroDetectionFlags
;
629 eepromWriteRequired
= true;
632 #if defined(USE_MULTI_GYRO)
633 if ((gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
&& !((gyroDetectionFlags
& GYRO_ALL_MASK
) == GYRO_ALL_MASK
))
634 || (gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_1
&& !(gyroDetectionFlags
& GYRO_1_MASK
))
635 || (gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_2
&& !(gyroDetectionFlags
& GYRO_2_MASK
))) {
636 if (gyroDetectionFlags
& GYRO_1_MASK
) {
637 gyro
.gyroToUse
= GYRO_CONFIG_USE_GYRO_1
;
639 gyro
.gyroToUse
= GYRO_CONFIG_USE_GYRO_2
;
642 gyroConfigMutable()->gyro_to_use
= gyro
.gyroToUse
;
643 eepromWriteRequired
= true;
646 // Only allow using both gyros simultaneously if they are the same hardware type.
647 if (((gyroDetectionFlags
& GYRO_ALL_MASK
) == GYRO_ALL_MASK
) && gyro
.gyroSensor1
.gyroDev
.gyroHardware
== gyro
.gyroSensor2
.gyroDev
.gyroHardware
) {
648 gyroDetectionFlags
|= GYRO_IDENTICAL_MASK
;
649 } else if (gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
650 // If the user selected "BOTH" and they are not the same type, then reset to using only the first gyro.
651 gyro
.gyroToUse
= GYRO_CONFIG_USE_GYRO_1
;
652 gyroConfigMutable()->gyro_to_use
= gyro
.gyroToUse
;
653 eepromWriteRequired
= true;
656 if (gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_2
|| gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
657 static DMA_DATA
uint8_t gyroBuf2
[GYRO_BUF_SIZE
];
658 // SPI DMA buffer required per device
659 gyro
.gyroSensor2
.gyroDev
.dev
.txBuf
= gyroBuf2
;
660 gyro
.gyroSensor2
.gyroDev
.dev
.rxBuf
= &gyroBuf2
[GYRO_BUF_SIZE
/ 2];
662 gyroInitSensor(&gyro
.gyroSensor2
, gyroDeviceConfig(1));
663 gyro
.gyroHasOverflowProtection
= gyro
.gyroHasOverflowProtection
&& gyro
.gyroSensor2
.gyroDev
.gyroHasOverflowProtection
;
664 detectedSensors
[SENSOR_INDEX_GYRO
] = gyro
.gyroSensor2
.gyroDev
.gyroHardware
;
668 if (eepromWriteRequired
) {
672 if (gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_1
|| gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_BOTH
) {
673 static DMA_DATA
uint8_t gyroBuf1
[GYRO_BUF_SIZE
];
674 // SPI DMA buffer required per device
675 gyro
.gyroSensor1
.gyroDev
.dev
.txBuf
= gyroBuf1
;
676 gyro
.gyroSensor1
.gyroDev
.dev
.rxBuf
= &gyroBuf1
[GYRO_BUF_SIZE
/ 2];
677 gyroInitSensor(&gyro
.gyroSensor1
, gyroDeviceConfig(0));
678 gyro
.gyroHasOverflowProtection
= gyro
.gyroHasOverflowProtection
&& gyro
.gyroSensor1
.gyroDev
.gyroHasOverflowProtection
;
679 detectedSensors
[SENSOR_INDEX_GYRO
] = gyro
.gyroSensor1
.gyroDev
.gyroHardware
;
682 // Copy the sensor's scale to the high-level gyro object. If running in "BOTH" mode
683 // then logic above requires both sensors to be the same so we'll use sensor1's scale.
684 // This will need to be revised if we ever allow different sensor types to be used simultaneously.
685 // Likewise determine the appropriate raw data for use in DEBUG_GYRO_RAW
686 gyro
.scale
= gyro
.gyroSensor1
.gyroDev
.scale
;
687 gyro
.rawSensorDev
= &gyro
.gyroSensor1
.gyroDev
;
688 #if defined(USE_MULTI_GYRO)
689 if (gyro
.gyroToUse
== GYRO_CONFIG_USE_GYRO_2
) {
690 gyro
.scale
= gyro
.gyroSensor2
.gyroDev
.scale
;
691 gyro
.rawSensorDev
= &gyro
.gyroSensor2
.gyroDev
;
695 if (gyro
.rawSensorDev
) {
696 gyro
.sampleRateHz
= gyro
.rawSensorDev
->gyroSampleRateHz
;
697 gyro
.accSampleRateHz
= gyro
.rawSensorDev
->accSampleRateHz
;
699 gyro
.sampleRateHz
= 0;
700 gyro
.accSampleRateHz
= 0;
706 gyroDetectionFlags_t
getGyroDetectionFlags(void)
708 return gyroDetectionFlags
;
711 void gyroSetTargetLooptime(uint8_t pidDenom
)
713 activePidLoopDenom
= pidDenom
;
714 if (gyro
.sampleRateHz
) {
715 gyro
.sampleLooptime
= 1e6f
/ gyro
.sampleRateHz
;
716 gyro
.targetLooptime
= activePidLoopDenom
* 1e6f
/ gyro
.sampleRateHz
;
718 gyro
.sampleLooptime
= 0;
719 gyro
.targetLooptime
= 0;
723 gyroDev_t
*gyroActiveDev(void)
725 return &ACTIVE_GYRO
->gyroDev
;
728 const mpuDetectionResult_t
*gyroMpuDetectionResult(void)
730 return &ACTIVE_GYRO
->gyroDev
.mpuDetectionResult
;
733 int16_t gyroRateDps(int axis
)
735 return lrintf(gyro
.gyroADCf
[axis
] / ACTIVE_GYRO
->gyroDev
.scale
);
738 #ifdef USE_GYRO_REGISTER_DUMP
739 static extDevice_t
*gyroSensorDevByInstance(uint8_t whichSensor
)
741 #ifdef USE_MULTI_GYRO
742 if (whichSensor
== GYRO_CONFIG_USE_GYRO_2
) {
743 return &gyro
.gyroSensor2
.gyroDev
.dev
;
748 return &gyro
.gyroSensor1
.gyroDev
.dev
;
751 uint8_t gyroReadRegister(uint8_t whichSensor
, uint8_t reg
)
753 return mpuGyroReadRegister(gyroSensorDevByInstance(whichSensor
), reg
);
755 #endif // USE_GYRO_REGISTER_DUMP