optimize bmi270 driver (#37)

This commit is contained in:
Hugo Chiang 2023-03-09 20:46:45 +08:00 committed by GitHub
parent 3163e0ac62
commit 9db7bec3fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 523 additions and 484 deletions

View File

@ -376,6 +376,7 @@ SIZE_OPTIMISED_SRC := $(SIZE_OPTIMISED_SRC) \
drivers/accgyro/accgyro_spi_mpu9250.c \
drivers/accgyro/accgyro_spi_icm20689.c \
drivers/accgyro/accgyro_spi_icm426xx.c \
drivers/accgyro/accgyro_spi_bmi270_init.c \
drivers/accgyro/accgyro_spi_asm330lhh_init.c \
drivers/accgyro/accgyro_spi_lsm6ds3_init.c \
drivers/accgyro/accgyro_spi_lsm6dsl_init.c \

View File

@ -38,418 +38,14 @@
#include "drivers/system.h"
#include "drivers/time.h"
#include "sensors/gyro.h"
// #include "build/debug.h"
// 10 MHz max SPI frequency
#define BMI270_MAX_SPI_CLK_HZ 10000000
#define BMI270_FIFO_FRAME_SIZE 6
#define BMI270_CONFIG_SIZE 8192
// Declaration for the device config (microcode) that must be uploaded to the sensor
extern const uint8_t bmi270_config_file[BMI270_CONFIG_SIZE];
#define BMI270_CHIP_ID 0x24
#define BMI270_GYRO_CAS_MASK 0x7F
#define BMI270_GYRO_CAS_SIGN_BIT_MASK 0x40
// BMI270 registers (not the complete list)
typedef enum {
BMI270_REG_CHIP_ID = 0x00,
BMI270_REG_ERR_REG = 0x02,
BMI270_REG_STATUS = 0x03,
BMI270_REG_ACC_DATA_X_LSB = 0x0C,
BMI270_REG_GYR_DATA_X_LSB = 0x12,
BMI270_REG_SENSORTIME_0 = 0x18,
BMI270_REG_SENSORTIME_1 = 0x19,
BMI270_REG_SENSORTIME_2 = 0x1A,
BMI270_REG_EVENT = 0x1B,
BMI270_REG_INT_STATUS_0 = 0x1C,
BMI270_REG_INT_STATUS_1 = 0x1D,
BMI270_REG_INTERNAL_STATUS = 0x21,
BMI270_REG_TEMPERATURE_LSB = 0x22,
BMI270_REG_TEMPERATURE_MSB = 0x23,
BMI270_REG_FIFO_LENGTH_LSB = 0x24,
BMI270_REG_FIFO_LENGTH_MSB = 0x25,
BMI270_REG_FIFO_DATA = 0x26,
BMI270_REG_FEAT_PAGE = 0x2F,
BMI270_REG_FEATURES_0_GYR_GAIN_STATUS = 0x38,
BMI270_REG_FEATURES_0_GYR_CAS = 0x3C,
BMI270_REG_FEATURES_1_G_TRIG_1 = 0x32,
BMI270_REG_FEATURES_1_GEN_SET_1 = 0x34,
BMI270_REG_ACC_CONF = 0x40,
BMI270_REG_ACC_RANGE = 0x41,
BMI270_REG_GYRO_CONF = 0x42,
BMI270_REG_GYRO_RANGE = 0x43,
BMI270_REG_AUX_CONF = 0x44,
BMI270_REG_FIFO_DOWNS = 0x45,
BMI270_REG_FIFO_WTM_0 = 0x46,
BMI270_REG_FIFO_WTM_1 = 0x47,
BMI270_REG_FIFO_CONFIG_0 = 0x48,
BMI270_REG_FIFO_CONFIG_1 = 0x49,
BMI270_REG_SATURATION = 0x4A,
BMI270_REG_INT1_IO_CTRL = 0x53,
BMI270_REG_INT2_IO_CTRL = 0x54,
BMI270_REG_INT_LATCH = 0x55,
BMI270_REG_INT1_MAP_FEAT = 0x56,
BMI270_REG_INT2_MAP_FEAT = 0x57,
BMI270_REG_INT_MAP_DATA = 0x58,
BMI270_REG_INIT_CTRL = 0x59,
BMI270_REG_INIT_DATA = 0x5E,
BMI270_REG_GYR_CRT_CONF = 0x69,
BMI270_REG_IF_CONF = 0x6B,
BMI270_REG_ACC_SELF_TEST = 0x6D,
BMI270_REG_GYR_SELF_TEST_AXES = 0x6E,
BMI270_REG_OFFSET_6 = 0x77,
BMI270_REG_PWR_CONF = 0x7C,
BMI270_REG_PWR_CTRL = 0x7D,
BMI270_REG_CMD = 0x7E,
} bmi270Register_e;
// BMI270 register configuration values
typedef enum {
BMI270_VAL_CMD_G_TRIGGER = 0x02,
BMI270_VAL_CMD_SOFTRESET = 0xB6,
BMI270_VAL_CMD_FIFOFLUSH = 0xB0,
BMI270_VAL_PWR_CTRL_DISABLE_ALL = 0x00, // disable all sensors
BMI270_VAL_PWR_CTRL = 0x0E, // enable gyro, acc and temp sensors
BMI270_VAL_PWR_CTRL_ACC_ENABLE = BIT(2), // bit 2, enable acc
BMI270_VAL_PWR_CTRL_ACC_DISABLE = 0x00, // bit 2, disable gyro
BMI270_VAL_PWR_CONF_ADV_POWER_SAVE_DISABLE = 0x00, // disable ADV PS
BMI270_VAL_PWR_CONF_ADV_POWER_SAVE_ENABLE = BIT(0), // enable ADV PS
BMI270_VAL_PWR_CONF = 0x02, // disable advanced power save, enable FIFO self-wake
BMI270_VAL_PAGE_0 = 0x00, // select page 0
BMI270_VAL_PAGE_1 = 0x01, // select page 1
BMI270_VAL_ACC_CONF_ODR800 = 0x0B, // set acc sample rate to 800hz
BMI270_VAL_ACC_CONF_ODR1600 = 0x0C, // set acc sample rate to 1600hz
BMI270_VAL_ACC_CONF_BWP = 0x01, // set acc filter in osr2 mode
BMI270_VAL_ACC_CONF_HP = 0x01, // set acc in high performance mode
BMI270_VAL_ACC_RANGE_8G = 0x02, // set acc to 8G full scale
BMI270_VAL_ACC_RANGE_16G = 0x03, // set acc to 16G full scale
BMI270_VAL_GYRO_CONF_ODR3200 = 0x0D, // set gyro sample rate to 3200hz
BMI270_VAL_GYRO_CONF_BWP_OSR4 = 0x00, // set gyro filter in OSR4 mode
BMI270_VAL_GYRO_CONF_BWP_OSR2 = 0x01, // set gyro filter in OSR2 mode
BMI270_VAL_GYRO_CONF_BWP_NORM = 0x02, // set gyro filter in normal mode
BMI270_VAL_GYRO_CONF_NOISE_PERF = 0x01, // set gyro in high performance noise mode
BMI270_VAL_GYRO_CONF_FILTER_PERF = 0x01, // set gyro in high performance filter mode
BMI270_VAL_GYRO_RANGE_2000DPS = 0x08, // set gyro to 2000dps full scale
// for some reason you have to enable the ois_range bit (bit 3) for 2000dps as well
// or else the gyro scale will be 250dps when in prefiltered FIFO mode (not documented in datasheet!)
BMI270_VAL_INT_MAP_DATA_DRDY_INT1 = 0x04, // enable the data ready interrupt pin 1
BMI270_VAL_INT_MAP_FIFO_WM_INT1 = 0x02, // enable the FIFO watermark interrupt pin 1
BMI270_VAL_INT1_IO_CTRL_PINMODE = 0x0A, // active high, push-pull, output enabled, input disabled
BMI270_VAL_IF_CONF_SET_INTERFACE = 0x00, // spi 4-wire mode, disable OIS, disable AUX
BMI270_VAL_FIFO_CONFIG_0 = 0x00, // don't stop when full, disable sensortime frame
BMI270_VAL_FIFO_CONFIG_1 = 0x80, // only gyro data in FIFO, use headerless mode
BMI270_VAL_FIFO_DOWNS = 0x00, // select unfiltered gyro data with no downsampling (6.4KHz samples)
BMI270_VAL_FIFO_WTM_0 = 0x06, // set the FIFO watermark level to 1 gyro sample (6 bytes)
BMI270_VAL_FIFO_WTM_1 = 0x00, // FIFO watermark MSB
BMI270_VAL_GEN_SET_1 = 0x0200, // bit 9, enable self offset correction (IOC part 1)
BMI270_VAL_OFFSET_6 = 0xC0, // Enable sensitivity error compensation and gyro offset compensation (IOC part2)
BMI270_VAL_OFFSET_6_GYR_GAIN_EN_ENABLE = BIT(7), // bit 7, enable gyro gain compensation
BMI270_VAL_GYR_CRT_CONF_CRT_RUNNING = BIT(2), // bit 7, enable gyro crt
BMI270_VAL_FEATURES_1_G_TRIG_1_SELECT_CRT = 0x0100, // bit 8, CRT will be executed
BMI270_VAL_FEATURES_1_G_TRIG_1_SELECT_GYR_BIST=0x0000, // bit 8, gyro built-in self-test will be executed
BMI270_VAL_FEATURES_1_G_TRIG_1_BLOCK_UNLOCK = 0x0000,// bit 9, do not block further G_TRIGGER commands
BMI270_VAL_FEATURES_1_G_TRIG_1_BLOCK_BLOCK = 0x0200, // bit 9, block further G_TRIGGER commands
} bmi270ConfigValues_e;
typedef enum {
BMI270_MASK_FEATURES_1_GEN_SET_1 = 0x0200,
BMI270_MASK_OFFSET_6 = 0xC0,
BMI270_MASK_OFFSET_6_GYR_GAIN_ENABLE = 0x80, // bit 7, enable gyro gain compensation
BMI270_MASK_PWR_ADV_POWER_SAVE = 0x01, // bit 0, enable advanced power save
BMI270_MASK_PWR_CTRL_ACC_ENABLE = 0x04, // bit 2, enable acc
BMI270_MASK_GYR_CRT_CONF_CRT_RUNNING = 0x04, // bit 2, gyro CRT running
BMI270_MASK_G_TRIG_1_SELECT = 0x0100, // bit 8, select feature that should be executed
BMI270_MASK_G_TRIG_1_BLOCK = 0x0200, // bit 9, block feature with next G_TRIGGER CMD
BMI270_MASK_GYR_GAIN_STATUS_G_TRIG_STATUS = 0x38 // bit[5:3]
} bmi270ConfigMasks_e;
// Need to see at least this many interrupts during initialisation to confirm EXTI connectivity
#define GYRO_EXTI_DETECT_THRESHOLD 1000
// BMI270 register reads are 16bits with the first byte a "dummy" value 0
// that must be ignored. The result is in the second byte.
static uint8_t bmi270RegisterRead(const extDevice_t *dev, bmi270Register_e registerId)
{
uint8_t data[2] = { 0, 0 };
if (spiReadRegMskBufRB(dev, registerId, data, 2)) {
return data[1];
} else {
return 0;
}
}
static uint16_t bmi270RegisterRead16(const extDevice_t *dev, bmi270Register_e registerId)
{
uint8_t data[3] = { 0, 0, 0 };
if (spiReadRegMskBufRB(dev, registerId, data, 3)) {
return (uint16_t)( (data[2]<<8) | data[1] ); // LSB first since address is auto-incremented
} else {
return 0;
}
}
static void bmi270RegisterWrite(const extDevice_t *dev, bmi270Register_e registerId, uint8_t value, unsigned delayMs)
{
spiWriteReg(dev, registerId, value);
if (delayMs) {
delay(delayMs);
}
}
static void bmi270RegisterWriteBits(const extDevice_t *dev, bmi270Register_e registerID, bmi270ConfigMasks_e mask, uint8_t value, unsigned delayMs)
{
uint8_t newValue = bmi270RegisterRead(dev, registerID);
delayMicroseconds(2);
newValue = (newValue & ~mask) | value;
bmi270RegisterWrite(dev, registerID, newValue, delayMs);
}
static void bmi270RegisterWrite16(const extDevice_t *dev, bmi270Register_e registerId, uint16_t data, unsigned delayMs)
{
uint8_t buf[2] = {
(uint8_t)(data & 0x00FF),
(uint8_t)(data >> 8)
};
spiWriteRegBuf(dev, registerId, buf, 2);
if (delayMs) {
delay(delayMs);
}
}
static void bmi270RegisterWriteBits16(const extDevice_t *dev, bmi270Register_e registerID, bmi270ConfigMasks_e mask, uint16_t value, unsigned delayMs)
{
uint16_t newValue = bmi270RegisterRead16(dev, registerID);
delayMicroseconds(2);
newValue = (newValue & ~mask) | value;
bmi270RegisterWrite16(dev, registerID, newValue, delayMs);
}
static int8_t bmi270ProcessGyroCas(uint8_t raw)
{
int8_t result = 0;
raw = raw & BMI270_GYRO_CAS_MASK;
if ((raw & BMI270_GYRO_CAS_SIGN_BIT_MASK) == 0) {
result = (int8_t)(raw);
} else {
result = (int8_t)(raw - 128);
}
return result;
}
// Toggle the CS to switch the device into SPI mode.
// Device switches initializes as I2C and switches to SPI on a low to high CS transition
static void bmi270EnableSPI(const extDevice_t *dev)
{
IOLo(dev->busType_u.spi.csnPin);
delay(1);
IOHi(dev->busType_u.spi.csnPin);
delay(10);
}
uint8_t bmi270Detect(const extDevice_t *dev)
{
bmi270EnableSPI(dev);
if (bmi270RegisterRead(dev, BMI270_REG_CHIP_ID) == BMI270_CHIP_ID) {
return BMI_270_SPI;
}
return MPU_NONE;
}
static void bmi270UploadConfig(const extDevice_t *dev)
{
bmi270RegisterWrite(dev, BMI270_REG_PWR_CONF, 0, 1);
bmi270RegisterWrite(dev, BMI270_REG_INIT_CTRL, 0, 1);
// Transfer the config file
spiWriteRegBuf(dev, BMI270_REG_INIT_DATA, (uint8_t *)bmi270_config_file, sizeof(bmi270_config_file));
delay(10);
bmi270RegisterWrite(dev, BMI270_REG_INIT_CTRL, 1, 1);
}
static void bmi270EnableIOC(const extDevice_t *dev)
{
// Configure the feature register page to page 1
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_1, 1);
// Enable self offset correction
bmi270RegisterWriteBits16(dev, BMI270_REG_FEATURES_1_GEN_SET_1, BMI270_MASK_FEATURES_1_GEN_SET_1, BMI270_VAL_GEN_SET_1, 1);
// Enable IOC
bmi270RegisterWriteBits(dev, BMI270_REG_OFFSET_6, BMI270_MASK_OFFSET_6, 0x40, 1);
// Configure the feature register page to page 0
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_0, 1);
}
static void bmi270PerformCRT(const extDevice_t *dev)
{
// disable advance power save mode
bmi270RegisterWriteBits(dev, BMI270_REG_PWR_CONF, BMI270_MASK_PWR_ADV_POWER_SAVE, BMI270_VAL_PWR_CONF_ADV_POWER_SAVE_DISABLE, 10);
// enable gyro gain compensation, set OFFSET_6.gain_comp_en = 1
bmi270RegisterWriteBits(dev, BMI270_REG_OFFSET_6, BMI270_MASK_OFFSET_6_GYR_GAIN_ENABLE, BMI270_VAL_OFFSET_6_GYR_GAIN_EN_ENABLE, 10);
// enable acc, set pwr_ctrl.acc_en = 1
bmi270RegisterWriteBits(dev, BMI270_REG_PWR_CTRL, BMI270_MASK_PWR_CTRL_ACC_ENABLE, BMI270_VAL_PWR_CTRL_ACC_ENABLE, 10);
// set GYR_CRT_CONF.crt_running = 0b1
bmi270RegisterWriteBits(dev, BMI270_REG_GYR_CRT_CONF, BMI270_MASK_GYR_CRT_CONF_CRT_RUNNING, BMI270_VAL_GYR_CRT_CONF_CRT_RUNNING, 10);
// set page to 1
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_1, 10);
// set G_TRIG_1.select =1
bmi270RegisterWriteBits16(dev, BMI270_REG_FEATURES_1_G_TRIG_1, BMI270_MASK_G_TRIG_1_SELECT, BMI270_VAL_FEATURES_1_G_TRIG_1_SELECT_CRT, 10);
// set G_TRIG_1.block = 0
// bmi270RegisterWriteBits16(dev, BMI270_REG_FEATURES_1_G_TRIG_1, BMI270_MASK_G_TRIG_1_BLOCK, BMI270_VAL_FEATURES_1_G_TRIG_1_BLOCK_UNLOCK, 1);
// send g_trigger command to CMD reg
bmi270RegisterWrite(dev, BMI270_REG_CMD, BMI270_VAL_CMD_G_TRIGGER, 5000);
// read GYR_CRT_CONF.crt_running and check if it is 0
uint8_t bmiCheck = bmi270RegisterRead(dev, BMI270_REG_GYR_CRT_CONF);
// if not, wait for 2 seconds and check again max time for 5
uint8_t checkCount = 0;
while ((bmiCheck!=0x00) && (checkCount++ < 5)) {
bmiCheck = bmi270RegisterRead(dev, BMI270_REG_GYR_CRT_CONF);
delay(1000);
if (bmiCheck == 0x00) {
break;
}
}
delay(100);
// set page to 0
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_0, 1);
// read GYR_GAIN_STATUS.g_trig_status
uint16_t bmiStatus = bmi270RegisterRead16(dev, BMI270_REG_FEATURES_0_GYR_GAIN_STATUS);
if (bmiStatus == 0x0000){
delay(10);
}
}
static uint8_t getBmiOsrMode()
{
switch(gyroConfig()->gyro_hardware_lpf) {
case GYRO_HARDWARE_LPF_NORMAL:
return BMI270_VAL_GYRO_CONF_BWP_OSR4;
case GYRO_HARDWARE_LPF_OPTION_1:
return BMI270_VAL_GYRO_CONF_BWP_OSR2;
case GYRO_HARDWARE_LPF_OPTION_2:
return BMI270_VAL_GYRO_CONF_BWP_NORM;
case GYRO_HARDWARE_LPF_EXPERIMENTAL:
return BMI270_VAL_GYRO_CONF_BWP_NORM;
}
return 0;
}
int8_t cas = 0;
static void bmi270Config(gyroDev_t *gyro)
{
extDevice_t *dev = &gyro->dev;
// If running in hardware_lpf experimental mode then switch to FIFO-based,
// 6.4KHz sampling, unfiltered data vs. the default 3.2KHz with hardware filtering
#ifdef USE_GYRO_DLPF_EXPERIMENTAL
const bool fifoMode = (gyro->hardware_lpf == GYRO_HARDWARE_LPF_EXPERIMENTAL);
#else
const bool fifoMode = false;
#endif
// Perform a soft reset to set all configuration to default
// Delay 100ms before continuing configuration
bmi270RegisterWrite(dev, BMI270_REG_CMD, BMI270_VAL_CMD_SOFTRESET, 100);
// Toggle the chip into SPI mode
bmi270EnableSPI(dev);
bmi270UploadConfig(dev);
bmi270PerformCRT(dev);
// Disable all sensors
bmi270RegisterWrite(dev, BMI270_REG_PWR_CTRL, BMI270_VAL_PWR_CTRL_DISABLE_ALL, 1);
// Configure the interface
// disable OIS, disable AUX, spi 4-wire mode
bmi270RegisterWrite(dev, BMI270_REG_IF_CONF, BMI270_VAL_IF_CONF_SET_INTERFACE, 1);
// Configure the FIFO
if (fifoMode) {
bmi270RegisterWrite(dev, BMI270_REG_FIFO_CONFIG_0, BMI270_VAL_FIFO_CONFIG_0, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_CONFIG_1, BMI270_VAL_FIFO_CONFIG_1, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_DOWNS, BMI270_VAL_FIFO_DOWNS, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_WTM_0, BMI270_VAL_FIFO_WTM_0, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_WTM_1, BMI270_VAL_FIFO_WTM_1, 1);
}
// Configure the accelerometer
bmi270RegisterWrite(dev, BMI270_REG_ACC_CONF, (BMI270_VAL_ACC_CONF_HP << 7) | (BMI270_VAL_ACC_CONF_BWP << 4) | BMI270_VAL_ACC_CONF_ODR800, 1);
// Configure the accelerometer full-scale range
bmi270RegisterWrite(dev, BMI270_REG_ACC_RANGE, BMI270_VAL_ACC_RANGE_16G, 1);
// Configure the gyro
bmi270RegisterWrite(dev, BMI270_REG_GYRO_CONF, (BMI270_VAL_GYRO_CONF_FILTER_PERF << 7) | (BMI270_VAL_GYRO_CONF_NOISE_PERF << 6) | (getBmiOsrMode() << 4) | BMI270_VAL_GYRO_CONF_ODR3200, 1);
// Configure the gyro full-range scale
bmi270RegisterWrite(dev, BMI270_REG_GYRO_RANGE, BMI270_VAL_GYRO_RANGE_2000DPS, 1);
// Configure the gyro data ready interrupt
if (fifoMode) {
// Interrupt driven by FIFO watermark level
bmi270RegisterWrite(dev, BMI270_REG_INT_MAP_DATA, BMI270_VAL_INT_MAP_FIFO_WM_INT1, 1);
} else {
// Interrupt driven by data ready
bmi270RegisterWrite(dev, BMI270_REG_INT_MAP_DATA, BMI270_VAL_INT_MAP_DATA_DRDY_INT1, 1);
}
// Configure the behavior of the INT1 pin
bmi270RegisterWrite(dev, BMI270_REG_INT1_IO_CTRL, BMI270_VAL_INT1_IO_CTRL_PINMODE, 1);
// Configure the device for high performance mode
bmi270RegisterWrite(dev, BMI270_REG_PWR_CONF, BMI270_VAL_PWR_CONF, 1);
// Enable the gyro, accelerometer and temperature sensor - disable aux interface
bmi270RegisterWrite(dev, BMI270_REG_PWR_CTRL, BMI270_VAL_PWR_CTRL, 1);
// Enable IOC
bmi270EnableIOC(dev);
// Flush the FIFO
if (fifoMode) {
bmi270RegisterWrite(dev, BMI270_REG_CMD, BMI270_VAL_CMD_FIFOFLUSH, 1);
}
// Read the CAS.zx factor
uint8_t casRaw = bmi270RegisterRead(dev, BMI270_REG_FEATURES_0_GYR_CAS);
cas = bmi270ProcessGyroCas(casRaw);
}
extiCallbackRec_t bmi270IntCallbackRec;
/*
* Gyro interrupt service routine
*/
#ifdef USE_GYRO_EXTI
// Called in ISR context
// Gyro read has just completed, next is CAS read
// Gyro read has just completed
busStatus_e bmi270Intcallback(uint32_t arg)
{
gyroDev_t *gyro = (gyroDev_t *)arg;
@ -480,20 +76,6 @@ void bmi270ExtiHandler(extiCallbackRec_t *cb)
gyro->detectedEXTI++;
}
static void bmi270IntExtiInit(gyroDev_t *gyro)
{
if (gyro->mpuIntExtiTag == IO_TAG_NONE) {
return;
}
IO_t mpuIntIO = IOGetByTag(gyro->mpuIntExtiTag);
IOInit(mpuIntIO, OWNER_GYRO_EXTI, 0);
EXTIHandlerInit(&gyro->exti, bmi270ExtiHandler);
EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EXTI, IOCFG_IN_FLOATING, BETAFLIGHT_EXTI_TRIGGER_RISING);
EXTIEnable(mpuIntIO);
}
#else
void bmi270ExtiHandler(extiCallbackRec_t *cb)
{
@ -502,7 +84,7 @@ void bmi270ExtiHandler(extiCallbackRec_t *cb)
}
#endif
static bool bmi270AccRead(accDev_t *acc)
bool bmi270AccRead(accDev_t *acc)
{
switch (acc->gyro->gyroModeSPI) {
case GYRO_EXTI_INT:
@ -547,7 +129,7 @@ static bool bmi270AccRead(accDev_t *acc)
return true;
}
static bool bmi270GyroReadRegister(gyroDev_t *gyro)
bool bmi270GyroReadRegister(gyroDev_t *gyro)
{
int16_t *gyroData = (int16_t *)gyro->dev.rxBuf;
switch (gyro->gyroModeSPI) {
@ -602,7 +184,7 @@ static bool bmi270GyroReadRegister(gyroDev_t *gyro)
spiWait(&gyro->dev);
// only x axis need overflow check
int32_t tempx = gyroData[1] - (int16_t)(cas * (int16_t)(gyroData[3]) / 512);
int32_t tempx = gyroData[1] - (int16_t)(bmi270CasFactor * (int16_t)(gyroData[3]) / 512);
if (tempx > 32767) {
gyro->gyroADCRaw[X] = 32767;
} else if (tempx < -32768) {
@ -618,7 +200,7 @@ static bool bmi270GyroReadRegister(gyroDev_t *gyro)
case GYRO_EXTI_INT_DMA:
{
int32_t tempx = gyroData[4] - (int16_t)(cas * (int16_t)(gyroData[6]) / 512);
int32_t tempx = gyroData[4] - (int16_t)(bmi270CasFactor * (int16_t)(gyroData[6]) / 512);
if (tempx > 32767) {
gyro->gyroADCRaw[X] = 32767;
} else if (tempx < -32768) {
@ -640,7 +222,7 @@ static bool bmi270GyroReadRegister(gyroDev_t *gyro)
}
#ifdef USE_GYRO_DLPF_EXPERIMENTAL
static bool bmi270GyroReadFifo(gyroDev_t *gyro)
bool bmi270GyroReadFifo(gyroDev_t *gyro)
{
enum {
IDX_REG = 0,
@ -695,14 +277,14 @@ static bool bmi270GyroReadFifo(gyroDev_t *gyro)
// would end up in a lock state of always re-reading the same partial or invalid sample.
if (fifoLength > 0) {
// Partial or additional frames left - flush the FIFO
bmi270RegisterWrite(&gyro->dev, BMI270_REG_CMD, BMI270_VAL_CMD_FIFOFLUSH, 0);
spiWriteReg(&gyro->dev, BMI270_REG_CMD, 0xB0);
}
return dataRead;
}
#endif
static bool bmi270GyroRead(gyroDev_t *gyro)
bool bmi270GyroRead(gyroDev_t *gyro)
{
#ifdef USE_GYRO_DLPF_EXPERIMENTAL
if (gyro->hardware_lpf == GYRO_HARDWARE_LPF_EXPERIMENTAL) {
@ -715,61 +297,4 @@ static bool bmi270GyroRead(gyroDev_t *gyro)
return bmi270GyroReadRegister(gyro);
}
}
static void bmi270SpiGyroInit(gyroDev_t *gyro)
{
extDevice_t *dev = &gyro->dev;
bmi270Config(gyro);
#if defined(USE_GYRO_EXTI)
bmi270IntExtiInit(gyro);
#endif
spiSetClkDivisor(dev, spiCalculateDivider(BMI270_MAX_SPI_CLK_HZ));
}
static void bmi270SpiAccInit(accDev_t *acc)
{
// sensor is configured during gyro init
acc->acc_1G = 512 * 4; // 16G sensor scale
}
bool bmi270SpiAccDetect(accDev_t *acc)
{
if (acc->mpuDetectionResult.sensor != BMI_270_SPI) {
return false;
}
acc->initFn = bmi270SpiAccInit;
acc->readFn = bmi270AccRead;
return true;
}
bool bmi270SpiGyroDetect(gyroDev_t *gyro)
{
if (gyro->mpuDetectionResult.sensor != BMI_270_SPI) {
return false;
}
gyro->initFn = bmi270SpiGyroInit;
gyro->readFn = bmi270GyroRead;
gyro->scale = GYRO_SCALE_2000DPS;
return true;
}
// Used to query the status register to determine what event caused the EXTI to fire.
// When in 3.2KHz mode the interrupt is mapped to the data ready state. However the data ready
// trigger will fire for both gyro and accelerometer. So it's necessary to check this register
// to determine which event caused the interrupt.
// When in 6.4KHz mode the interrupt is configured to be the FIFO watermark size of 6 bytes.
// Since in this mode we only put gyro data in the FIFO it's sufficient to check for the FIFO
// watermark reason as an idication of gyro data ready.
uint8_t bmi270InterruptStatus(gyroDev_t *gyro)
{
return bmi270RegisterRead(&gyro->dev, BMI270_REG_INT_STATUS_1);
}
#endif // USE_ACCGYRO_BMI270
#endif // USE_ACCGYRO_SPI_BMI270

View File

@ -21,8 +21,69 @@
#pragma once
#include "drivers/bus.h"
#include "drivers/exti.h"
// BMI270 registers (not the complete list)
typedef enum {
BMI270_REG_CHIP_ID = 0x00,
BMI270_REG_ERR_REG = 0x02,
BMI270_REG_STATUS = 0x03,
BMI270_REG_ACC_DATA_X_LSB = 0x0C,
BMI270_REG_GYR_DATA_X_LSB = 0x12,
BMI270_REG_SENSORTIME_0 = 0x18,
BMI270_REG_SENSORTIME_1 = 0x19,
BMI270_REG_SENSORTIME_2 = 0x1A,
BMI270_REG_EVENT = 0x1B,
BMI270_REG_INT_STATUS_0 = 0x1C,
BMI270_REG_INT_STATUS_1 = 0x1D,
BMI270_REG_INTERNAL_STATUS = 0x21,
BMI270_REG_TEMPERATURE_LSB = 0x22,
BMI270_REG_TEMPERATURE_MSB = 0x23,
BMI270_REG_FIFO_LENGTH_LSB = 0x24,
BMI270_REG_FIFO_LENGTH_MSB = 0x25,
BMI270_REG_FIFO_DATA = 0x26,
BMI270_REG_FEAT_PAGE = 0x2F,
BMI270_REG_FEATURES_0_GYR_GAIN_STATUS = 0x38,
BMI270_REG_FEATURES_0_GYR_CAS = 0x3C,
BMI270_REG_FEATURES_1_G_TRIG_1 = 0x32,
BMI270_REG_FEATURES_1_GEN_SET_1 = 0x34,
BMI270_REG_ACC_CONF = 0x40,
BMI270_REG_ACC_RANGE = 0x41,
BMI270_REG_GYRO_CONF = 0x42,
BMI270_REG_GYRO_RANGE = 0x43,
BMI270_REG_AUX_CONF = 0x44,
BMI270_REG_FIFO_DOWNS = 0x45,
BMI270_REG_FIFO_WTM_0 = 0x46,
BMI270_REG_FIFO_WTM_1 = 0x47,
BMI270_REG_FIFO_CONFIG_0 = 0x48,
BMI270_REG_FIFO_CONFIG_1 = 0x49,
BMI270_REG_SATURATION = 0x4A,
BMI270_REG_INT1_IO_CTRL = 0x53,
BMI270_REG_INT2_IO_CTRL = 0x54,
BMI270_REG_INT_LATCH = 0x55,
BMI270_REG_INT1_MAP_FEAT = 0x56,
BMI270_REG_INT2_MAP_FEAT = 0x57,
BMI270_REG_INT_MAP_DATA = 0x58,
BMI270_REG_INIT_CTRL = 0x59,
BMI270_REG_INIT_DATA = 0x5E,
BMI270_REG_GYR_CRT_CONF = 0x69,
BMI270_REG_IF_CONF = 0x6B,
BMI270_REG_ACC_SELF_TEST = 0x6D,
BMI270_REG_GYR_SELF_TEST_AXES = 0x6E,
BMI270_REG_OFFSET_6 = 0x77,
BMI270_REG_PWR_CONF = 0x7C,
BMI270_REG_PWR_CTRL = 0x7D,
BMI270_REG_CMD = 0x7E,
} bmi270Register_e;
extern int8_t bmi270CasFactor;
// Contained in accgyro_spi_bmi270_init.c which is size-optimized
uint8_t bmi270Detect(const extDevice_t *dev);
bool bmi270SpiAccDetect(accDev_t *acc);
bool bmi270SpiGyroDetect(gyroDev_t *gyro);
// Contained in accgyro_spi_bmi270.c which is speed-optimized
uint8_t bmi270InterruptStatus(gyroDev_t *gyro);
void bmi270ExtiHandler(extiCallbackRec_t* cb);
bool bmi270AccRead(accDev_t *acc);
bool bmi270GyroRead(gyroDev_t *gyro);

View File

@ -0,0 +1,448 @@
/*
* This file is part of Cleanflight and Betaflight.
*
* Cleanflight and Betaflight are free software. You can redistribute
* this software and/or modify this software under the terms of the
* GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Cleanflight and Betaflight are distributed in the hope that they
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software.
*
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "platform.h"
#ifdef USE_ACCGYRO_BMI270
#include "drivers/accgyro/accgyro.h"
#include "drivers/accgyro/accgyro_spi_bmi270.h"
#include "drivers/bus_spi.h"
#include "drivers/exti.h"
#include "drivers/io.h"
#include "drivers/io_impl.h"
#include "drivers/nvic.h"
#include "drivers/sensor.h"
#include "drivers/system.h"
#include "drivers/time.h"
#include "sensors/gyro.h"
// #include "build/debug.h"
// 10 MHz max SPI frequency
#define BMI270_MAX_SPI_CLK_HZ 10000000
#define BMI270_CONFIG_SIZE 8192
// Declaration for the device config (microcode) that must be uploaded to the sensor
extern const uint8_t bmi270_config_file[BMI270_CONFIG_SIZE];
#define BMI270_CHIP_ID 0x24
#define BMI270_GYRO_CAS_MASK 0x7F
#define BMI270_GYRO_CAS_SIGN_BIT_MASK 0x40
int8_t bmi270CasFactor = 0;
// BMI270 register configuration values
typedef enum {
BMI270_VAL_CMD_G_TRIGGER = 0x02,
BMI270_VAL_CMD_SOFTRESET = 0xB6,
BMI270_VAL_CMD_FIFOFLUSH = 0xB0,
BMI270_VAL_PWR_CTRL_DISABLE_ALL = 0x00, // disable all sensors
BMI270_VAL_PWR_CTRL = 0x0E, // enable gyro, acc and temp sensors
BMI270_VAL_PWR_CTRL_ACC_ENABLE = BIT(2), // bit 2, enable acc
BMI270_VAL_PWR_CTRL_ACC_DISABLE = 0x00, // bit 2, disable gyro
BMI270_VAL_PWR_CONF_ADV_POWER_SAVE_DISABLE = 0x00, // disable ADV PS
BMI270_VAL_PWR_CONF_ADV_POWER_SAVE_ENABLE = BIT(0), // enable ADV PS
BMI270_VAL_PWR_CONF = 0x02, // disable advanced power save, enable FIFO self-wake
BMI270_VAL_PAGE_0 = 0x00, // select page 0
BMI270_VAL_PAGE_1 = 0x01, // select page 1
BMI270_VAL_ACC_CONF_ODR800 = 0x0B, // set acc sample rate to 800hz
BMI270_VAL_ACC_CONF_ODR1600 = 0x0C, // set acc sample rate to 1600hz
BMI270_VAL_ACC_CONF_BWP = 0x01, // set acc filter in osr2 mode
BMI270_VAL_ACC_CONF_HP = 0x01, // set acc in high performance mode
BMI270_VAL_ACC_RANGE_8G = 0x02, // set acc to 8G full scale
BMI270_VAL_ACC_RANGE_16G = 0x03, // set acc to 16G full scale
BMI270_VAL_GYRO_CONF_ODR3200 = 0x0D, // set gyro sample rate to 3200hz
BMI270_VAL_GYRO_CONF_BWP_OSR4 = 0x00, // set gyro filter in OSR4 mode
BMI270_VAL_GYRO_CONF_BWP_OSR2 = 0x01, // set gyro filter in OSR2 mode
BMI270_VAL_GYRO_CONF_BWP_NORM = 0x02, // set gyro filter in normal mode
BMI270_VAL_GYRO_CONF_NOISE_PERF = 0x01, // set gyro in high performance noise mode
BMI270_VAL_GYRO_CONF_FILTER_PERF = 0x01, // set gyro in high performance filter mode
BMI270_VAL_GYRO_RANGE_2000DPS = 0x08, // set gyro to 2000dps full scale
// for some reason you have to enable the ois_range bit (bit 3) for 2000dps as well
// or else the gyro scale will be 250dps when in prefiltered FIFO mode (not documented in datasheet!)
BMI270_VAL_INT_MAP_DATA_DRDY_INT1 = 0x04, // enable the data ready interrupt pin 1
BMI270_VAL_INT_MAP_FIFO_WM_INT1 = 0x02, // enable the FIFO watermark interrupt pin 1
BMI270_VAL_INT1_IO_CTRL_PINMODE = 0x0A, // active high, push-pull, output enabled, input disabled
BMI270_VAL_IF_CONF_SET_INTERFACE = 0x00, // spi 4-wire mode, disable OIS, disable AUX
BMI270_VAL_FIFO_CONFIG_0 = 0x00, // don't stop when full, disable sensortime frame
BMI270_VAL_FIFO_CONFIG_1 = 0x80, // only gyro data in FIFO, use headerless mode
BMI270_VAL_FIFO_DOWNS = 0x00, // select unfiltered gyro data with no downsampling (6.4KHz samples)
BMI270_VAL_FIFO_WTM_0 = 0x06, // set the FIFO watermark level to 1 gyro sample (6 bytes)
BMI270_VAL_FIFO_WTM_1 = 0x00, // FIFO watermark MSB
BMI270_VAL_GEN_SET_1 = 0x0200, // bit 9, enable self offset correction (IOC part 1)
BMI270_VAL_OFFSET_6 = 0xC0, // Enable sensitivity error compensation and gyro offset compensation (IOC part2)
BMI270_VAL_OFFSET_6_GYR_GAIN_EN_ENABLE = BIT(7), // bit 7, enable gyro gain compensation
BMI270_VAL_GYR_CRT_CONF_CRT_RUNNING = BIT(2), // bit 7, enable gyro crt
BMI270_VAL_FEATURES_1_G_TRIG_1_SELECT_CRT = 0x0100, // bit 8, CRT will be executed
BMI270_VAL_FEATURES_1_G_TRIG_1_SELECT_GYR_BIST=0x0000, // bit 8, gyro built-in self-test will be executed
BMI270_VAL_FEATURES_1_G_TRIG_1_BLOCK_UNLOCK = 0x0000,// bit 9, do not block further G_TRIGGER commands
BMI270_VAL_FEATURES_1_G_TRIG_1_BLOCK_BLOCK = 0x0200, // bit 9, block further G_TRIGGER commands
} bmi270ConfigValues_e;
typedef enum {
BMI270_MASK_FEATURES_1_GEN_SET_1 = 0x0200,
BMI270_MASK_OFFSET_6 = 0xC0,
BMI270_MASK_OFFSET_6_GYR_GAIN_ENABLE = 0x80, // bit 7, enable gyro gain compensation
BMI270_MASK_PWR_ADV_POWER_SAVE = 0x01, // bit 0, enable advanced power save
BMI270_MASK_PWR_CTRL_ACC_ENABLE = 0x04, // bit 2, enable acc
BMI270_MASK_GYR_CRT_CONF_CRT_RUNNING = 0x04, // bit 2, gyro CRT running
BMI270_MASK_G_TRIG_1_SELECT = 0x0100, // bit 8, select feature that should be executed
BMI270_MASK_G_TRIG_1_BLOCK = 0x0200, // bit 9, block feature with next G_TRIGGER CMD
BMI270_MASK_GYR_GAIN_STATUS_G_TRIG_STATUS = 0x38 // bit[5:3]
} bmi270ConfigMasks_e;
// BMI270 register reads are 16bits with the first byte a "dummy" value 0
// that must be ignored. The result is in the second byte.
static uint8_t bmi270RegisterRead(const extDevice_t *dev, bmi270Register_e registerId)
{
uint8_t data[2] = { 0, 0 };
if (spiReadRegMskBufRB(dev, registerId, data, 2)) {
return data[1];
} else {
return 0;
}
}
static uint16_t bmi270RegisterRead16(const extDevice_t *dev, bmi270Register_e registerId)
{
uint8_t data[3] = { 0, 0, 0 };
if (spiReadRegMskBufRB(dev, registerId, data, 3)) {
return (uint16_t)( (data[2]<<8) | data[1] ); // LSB first since address is auto-incremented
} else {
return 0;
}
}
static void bmi270RegisterWrite(const extDevice_t *dev, bmi270Register_e registerId, uint8_t value, unsigned delayMs)
{
spiWriteReg(dev, registerId, value);
if (delayMs) {
delay(delayMs);
}
}
static void bmi270RegisterWriteBits(const extDevice_t *dev, bmi270Register_e registerID, bmi270ConfigMasks_e mask, uint8_t value, unsigned delayMs)
{
uint8_t newValue = bmi270RegisterRead(dev, registerID);
delayMicroseconds(2);
newValue = (newValue & ~mask) | value;
bmi270RegisterWrite(dev, registerID, newValue, delayMs);
}
static void bmi270RegisterWrite16(const extDevice_t *dev, bmi270Register_e registerId, uint16_t data, unsigned delayMs)
{
uint8_t buf[2] = {
(uint8_t)(data & 0x00FF),
(uint8_t)(data >> 8)
};
spiWriteRegBuf(dev, registerId, buf, 2);
if (delayMs) {
delay(delayMs);
}
}
static void bmi270RegisterWriteBits16(const extDevice_t *dev, bmi270Register_e registerID, bmi270ConfigMasks_e mask, uint16_t value, unsigned delayMs)
{
uint16_t newValue = bmi270RegisterRead16(dev, registerID);
delayMicroseconds(2);
newValue = (newValue & ~mask) | value;
bmi270RegisterWrite16(dev, registerID, newValue, delayMs);
}
// Toggle the CS to switch the device into SPI mode.
// Device switches initializes as I2C and switches to SPI on a low to high CS transition
static void bmi270EnableSPI(const extDevice_t *dev)
{
IOLo(dev->busType_u.spi.csnPin);
delay(1);
IOHi(dev->busType_u.spi.csnPin);
delay(10);
}
uint8_t bmi270Detect(const extDevice_t *dev)
{
bmi270EnableSPI(dev);
if (bmi270RegisterRead(dev, BMI270_REG_CHIP_ID) == BMI270_CHIP_ID) {
return BMI_270_SPI;
}
return MPU_NONE;
}
static int8_t bmi270ProcessGyroCas(uint8_t raw)
{
int8_t result = 0;
raw = raw & BMI270_GYRO_CAS_MASK;
if ((raw & BMI270_GYRO_CAS_SIGN_BIT_MASK) == 0) {
result = (int8_t)(raw);
} else {
result = (int8_t)(raw - 128);
}
return result;
}
static void bmi270UploadConfig(const extDevice_t *dev)
{
bmi270RegisterWrite(dev, BMI270_REG_PWR_CONF, 0, 1);
bmi270RegisterWrite(dev, BMI270_REG_INIT_CTRL, 0, 1);
// Transfer the config file
spiWriteRegBuf(dev, BMI270_REG_INIT_DATA, (uint8_t *)bmi270_config_file, sizeof(bmi270_config_file));
delay(10);
bmi270RegisterWrite(dev, BMI270_REG_INIT_CTRL, 1, 1);
}
static void bmi270EnableIOC(const extDevice_t *dev)
{
// Configure the feature register page to page 1
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_1, 1);
// Enable self offset correction
bmi270RegisterWriteBits16(dev, BMI270_REG_FEATURES_1_GEN_SET_1, BMI270_MASK_FEATURES_1_GEN_SET_1, BMI270_VAL_GEN_SET_1, 1);
// Enable IOC
bmi270RegisterWriteBits(dev, BMI270_REG_OFFSET_6, BMI270_MASK_OFFSET_6, 0x40, 1);
// Configure the feature register page to page 0
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_0, 1);
}
static void bmi270PerformCRT(const extDevice_t *dev)
{
// disable advance power save mode
bmi270RegisterWriteBits(dev, BMI270_REG_PWR_CONF, BMI270_MASK_PWR_ADV_POWER_SAVE, BMI270_VAL_PWR_CONF_ADV_POWER_SAVE_DISABLE, 10);
// enable gyro gain compensation, set OFFSET_6.gain_comp_en = 1
bmi270RegisterWriteBits(dev, BMI270_REG_OFFSET_6, BMI270_MASK_OFFSET_6_GYR_GAIN_ENABLE, BMI270_VAL_OFFSET_6_GYR_GAIN_EN_ENABLE, 10);
// enable acc, set pwr_ctrl.acc_en = 1
bmi270RegisterWriteBits(dev, BMI270_REG_PWR_CTRL, BMI270_MASK_PWR_CTRL_ACC_ENABLE, BMI270_VAL_PWR_CTRL_ACC_ENABLE, 10);
// set GYR_CRT_CONF.crt_running = 0b1
bmi270RegisterWriteBits(dev, BMI270_REG_GYR_CRT_CONF, BMI270_MASK_GYR_CRT_CONF_CRT_RUNNING, BMI270_VAL_GYR_CRT_CONF_CRT_RUNNING, 10);
// set page to 1
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_1, 10);
// set G_TRIG_1.select =1
bmi270RegisterWriteBits16(dev, BMI270_REG_FEATURES_1_G_TRIG_1, BMI270_MASK_G_TRIG_1_SELECT, BMI270_VAL_FEATURES_1_G_TRIG_1_SELECT_CRT, 10);
// set G_TRIG_1.block = 0
// bmi270RegisterWriteBits16(dev, BMI270_REG_FEATURES_1_G_TRIG_1, BMI270_MASK_G_TRIG_1_BLOCK, BMI270_VAL_FEATURES_1_G_TRIG_1_BLOCK_UNLOCK, 1);
// send g_trigger command to CMD reg
bmi270RegisterWrite(dev, BMI270_REG_CMD, BMI270_VAL_CMD_G_TRIGGER, 5000);
// read GYR_CRT_CONF.crt_running and check if it is 0
uint8_t bmiCheck = bmi270RegisterRead(dev, BMI270_REG_GYR_CRT_CONF);
// if not, wait for 2 seconds and check again max time for 5
uint8_t checkCount = 0;
while ((bmiCheck!=0x00) && (checkCount++ < 5)) {
bmiCheck = bmi270RegisterRead(dev, BMI270_REG_GYR_CRT_CONF);
delay(1000);
if (bmiCheck == 0x00) {
break;
}
}
delay(100);
// set page to 0
bmi270RegisterWrite(dev, BMI270_REG_FEAT_PAGE, BMI270_VAL_PAGE_0, 1);
// read GYR_GAIN_STATUS.g_trig_status
uint16_t bmiStatus = bmi270RegisterRead16(dev, BMI270_REG_FEATURES_0_GYR_GAIN_STATUS);
if (bmiStatus == 0x0000){
delay(10);
}
}
static uint8_t getBmiOsrMode()
{
switch(gyroConfig()->gyro_hardware_lpf) {
case GYRO_HARDWARE_LPF_NORMAL:
return BMI270_VAL_GYRO_CONF_BWP_OSR4;
case GYRO_HARDWARE_LPF_OPTION_1:
return BMI270_VAL_GYRO_CONF_BWP_OSR2;
case GYRO_HARDWARE_LPF_OPTION_2:
return BMI270_VAL_GYRO_CONF_BWP_NORM;
case GYRO_HARDWARE_LPF_EXPERIMENTAL:
return BMI270_VAL_GYRO_CONF_BWP_NORM;
}
return 0;
}
static void bmi270Config(gyroDev_t *gyro)
{
extDevice_t *dev = &gyro->dev;
// If running in hardware_lpf experimental mode then switch to FIFO-based,
// 6.4KHz sampling, unfiltered data vs. the default 3.2KHz with hardware filtering
#ifdef USE_GYRO_DLPF_EXPERIMENTAL
const bool fifoMode = (gyro->hardware_lpf == GYRO_HARDWARE_LPF_EXPERIMENTAL);
#else
const bool fifoMode = false;
#endif
// Perform a soft reset to set all configuration to default
// Delay 100ms before continuing configuration
bmi270RegisterWrite(dev, BMI270_REG_CMD, BMI270_VAL_CMD_SOFTRESET, 100);
// Toggle the chip into SPI mode
bmi270EnableSPI(dev);
bmi270UploadConfig(dev);
bmi270PerformCRT(dev);
// Disable all sensors
bmi270RegisterWrite(dev, BMI270_REG_PWR_CTRL, BMI270_VAL_PWR_CTRL_DISABLE_ALL, 1);
// Configure the interface
// disable OIS, disable AUX, spi 4-wire mode
bmi270RegisterWrite(dev, BMI270_REG_IF_CONF, BMI270_VAL_IF_CONF_SET_INTERFACE, 1);
// Configure the FIFO
if (fifoMode) {
bmi270RegisterWrite(dev, BMI270_REG_FIFO_CONFIG_0, BMI270_VAL_FIFO_CONFIG_0, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_CONFIG_1, BMI270_VAL_FIFO_CONFIG_1, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_DOWNS, BMI270_VAL_FIFO_DOWNS, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_WTM_0, BMI270_VAL_FIFO_WTM_0, 1);
bmi270RegisterWrite(dev, BMI270_REG_FIFO_WTM_1, BMI270_VAL_FIFO_WTM_1, 1);
}
// Configure the accelerometer
bmi270RegisterWrite(dev, BMI270_REG_ACC_CONF, (BMI270_VAL_ACC_CONF_HP << 7) | (BMI270_VAL_ACC_CONF_BWP << 4) | BMI270_VAL_ACC_CONF_ODR800, 1);
// Configure the accelerometer full-scale range
bmi270RegisterWrite(dev, BMI270_REG_ACC_RANGE, BMI270_VAL_ACC_RANGE_16G, 1);
// Configure the gyro
bmi270RegisterWrite(dev, BMI270_REG_GYRO_CONF, (BMI270_VAL_GYRO_CONF_FILTER_PERF << 7) | (BMI270_VAL_GYRO_CONF_NOISE_PERF << 6) | (getBmiOsrMode() << 4) | BMI270_VAL_GYRO_CONF_ODR3200, 1);
// Configure the gyro full-range scale
bmi270RegisterWrite(dev, BMI270_REG_GYRO_RANGE, BMI270_VAL_GYRO_RANGE_2000DPS, 1);
// Configure the gyro data ready interrupt
if (fifoMode) {
// Interrupt driven by FIFO watermark level
bmi270RegisterWrite(dev, BMI270_REG_INT_MAP_DATA, BMI270_VAL_INT_MAP_FIFO_WM_INT1, 1);
} else {
// Interrupt driven by data ready
bmi270RegisterWrite(dev, BMI270_REG_INT_MAP_DATA, BMI270_VAL_INT_MAP_DATA_DRDY_INT1, 1);
}
// Configure the behavior of the INT1 pin
bmi270RegisterWrite(dev, BMI270_REG_INT1_IO_CTRL, BMI270_VAL_INT1_IO_CTRL_PINMODE, 1);
// Configure the device for high performance mode
bmi270RegisterWrite(dev, BMI270_REG_PWR_CONF, BMI270_VAL_PWR_CONF, 1);
// Enable the gyro, accelerometer and temperature sensor - disable aux interface
bmi270RegisterWrite(dev, BMI270_REG_PWR_CTRL, BMI270_VAL_PWR_CTRL, 1);
// Enable IOC
bmi270EnableIOC(dev);
// Flush the FIFO
if (fifoMode) {
bmi270RegisterWrite(dev, BMI270_REG_CMD, BMI270_VAL_CMD_FIFOFLUSH, 1);
}
// Read the CAS.zx factor
uint8_t casRaw = bmi270RegisterRead(dev, BMI270_REG_FEATURES_0_GYR_CAS);
bmi270CasFactor = bmi270ProcessGyroCas(casRaw);
}
#ifdef USE_GYRO_EXTI
static void bmi270IntExtiInit(gyroDev_t *gyro)
{
if (gyro->mpuIntExtiTag == IO_TAG_NONE) {
return;
}
IO_t mpuIntIO = IOGetByTag(gyro->mpuIntExtiTag);
IOInit(mpuIntIO, OWNER_GYRO_EXTI, 0);
EXTIHandlerInit(&gyro->exti, bmi270ExtiHandler);
EXTIConfig(mpuIntIO, &gyro->exti, NVIC_PRIO_MPU_INT_EXTI, IOCFG_IN_FLOATING, BETAFLIGHT_EXTI_TRIGGER_RISING);
EXTIEnable(mpuIntIO);
}
#endif
static void bmi270SpiGyroInit(gyroDev_t *gyro)
{
extDevice_t *dev = &gyro->dev;
bmi270Config(gyro);
#ifdef USE_GYRO_EXTI
bmi270IntExtiInit(gyro);
#endif
spiSetClkDivisor(dev, spiCalculateDivider(BMI270_MAX_SPI_CLK_HZ));
}
static void bmi270SpiAccInit(accDev_t *acc)
{
// sensor is configured during gyro init
acc->acc_1G = 512 * 4; // 16G sensor scale
}
bool bmi270SpiAccDetect(accDev_t *acc)
{
if (acc->mpuDetectionResult.sensor != BMI_270_SPI) {
return false;
}
acc->initFn = bmi270SpiAccInit;
acc->readFn = bmi270AccRead;
return true;
}
bool bmi270SpiGyroDetect(gyroDev_t *gyro)
{
if (gyro->mpuDetectionResult.sensor != BMI_270_SPI) {
return false;
}
gyro->initFn = bmi270SpiGyroInit;
gyro->readFn = bmi270GyroRead;
gyro->scale = GYRO_SCALE_2000DPS;
return true;
}
#endif // USE_ACCGYRO_BMI270

View File

@ -13,6 +13,7 @@ TARGET_SRC = \
drivers/compass/compass_hmc5883l.c\
drivers/compass/compass_qmc5883l.c\
$(ROOT)/lib/main/BoschSensortec/BMI270-Sensor-API/bmi270.c \
drivers/accgyro/accgyro_spi_bmi270_init.c \
drivers/accgyro/accgyro_spi_bmi270.c\
drivers/accgyro/accgyro_spi_asm330lhh_init.c \
drivers/accgyro/accgyro_spi_asm330lhh.c \

View File

@ -13,6 +13,7 @@ TARGET_SRC = \
drivers/compass/compass_hmc5883l.c\
drivers/compass/compass_qmc5883l.c\
$(ROOT)/lib/main/BoschSensortec/BMI270-Sensor-API/bmi270.c \
drivers/accgyro/accgyro_spi_bmi270_init.c \
drivers/accgyro/accgyro_spi_bmi270.c\
drivers/accgyro/accgyro_spi_asm330lhh_init.c \
drivers/accgyro/accgyro_spi_asm330lhh.c \

View File

@ -12,6 +12,7 @@ TARGET_SRC = \
drivers/compass/compass_hmc5883l.c\
drivers/compass/compass_qmc5883l.c\
$(ROOT)/lib/main/BoschSensortec/BMI270-Sensor-API/bmi270.c \
drivers/accgyro/accgyro_spi_bmi270_init.c \
drivers/accgyro/accgyro_spi_bmi270.c\
drivers/accgyro/accgyro_spi_asm330lhh_init.c \
drivers/accgyro/accgyro_spi_asm330lhh.c \

View File

@ -12,6 +12,7 @@ TARGET_SRC = \
drivers/compass/compass_hmc5883l.c\
drivers/compass/compass_qmc5883l.c\
$(ROOT)/lib/main/BoschSensortec/BMI270-Sensor-API/bmi270.c \
drivers/accgyro/accgyro_spi_bmi270_init.c \
drivers/accgyro/accgyro_spi_bmi270.c\
drivers/accgyro/accgyro_spi_asm330lhh_init.c \
drivers/accgyro/accgyro_spi_asm330lhh.c \