Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1f9f221
spi: data-ready reads on F4 and F7, through DMA
MrScothh Sep 28, 2026
697e995
targets: gyro data-ready pins on F4 and F7 boards
MrScothh Sep 28, 2026
b9d32b6
gyro: BMI270 and ICM-45686 read on data-ready too
MrScothh Sep 28, 2026
140552c
targets: BMI270 data-ready pins
MrScothh Sep 28, 2026
608b4b8
gyro: a data-ready that came during the last read starts nothing befo…
MrScothh Sep 28, 2026
52b95e8
spi: an H7 data-ready read clears the EOT a polled transfer left behind
MrScothh Sep 28, 2026
6c9c0f9
spi: on F7 an aborted transfer waits for its queued bytes by time, no…
MrScothh Sep 28, 2026
cfd0513
spi: register reads and writes report a transfer that failed
MrScothh Sep 28, 2026
6339fab
gyro: on F4 the data-ready interrupt is on the rising edge, not on no…
MrScothh Sep 28, 2026
6cf11aa
spi: a data-ready read stopped on F4 clears the overrun it may leave
MrScothh Sep 28, 2026
55c6af5
targets: no data-ready pin on SPEEDYBEEF405AIO, whose port E the targ…
MrScothh Sep 28, 2026
122b0dc
gyro: new config version for gyro_data_ready
MrScothh Sep 28, 2026
7cec776
gyro, spi: shorter comments
MrScothh Sep 28, 2026
683d24f
gyro: data-ready on by default for the ICM426xx on F4 and F7 too
MrScothh Sep 28, 2026
dcef64b
gyro: data-ready on by default for the BMI270 and ICM-45686 too
MrScothh Sep 28, 2026
a785ce4
gyro: MPU6000, MPU6500 and ICM-20689 read on data-ready too
MrScothh Sep 28, 2026
e82cc31
targets: MPU6000, MPU6500 and ICM-20689 data-ready pins
MrScothh Sep 28, 2026
e2a7aeb
gyro: MPU9250 and LSM6DXX read on data-ready too
MrScothh Sep 28, 2026
7fb0a2f
targets: MPU9250 and LSM6DXX data-ready pins
MrScothh Sep 28, 2026
14535f7
targets: data-ready pins the first Betaflight comparison missed
MrScothh Sep 28, 2026
7971db0
targets: FLYWOOF405S_AIO's ICM-42605 data-ready pin, which the first …
MrScothh Sep 28, 2026
5106b6e
spi: clean the data-ready transmit buffer from the cache before DMA r…
MrScothh Sep 29, 2026
c9053d0
gyro: keep PG_GYRO_CONFIG at version 12
MrScothh Oct 5, 2026
066dbe0
Merge maintenance-10.x into feature/gyro-data-ready-bmi270
MrScothh Oct 6, 2026
9b019e4
Merge maintenance-10.x into feature/gyro-data-ready-bmi270
MrScothh Oct 15, 2026
a210fc9
Merge upstream/next-10.1 to resolve conflicts with PR #12066
sensei-hacker Oct 18, 2026
da364e7
Merge upstream/next-10.1 into PR 12066 branch
sensei-hacker Oct 18, 2026
6676154
gyro: ICM-45686 and MPU data-ready with ON only, until run on hardware
MrScothh Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/Settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -2140,7 +2140,7 @@ Gyro processing anti-aliasing filter cutoff frequency. In normal operation this

### gyro_data_ready

Read the gyro when it signals a new sample, on its data-ready interrupt, instead of polling it: every sample once, and the CPU no longer waits on the bus. Needs a supported IMU (ICM-42605, ICM-42688-P) and a target that declares the interrupt pin. AUTO and ON do it, OFF polls the gyro.
Read the gyro when it signals a new sample, on its data-ready interrupt, instead of polling it: every sample once, and the CPU no longer waits on the bus. Needs a supported IMU and a target that declares the interrupt pin; without interrupts the gyro is read as before. AUTO does it with the ICM-42605, ICM-42688-P, BMI270 and LSM6DXX; ON also with the ICM-45686, MPU6000, MPU6500 (and the ICM-20602 and ICM-20608 it drives), MPU9250 and ICM-20689, not yet run on hardware. OFF polls the gyro.

| Allowed Values | |
| --- | --- |
Expand Down
2 changes: 1 addition & 1 deletion src/main/drivers/accgyro/accgyro.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ typedef struct {
// Whether a driver that can reads its gyro on the data-ready interrupt (gyro_data_ready)
typedef enum {
GYRO_DEV_DATA_READY_OFF = 0,
GYRO_DEV_DATA_READY_WHERE_TESTED, // only where that driver has been tested
GYRO_DEV_DATA_READY_WHERE_TESTED, // where the driver turns it on for AUTO
GYRO_DEV_DATA_READY_ON,
} gyroDevDataReady_e;

Expand Down
41 changes: 41 additions & 0 deletions src/main/drivers/accgyro/accgyro_bmi270.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

#include "drivers/sensor.h"
#include "drivers/accgyro/accgyro.h"
#include "drivers/accgyro/accgyro_data_ready.h"
#include "drivers/accgyro/accgyro_bmi270.h"

#define BMI270_CONFIG_SIZE 328
Expand Down Expand Up @@ -257,6 +258,17 @@ static bool bmi270yroReadScratchpad(gyroDev_t *gyro)

static bool bmi270AccReadScratchpad(accDev_t *acc)
{
#if defined(USE_SPI_DATA_READY)
// The read on data-ready brought the accelerometer too
int16_t v[XYZ_AXIS_COUNT];
if (gyroDataReadyAcc(acc->busDev, v)) {
acc->ADCRaw[X] = v[X];
acc->ADCRaw[Y] = v[Y];
acc->ADCRaw[Z] = v[Z];
return true;
}
#endif

bmi270ContextData_t * ctx = busDeviceGetScratchpadMemory(acc->busDev);

if (ctx->lastReadStatus) {
Expand Down Expand Up @@ -284,9 +296,38 @@ static bool bmi270TemperatureRead(gyroDev_t *gyro, int16_t * data)
return false;
}

#if defined(USE_SPI_DATA_READY)
// After a dummy byte, from ACC_DATA_X_LSB: accelerometer X, Y, Z and gyro X, Y, Z, little-endian.
// INT1 flags new data of either sensor, so the gyro-only read takes the accelerometer too
static void bmi270DataReadyParse(const uint8_t *data, bool withAccAndTemp, int16_t *gyro, int16_t *acc, int16_t *temp)
{
UNUSED(temp);
data++;
if (withAccAndTemp) {
acc[X] = int16_val_little_endian(data, 0);
acc[Y] = int16_val_little_endian(data, 1);
acc[Z] = int16_val_little_endian(data, 2);
}
gyro[X] = int16_val_little_endian(data, 3);
gyro[Y] = int16_val_little_endian(data, 4);
gyro[Z] = int16_val_little_endian(data, 5);
}

static const gyroDataReadyDriver_t bmi270DataReady = {
.withAccAndTemp = { BMI270_REG_ACC_DATA_X_LSB | 0x80, 13 },
.gyroOnly = { BMI270_REG_ACC_DATA_X_LSB | 0x80, 13 },
.parse = bmi270DataReadyParse,
.registerRead = bmi270yroReadScratchpad,
.tested = true,
};
#endif

static void bmi270GyroInit(gyroDev_t *gyro)
{
bmi270AccAndGyroInit(gyro);
#if defined(USE_SPI_DATA_READY)
gyro->dataReadyDriver = &bmi270DataReady;
#endif
}

static void bmi270AccInit(accDev_t *acc)
Expand Down
17 changes: 14 additions & 3 deletions src/main/drivers/accgyro/accgyro_data_ready.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,19 @@ void gyroDataReadySuspend(void)
}
}

bool gyroDataReadyWanted(const gyroDev_t *gyro)
{
const gyroDataReadyDriver_t *driver = gyro->dataReadyDriver;
const busDevice_t *dev = gyro->busDev;
return driver && dev && dev->irqPin && gyro->readOnDataReady != GYRO_DEV_DATA_READY_OFF &&
(gyro->readOnDataReady != GYRO_DEV_DATA_READY_WHERE_TESTED || driver->tested);
}

void gyroDataReadyStart(gyroDev_t *gyro)
{
const gyroDataReadyDriver_t *driver = gyro->dataReadyDriver;
busDevice_t *dev = gyro->busDev;
if (!driver || !dev || !dev->irqPin || gyro->readOnDataReady == GYRO_DEV_DATA_READY_OFF ||
(gyro->readOnDataReady == GYRO_DEV_DATA_READY_WHERE_TESTED && !driver->tested)) {
if (!gyroDataReadyWanted(gyro)) {
return;
}
// A pin already owned stays with its owner; a wrong but free pin only means polling as before
Expand Down Expand Up @@ -216,7 +223,11 @@ void gyroDataReadyStart(gyroDev_t *gyro)

IOInit(dev->irqPin, OWNER_MPU, RESOURCE_EXTI, RESOURCE_INDEX(gyro->imuSensorToUse));
EXTIHandlerInit(&d->exti, gyroDataReadyExti);
EXTIConfig(dev->irqPin, &d->exti, NVIC_PRIO_GYRO_DATA_READY, IOCFG_IN_FLOATING);
#if defined(STM32F7) || defined(STM32H7)
EXTIConfig(dev->irqPin, &d->exti, NVIC_PRIO_GYRO_DATA_READY, IOCFG_IN_FLOATING); // always on the rising edge
#else
EXTIConfig(dev->irqPin, &d->exti, NVIC_PRIO_GYRO_DATA_READY, EXTI_Trigger_Rising);
#endif
EXTIEnable(dev->irqPin, true);

gyro->dataReadyState = d;
Expand Down
2 changes: 2 additions & 0 deletions src/main/drivers/accgyro/accgyro_data_ready.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ typedef struct gyroDataReadyDriver_s {
typedef struct gyroDataReady_s gyroDataReady_t;

#if defined(USE_SPI_DATA_READY)
// Whether gyroDataReadyStart() will try, for a driver whose rate depends on it
bool gyroDataReadyWanted(const gyroDev_t *gyro);
void gyroDataReadyStart(gyroDev_t *gyro);
void gyroDataReadySuspend(void);
// For the driver's acc and temperature reads: true when the last data-ready read brought them
Expand Down
4 changes: 4 additions & 0 deletions src/main/drivers/accgyro/accgyro_icm20689.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ static void icm20689AccAndGyroInit(gyroDev_t *gyro)
busWrite(busDev, MPU_RA_SMPLRT_DIV, config->gyroConfigValues[1]); // Get Divider Drops
delay(100);

#if defined(USE_SPI_DATA_READY)
mpuDataReadySetup(gyro);
#endif

// Switch SPI to fast speed
busSetSpeed(busDev, BUS_SPEED_FAST);
}
Expand Down
2 changes: 0 additions & 2 deletions src/main/drivers/accgyro/accgyro_icm42605.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,7 @@ static const gyroDataReadyDriver_t icm426xxDataReady = {
.hasTemp = true,
.parse = icm426xxDataReadyParse,
.registerRead = icm42605GyroRead,
#if defined(STM32H7)
.tested = true,
#endif
};
#endif

Expand Down
52 changes: 52 additions & 0 deletions src/main/drivers/accgyro/accgyro_icm45686.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "drivers/sensor.h"
#include "drivers/accgyro/accgyro_mpu.h"
#include "drivers/accgyro/accgyro.h"
#include "drivers/accgyro/accgyro_data_ready.h"
#include "accgyro_icm45686.h"

#if defined(USE_IMU_ICM45686)
Expand Down Expand Up @@ -309,6 +310,17 @@ static void icm45686AccInit(accDev_t *acc)

static bool icm45686AccRead(accDev_t *acc)
{
#if defined(USE_SPI_DATA_READY)
// The read on data-ready brought the accelerometer too
int16_t v[XYZ_AXIS_COUNT];
if (gyroDataReadyAcc(acc->busDev, v)) {
acc->ADCRaw[X] = v[X];
acc->ADCRaw[Y] = v[Y];
acc->ADCRaw[Z] = v[Z];
return true;
}
#endif

uint8_t data[6];

const bool ack = busReadBuf(acc->busDev, ICM456XX_ACCEL_DATA_X1_UI, data, 6);
Expand Down Expand Up @@ -341,6 +353,14 @@ static bool icm45686GyroRead(gyroDev_t *gyro)

static bool icm45686ReadTemperature(gyroDev_t *gyro, int16_t * temp)
{
#if defined(USE_SPI_DATA_READY)
int16_t raw;
if (gyroDataReadyTemperature(gyro->busDev, &raw)) {
*temp = (raw / 12.8f) + 250.0f; // as below, degC*10
return true;
}
#endif

uint8_t data[2];

const bool ack = busReadBuf(gyro->busDev, ICM456XX_TEMP_DATA1, data, 2);
Expand All @@ -353,6 +373,34 @@ static bool icm45686ReadTemperature(gyroDev_t *gyro, int16_t * temp)
return true;
}

#if defined(USE_SPI_DATA_READY)
// From ACCEL_DATA_X1_UI: accelerometer X, Y, Z, gyro X, Y, Z and temperature, little-endian
static void icm45686DataReadyParse(const uint8_t *data, bool withAccAndTemp, int16_t *gyro, int16_t *acc, int16_t *temp)
{
if (withAccAndTemp) {
acc[X] = int16_val_little_endian(data, 0);
acc[Y] = int16_val_little_endian(data, 1);
acc[Z] = int16_val_little_endian(data, 2);
data += 6;
}
gyro[X] = int16_val_little_endian(data, 0);
gyro[Y] = int16_val_little_endian(data, 1);
gyro[Z] = int16_val_little_endian(data, 2);
if (withAccAndTemp) {
*temp = int16_val_little_endian(data, 3);
}
}

static const gyroDataReadyDriver_t icm45686DataReady = {
.withAccAndTemp = { ICM456XX_ACCEL_DATA_X1_UI | 0x80, 14 },
.gyroOnly = { ICM456XX_GYRO_DATA_X1_UI | 0x80, 6 },
.hasTemp = true,
.parse = icm45686DataReadyParse,
.registerRead = icm45686GyroRead,
.tested = false, // not run on hardware yet
};
#endif

static void icm45686AccAndGyroInit(gyroDev_t *gyro)
{
busDevice_t * dev = gyro->busDev;
Expand Down Expand Up @@ -402,6 +450,10 @@ static void icm45686AccAndGyroInit(gyroDev_t *gyro)

delay(ICM456XX_INT_CONFIG_DELAY_MS);
busSetSpeed(dev, BUS_SPEED_FAST);

#if defined(USE_SPI_DATA_READY)
gyro->dataReadyDriver = &icm45686DataReady;
#endif
}

static bool icm45686DeviceDetect(busDevice_t * dev)
Expand Down
47 changes: 47 additions & 0 deletions src/main/drivers/accgyro/accgyro_lsm6dxx.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "drivers/accgyro/accgyro.h"
#include "drivers/accgyro/accgyro_mpu.h"
#include "drivers/accgyro/accgyro_lsm6dxx.h"
#include "drivers/accgyro/accgyro_data_ready.h"

#if defined(USE_IMU_LSM6DXX)

Expand Down Expand Up @@ -180,6 +181,12 @@ static void lsm6dxxConfig(gyroDev_t *gyro)
busDevice_t * dev = gyro->busDev;
const gyroFilterAndRateConfig_t * config = mpuChooseGyroConfig(gyro->lpf, 1000000 / gyro->requestedSampleIntervalUs);
gyro->sampleRateIntervalUs = 1000000 / config->gyroRateHz;
#if defined(USE_SPI_DATA_READY)
// On data-ready every sample reaches the gyro task and its first filter, so they run at the 6664 Hz set below
if (gyroDataReadyWanted(gyro)) {
gyro->sampleRateIntervalUs = 150;
}
#endif

busSetSpeed(dev, BUS_SPEED_INITIALIZATION);
// Reset the device (wait 100ms before continuing config)
Expand Down Expand Up @@ -272,6 +279,17 @@ static void lsm6dxxSpiAccInit(accDev_t *acc)

static bool lsm6dxxAccRead(accDev_t *acc)
{
#if defined(USE_SPI_DATA_READY)
// The read on data-ready brought the accelerometer too
int16_t v[XYZ_AXIS_COUNT];
if (gyroDataReadyAcc(acc->busDev, v)) {
acc->ADCRaw[X] = v[X];
acc->ADCRaw[Y] = v[Y];
acc->ADCRaw[Z] = v[Z];
return true;
}
#endif

uint8_t data[6];
const bool ack = busReadBuf(acc->busDev, LSM6DXX_REG_OUTX_L_A, data, 6);
if (!ack) {
Expand All @@ -296,6 +314,31 @@ static bool lsm6dxxGyroRead(gyroDev_t *gyro)
return true;
}

#if defined(USE_SPI_DATA_READY)
// From OUTX_L_G: gyro X, Y, Z, then accelerometer X, Y, Z, little-endian
static void lsm6dxxDataReadyParse(const uint8_t *data, bool withAccAndTemp, int16_t *gyro, int16_t *acc, int16_t *temp)
{
UNUSED(temp);
gyro[X] = int16_val_little_endian(data, 0);
gyro[Y] = int16_val_little_endian(data, 1);
gyro[Z] = int16_val_little_endian(data, 2);
if (withAccAndTemp) {
acc[X] = int16_val_little_endian(data, 3);
acc[Y] = int16_val_little_endian(data, 4);
acc[Z] = int16_val_little_endian(data, 5);
}
}

static const gyroDataReadyDriver_t lsm6dxxDataReady = {
.withAccAndTemp = { LSM6DXX_REG_OUTX_L_G | 0x80, 12 },
.gyroOnly = { LSM6DXX_REG_OUTX_L_G | 0x80, 6 },
.hasTemp = false,
.parse = lsm6dxxDataReadyParse,
.registerRead = lsm6dxxGyroRead,
.tested = true,
};
#endif

// Init Gyro first,then Acc
bool lsm6dGyroDetect(gyroDev_t *gyro)
{
Expand All @@ -317,6 +360,10 @@ bool lsm6dGyroDetect(gyroDev_t *gyro)
gyro->intStatusFn = gyroCheckDataReady;
gyro->gyroAlign = gyro->busDev->param;
gyro->scale = 1.0f / 16.4f; // 2000 dps
#if defined(USE_SPI_DATA_READY)
// Both register maps configure gyro data-ready, pulsed, on INT1
gyro->dataReadyDriver = &lsm6dxxDataReady;
#endif
return true;

}
Expand Down
Loading
Loading