BMI088是一款高性能6轴惯性传感器,由16位数字三轴±24g加速度计和16位数字三轴±2000°/ s陀螺仪组成。
这里用SPI来驱动BMI088进行数据解读
-
第一步,首先在 RT-Thread Settings中进行配置
-
第二步,退出RT-Thread Settings,进入board.h,定义宏
-
第三步,**进入stm32f4xx_hal_conf.h **
-
第四步,STM32 CubeMX配置
-
第五步,添加驱动文件到application
bmi088.c
c
#include "bmi088.h"
#include <rtdbg.h>
#include <rtdevice.h>
#include <board.h>
#include "drv_spi.h"
#define BMI088_SPI_MAX_SPEED (10 * 1000 * 1000) // M
#define CSB1_Pin GET_PIN(B, 14)
#define CSB2_Pin GET_PIN(B, 15)
static rt_err_t _bmi088_spi_read(struct rt_spi_device *dev, rt_uint8_t reg_addr, const rt_uint8_t len, rt_uint8_t *buf)
{
reg_addr |= 0x80;
dev->bus->owner = dev;
rt_spi_send_then_recv(dev, ®_addr, 1, buf, len);
return RT_EOK;
}
static rt_err_t _bmi088_spi_write(struct rt_spi_device *dev, rt_uint8_t reg_addr, const rt_uint8_t len, rt_uint8_t *buf)
{
reg_addr &= 0x7f;
dev->bus->owner = dev;
rt_spi_send_then_send(dev, ®_addr, 1, buf, len);
return RT_EOK;
}
static rt_err_t _bmi088_get_accel_raw(struct bmi08x_dev *dev, struct bmi088_3axes *accel)
{
rt_uint8_t buffer[10];
uint8_t lsb, msb;
rt_err_t res;
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->accel_bus);
res = _bmi088_spi_read(spi_dev, ACC_X_LSB_REG, 10, buffer);
if (res != RT_EOK)
{
return res;
}
lsb = buffer[1];
msb = buffer[2];
accel->x = (rt_int16_t)((msb << 8) | lsb); /* X */
lsb = buffer[3];
msb = buffer[4];
accel->y = (rt_int16_t)((msb << 8) | lsb);/* Y */
lsb = buffer[5];
msb = buffer[6];
accel->z = (rt_int16_t)((msb << 8) | lsb);/* Z */
return RT_EOK;
}
static rt_err_t _bmi088_get_gyro_raw(struct bmi08x_dev *dev, struct bmi088_3axes *gyro)
{
rt_uint8_t buffer[6];
uint8_t lsb, msb;
rt_err_t res;
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->gyro_bus);
res = _bmi088_spi_read(spi_dev, RATE_X_LSB_REG, 6, buffer);
if (res != RT_EOK)
{
return res;
}
lsb = buffer[0];
msb = buffer[1];
gyro->x = (rt_int16_t)((msb * 256) + lsb); /* X */
lsb = buffer[2];
msb = buffer[3];
gyro->y = (rt_int16_t)((msb * 256) + lsb); /* Y */
lsb = buffer[4];
msb = buffer[5];
gyro->z = (rt_int16_t)((msb * 256) + lsb); /* Z */
return RT_EOK;
}
/**
* This function gets the data of the accelerometer, unit: m/ss
*
* @param dev the pointer of device driver structure
* @param accel the pointer of 3axes structure for receive data
*
* @return the reading number.
*/
rt_size_t bmi088_get_accel(struct bmi08x_dev *dev, struct bmi088_data *buf)
{
struct bmi088_3axes tmp;
_bmi088_get_accel_raw(dev, &tmp);
buf->x = ((float)tmp.x) /32768.0f * 6 * G;
buf->y = ((float)tmp.y) /32768.0f * 6 * G;
buf->z = ((float)tmp.z) /32768.0f * 6 * G;
return 1;// just support rw mode
}
/**
* This function gets the data of the gyroscope, unit: rad/s
*
* @param dev the pointer of device driver structure
* @param gyro the pointer of 3axes structure for receive data
*
* @return the reading number.
*/
rt_size_t bmi088_get_gyro(struct bmi08x_dev *dev, struct bmi088_data *buf)
{
struct bmi088_3axes tmp;
_bmi088_get_gyro_raw(dev, &tmp);
buf->x = (float)tmp.x / 32767.0f * 2000.0f;
buf->y = (float)tmp.y / 32767.0f * 2000.0f;
buf->z = (float)tmp.z / 32767.0f * 2000.0f;
return 1;
}
/**
* This function software reset the accelerometer of bmi08x.
*
* @param dev the pointer of bmi08x driver structure
*
* @return the status of software reset, RT_EOK represents software reset successfully.
*/
static rt_err_t _bmi088a_soft_reset(struct bmi08x_dev *dev)
{
uint8_t send_cmd = BMI08X_SOFT_RESET_CMD;
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->accel_bus);
if (_bmi088_spi_write(spi_dev, ACC_SOFTRESET_REG, 1, &send_cmd) == RT_EOK)
{
rt_thread_mdelay(BMI08X_ACCEL_SOFTRESET_DELAY_MS);
return RT_EOK;
}
else
{
return RT_ERROR;
}
}
/**
* This function software reset the gyroscope of bmi08x.
*
* @param dev the pointer of bmi08x driver structure
*
* @return the status of software reset, RT_EOK represents software reset successfully.
*/
static rt_err_t _bmi088g_soft_reset(struct bmi08x_dev *dev)
{
uint8_t send_cmd = BMI08X_SOFT_RESET_CMD;
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->gyro_bus);
if (_bmi088_spi_write(spi_dev, GYRO_SOFTRESET_REG, 1, &send_cmd) == RT_EOK)
{
rt_thread_mdelay(BMI08X_GYRO_SOFTRESET_DELAY_MS);
return RT_EOK;
}
else
{
return RT_ERROR;
}
}
/**
* This function initialize the accelerometer of bmi08x.
*
* @param dev the pointer of bmi08x driver structure
*
* @return the status of initialization, RT_EOK represents initialize successfully.
*/
static rt_err_t _bmi088a_init(struct bmi08x_dev *dev)
{
rt_err_t res = RT_EOK;
uint8_t chip_acc_id[2] = {0};
// config acc to spi mode
rt_pin_write(dev->accel_id, PIN_LOW);
rt_thread_mdelay(1);
rt_pin_write(dev->accel_id, PIN_HIGH);
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->accel_bus);
_bmi088_spi_read(spi_dev, ACC_CHIP_ID_REG, 2, chip_acc_id); /* Dummy read */
if (chip_acc_id[1] != dev->accel_chip_id)
{
LOG_E("Fail initialize acc");
goto __exit;
}
rt_thread_mdelay(10);
res = _bmi088a_soft_reset(dev);
// config acc to spi mode
rt_pin_write(dev->accel_id, PIN_LOW);
rt_thread_mdelay(1);
rt_pin_write(dev->accel_id, PIN_HIGH);
return res;
__exit:
return RT_ERROR;
}
/**
* This function initialize the gyroscope of bmi08x.
*
* @param dev the pointer of bmi08x driver structure
*
* @return the status of initialization, RT_EOK represents initialize successfully.
*/
static rt_err_t _bmi088g_init(struct bmi08x_dev *dev)
{
rt_err_t res = RT_EOK;
rt_uint8_t id = 0;
struct rt_spi_device *spi_dev = (struct rt_spi_device *)dev->gyro_bus;
_bmi088_spi_read(spi_dev, GYRO_CHIP_ID_REG, 1, &id);
if (id != dev->gyro_chip_id)
{
LOG_E("Fail initialize gyro");
goto __exit;
}
rt_thread_mdelay(10);
res = _bmi088g_soft_reset(dev);
return res;
__exit:
return RT_ERROR;
}
/**
* This function set the power mode of accelerometer of bmi08x
*
* @param dev the pointer of bmi08x driver structure
*
* @return the setting status, RT_EOK represents reading the data successfully.
*/
rt_err_t bmi088a_set_power_mode(struct bmi08x_dev *dev)
{
uint8_t power_mode = dev->accel_cfg.power;
uint8_t data[2];
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->accel_bus);
if (power_mode == BMI08X_ACCEL_PM_ACTIVE)
{
data[0] = BMI08X_ACCEL_PWR_ACTIVE_CMD;
data[1] = BMI08X_ACCEL_POWER_ENABLE_CMD;
}
else if (power_mode == BMI08X_ACCEL_PM_SUSPEND)
{
data[0] = BMI08X_ACCEL_PWR_SUSPEND_CMD;
data[1] = BMI08X_ACCEL_POWER_DISABLE_CMD;
}
else
{
LOG_E("Invalid acc power mode!");
goto __exit;
}
if (_bmi088_spi_write(spi_dev, ACC_PWR_CONF_REG, 1, &data[0]) == RT_EOK)
{
rt_thread_mdelay(BMI08X_POWER_CONFIG_DELAY);
data[1] = BMI08X_ACCEL_POWER_ENABLE_CMD;
if (_bmi088_spi_write(spi_dev, ACC_PWR_CTRL_REG, 1, &data[1]) == RT_EOK)
{
rt_thread_mdelay(BMI08X_POWER_CONFIG_DELAY);
return RT_EOK;
}
else
{
LOG_E("Failed write CTRL_REG");
goto __exit;
}
}
else
{
LOG_E("Failed write PWR_REG");
goto __exit;
}
__exit:
return RT_ERROR;
}
/**
* This function set the power mode of gyroscope of bmi08x
*
* @param dev the pointer of bmi08x driver structure
*
* @return the setting status, RT_EOK represents reading the data successfully.
*/
rt_err_t bmi088g_set_power_mode(struct bmi08x_dev *dev)
{
uint8_t power_mode = dev->gyro_cfg.power;
uint8_t read_data;
uint8_t is_power_switching_mode_valid = 1;
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->gyro_bus);
_bmi088_spi_read(spi_dev, GYRO_LPM1_REG, 1, &read_data);
if (power_mode == read_data)
{
return RT_EOK;
}
else
{
// only switching between normal mode and the suspend mode is allowed
if ((power_mode == BMI08X_GYRO_PM_SUSPEND) && (read_data == BMI08X_GYRO_PM_DEEP_SUSPEND))
{
is_power_switching_mode_valid = 0;
}
if ((power_mode == BMI08X_GYRO_PM_DEEP_SUSPEND) && (read_data == BMI08X_GYRO_PM_SUSPEND))
{
is_power_switching_mode_valid = 0;
}
if (is_power_switching_mode_valid)
{
if (_bmi088_spi_write(spi_dev, GYRO_LPM1_REG, 1, &power_mode) == RT_EOK)
{
rt_thread_mdelay(BMI08X_GYRO_POWER_MODE_CONFIG_DELAY);
}
}
else
{
LOG_E("Invalid gyro mode switch");
goto __exit;
}
}
__exit:
return RT_ERROR;
}
/**
* This function set the bandwidth(bw), output data rate(odr) and range of accelerometer of bmi08x
*
* @param dev the pointer of bmi08x driver structure
*
* @return the setting status, RT_EOK represents reading the data successfully.
*/
rt_err_t bmi088a_set_meas_conf(struct bmi08x_dev *dev)
{
uint8_t data[2] = {0};
uint8_t reg_val[3] = {0};
uint8_t bw = dev->accel_cfg.bw;
uint8_t range = dev->accel_cfg.range;
uint8_t odr = dev->accel_cfg.odr;
uint8_t is_odr_invalid = 0, is_bw_invalid = 0, is_range_invalid = 0;
if ((odr < BMI08X_ACCEL_ODR_12_5_HZ) || (odr > BMI08X_ACCEL_ODR_1600_HZ))
{
is_odr_invalid = 1;
}
if (bw > BMI08X_ACCEL_BW_NORMAL)
{
is_bw_invalid = 1;
}
if (range > BMI088_ACCEL_RANGE_24G)
{
is_range_invalid = 1;
}
if ((!is_odr_invalid) && (!is_bw_invalid) && (!is_range_invalid))
{
//dummy read
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->accel_bus);
if (_bmi088_spi_read(spi_dev, ACC_CONF_REG, 2, data) == RT_EOK)
{
data[0] = (1<<7) | (2<<4) | (0xB<<0);// bwp = normal, odr = 800
_bmi088_spi_write(spi_dev, ACC_CONF_REG, 1, &data[0]);
data[1] = 0x01;// range = 6G
_bmi088_spi_write(spi_dev, ACC_RANGE_REG, 1, &data[1]);
rt_thread_mdelay(10);
_bmi088_spi_read(spi_dev, ACC_CONF_REG, 3, reg_val);// dummy read
if ((reg_val[1] == 0xAB) && (reg_val[2] == 0x01))
{
return RT_EOK;
}
}
}
return RT_ERROR;
}
/**
* This function set the bandwidth(bw), output data rate(odr) and range of gyroscope of bmi08x
*
* @param dev the pointer of bmi08x driver structure
*
* @return the setting status, RT_EOK represents reading the data successfully.
*/
rt_err_t bmi088g_set_meas_conf(struct bmi08x_dev *dev)
{
uint8_t data;
uint8_t bw_odr = dev->gyro_cfg.bw, range = dev->gyro_cfg.range;
uint8_t reg_val[2] = {0};
uint8_t is_range_invalid = 0, is_odr_invalid = 0;
if (bw_odr > BMI08X_GYRO_BW_32_ODR_100_HZ)
{
is_odr_invalid = 1;
}
if (range > BMI08X_GYRO_RANGE_125_DPS)
{
is_range_invalid = 1;
}
if ((!is_odr_invalid) && (!is_range_invalid))
{
// data = BMI08X_SET_BITS_POS_0(data, BMI08X_GYRO_BW, odr);
data = 0x01;// ODR = 2000Hz, Filter bandwidth = 230Hz
struct rt_spi_device *spi_dev = (struct rt_spi_device *)(dev->gyro_bus);
if (_bmi088_spi_write(spi_dev, GYRO_BANDWIDTH_REG, 1, &data) == RT_EOK)
{
// data = BMI08X_SET_BITS_POS_0(data, GYRO_RANGE_REG, range);
data = 0x00;// range = 2000deg/s
if (_bmi088_spi_write(spi_dev, GYRO_RANGE_REG, 1, &data) == RT_EOK)
{
rt_thread_mdelay(10);
_bmi088_spi_read(spi_dev, GYRO_RANGE_REG, 2, reg_val);
if ((reg_val[0] == 0x00) && (reg_val[1] == 0x81))// 7 bit always 1
{
return RT_EOK;
}
}
}
}
return RT_ERROR;
}
/**
* This function initialize the bmi088 device.
*
* @param acc_spi_name the name of spi device(Accelerometer)
* @param gyro_spi_name the name of spi device(Gyroscope)
*
* @return the pointer of bmi08x driver structure, RT_NULL represents initialization failed.
*/
struct bmi08x_dev *bmi088_init(const char *acc_spi_name, const char *gyro_spi_name)
{
struct bmi08x_dev *dev = RT_NULL;
rt_uint8_t res = RT_EOK;
RT_ASSERT(acc_spi_name);
RT_ASSERT(gyro_spi_name);
dev = rt_calloc(1, sizeof(struct bmi08x_dev));
if (dev == RT_NULL)
{
LOG_E("Can't allocate memory for bmi08x device on '%s' and '%s' ", acc_spi_name, gyro_spi_name);
goto __exit;
}
dev->accel_bus = rt_device_find(acc_spi_name);
dev->gyro_bus = rt_device_find(gyro_spi_name);
if ((dev->accel_bus == RT_NULL) || (dev->gyro_bus == RT_NULL))
{
LOG_E("Can't find device:'%s' of '%s'", acc_spi_name, gyro_spi_name);
goto __exit;
}
if (dev->accel_bus->type != dev->gyro_bus->type)
{
LOG_E("The bus type of '%s' and '%s' should same", acc_spi_name, gyro_spi_name);
goto __exit;
}
if (dev->accel_bus->type == RT_Device_Class_I2CBUS)
{
LOG_E("Bmi08x not support I2C temporarily");
goto __exit;
}
else if (dev->accel_bus->type == RT_Device_Class_SPIDevice)
{
//#ifdef RT_USING_SPI
struct rt_spi_configuration cfg;
cfg.data_width = 8;
cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
cfg.max_hz = BMI088_SPI_MAX_SPEED; /* Set spi max speed */
struct rt_spi_device *spi_dev = (struct rt_spi_device *)dev->accel_bus;
spi_dev->bus->owner = spi_dev;
rt_spi_configure(spi_dev, &cfg);
//#endif
}
else
{
LOG_E("Unsupported bus type:'%s'!", acc_spi_name);
goto __exit;
}
// acc init
{
dev->accel_id = CSB1_Pin;
dev->accel_chip_id = 0x1E;
dev->accel_cfg.bw = BMI08X_ACCEL_BW_NORMAL;
dev->accel_cfg.odr = BMI08X_ACCEL_ODR_800_HZ;
dev->accel_cfg.power = BMI08X_ACCEL_PM_ACTIVE;
dev->accel_cfg.range = BMI088_ACCEL_RANGE_6G;
res += _bmi088a_init(dev);
res += bmi088a_set_power_mode(dev);
res += bmi088a_set_meas_conf(dev);
}
// gyro init
{
dev->gyro_id = CSB2_Pin;
dev->gyro_chip_id = 0x0F;
dev->gyro_cfg.bw = BMI08X_GYRO_BW_230_ODR_2000_HZ;
dev->gyro_cfg.odr = BMI08X_GYRO_BW_230_ODR_2000_HZ;
dev->gyro_cfg.power = BMI08X_GYRO_PM_NORMAL;
dev->gyro_cfg.range = BMI08X_GYRO_RANGE_2000_DPS;
res += _bmi088g_init(dev);
res += bmi088g_set_power_mode(dev);
res += bmi088g_set_meas_conf(dev);
}
rt_thread_mdelay(20);
if (res == RT_EOK)
{
LOG_I("Device init succeed!");
}
else
{
goto __exit;
}
return dev;
__exit:
if (dev != RT_NULL)
{
rt_free(dev);
}
return RT_NULL;
}
/**
* This function releases memory
*
* @param dev the pointer of bmi08x driver structure
*/
void bmi088_deinit(struct bmi08x_dev *dev)
{
RT_ASSERT(dev);
rt_free(dev);
}
bmi088.h
c
#ifndef __BMI088_H__
#define __BMI088_H__
#include <rtthread.h>
#include "sensor.h"
#define IMU_THREAD_STACK_SIZE 4086
/*************************** Common Macros for both Accel and Gyro *****************************/
// Bit #0 : Read/Write bit
// Bit #1-7: Address AD
#define BMI08X_SPI_RD_MASK UINT8_C(0x80)
#define BMI08X_SPI_WR_MASK UINT8_C(0x7F)
/* CMD: soft reset */
#define BMI08X_SOFT_RESET_CMD UINT8_C(0xB6)
/* CMD: accel power save */
#define BMI08X_ACCEL_PWR_ACTIVE_CMD UINT8_C(0x00)
#define BMI08X_ACCEL_PWR_SUSPEND_CMD UINT8_C(0x03)
/* CMD: accel power control */
#define BMI08X_ACCEL_POWER_DISABLE_CMD UINT8_C(0x00)
#define BMI08X_ACCEL_POWER_ENABLE_CMD UINT8_C(0x04)
/* Accel Power Mode */
#define BMI08X_ACCEL_PM_ACTIVE UINT8_C(0x00)
#define BMI08X_ACCEL_PM_SUSPEND UINT8_C(0x03)
/* Gyro Power mode */
#define BMI08X_GYRO_PM_NORMAL UINT8_C(0x00)
#define BMI08X_GYRO_PM_DEEP_SUSPEND UINT8_C(0x20)
#define BMI08X_GYRO_PM_SUSPEND UINT8_C(0x80)
/* Accel Bandwidth */
#define BMI08X_ACCEL_BW_OSR4 UINT8_C(0x00)
#define BMI08X_ACCEL_BW_OSR2 UINT8_C(0x01)
#define BMI08X_ACCEL_BW_NORMAL UINT8_C(0x02)
/* Accel Output Data Rate */
#define BMI08X_ACCEL_ODR_12_5_HZ UINT8_C(0x05)
#define BMI08X_ACCEL_ODR_25_HZ UINT8_C(0x06)
#define BMI08X_ACCEL_ODR_50_HZ UINT8_C(0x07)
#define BMI08X_ACCEL_ODR_100_HZ UINT8_C(0x08)
#define BMI08X_ACCEL_ODR_200_HZ UINT8_C(0x09)
#define BMI08X_ACCEL_ODR_400_HZ UINT8_C(0x0A)
#define BMI08X_ACCEL_ODR_800_HZ UINT8_C(0x0B)
#define BMI08X_ACCEL_ODR_1600_HZ UINT8_C(0x0C)
/* Accel Range */
#define BMI088_ACCEL_RANGE_3G UINT8_C(0x00)
#define BMI088_ACCEL_RANGE_6G UINT8_C(0x01)
#define BMI088_ACCEL_RANGE_12G UINT8_C(0x02)
#define BMI088_ACCEL_RANGE_24G UINT8_C(0x03)
/* Gyro Range */
#define BMI08X_GYRO_RANGE_2000_DPS UINT8_C(0x00)
#define BMI08X_GYRO_RANGE_1000_DPS UINT8_C(0x01)
#define BMI08X_GYRO_RANGE_500_DPS UINT8_C(0x02)
#define BMI08X_GYRO_RANGE_250_DPS UINT8_C(0x03)
#define BMI08X_GYRO_RANGE_125_DPS UINT8_C(0x04)
/* Gyro Output data rate and bandwidth */
#define BMI08X_GYRO_BW_532_ODR_2000_HZ UINT8_C(0x00)
#define BMI08X_GYRO_BW_230_ODR_2000_HZ UINT8_C(0x01)
#define BMI08X_GYRO_BW_116_ODR_1000_HZ UINT8_C(0x02)
#define BMI08X_GYRO_BW_47_ODR_400_HZ UINT8_C(0x03)
#define BMI08X_GYRO_BW_23_ODR_200_HZ UINT8_C(0x04)
#define BMI08X_GYRO_BW_12_ODR_100_HZ UINT8_C(0x05)
#define BMI08X_GYRO_BW_64_ODR_200_HZ UINT8_C(0x06)
#define BMI08X_GYRO_BW_32_ODR_100_HZ UINT8_C(0x07)
#define BMI08X_GYRO_ODR_RESET_VAL UINT8_C(0x80)
#define BMI08X_ACCEL_DATA_SYNC_MODE_OFF 0x00
#define BMI08X_ACCEL_DATA_SYNC_MODE_400HZ 0x01
#define BMI08X_ACCEL_DATA_SYNC_MODE_1000HZ 0x02
#define BMI08X_ACCEL_DATA_SYNC_MODE_2000HZ 0x03
/* Wait Time */
#define BMI08X_ACCEL_SOFTRESET_DELAY_MS UINT8_C(1)
#define BMI08X_GYRO_SOFTRESET_DELAY_MS UINT8_C(30)
#define BMI08X_GYRO_POWER_MODE_CONFIG_DELAY UINT8_C(30)
#define BMI08X_POWER_CONFIG_DELAY UINT8_C(50)
#define G (9.80f)
#define deg2rad (3.1415926 / 180.0f)
#define rad2deg (180.0f / 3.1415926)
typedef enum
{
ACC_CHIP_ID_REG = 0x00,
ACC_ERR_REG = 0x02,
ACC_STATUS_REG = 0x03,
ACC_X_LSB_REG = 0x12,
ACC_X_MSB_REG = 0x13,
ACC_Y_LSB_REG = 0x14,
ACC_Y_MSB_REG = 0x15,
ACC_Z_LSB_REG = 0x16,
ACC_Z_MSB_REG = 0x17,
TEMP_MSB_REG = 0x22,
TEMP_LSB_REG = 0x23,
ACC_CONF_REG = 0x40,
ACC_RANGE_REG = 0x41,
INT1_IO_CTRL_REG = 0x53,
INT2_IO_CTRL_REG = 0x54,
ACC_SELF_TEST_REG = 0x6D,
ACC_PWR_CONF_REG = 0x7C,
ACC_PWR_CTRL_REG = 0x7D,
ACC_SOFTRESET_REG = 0x7E
} bmi088a_reg_list_t;
typedef enum
{
GYRO_CHIP_ID_REG = 0x00,
RATE_X_LSB_REG = 0x02,
RATE_X_MSB_REG = 0x03,
RATE_Y_LSB_REG = 0x04,
RATE_Y_MSB_REG = 0x05,
RATE_Z_LSB_REG = 0x06,
RATE_Z_MSB_REG = 0x07,
GYRO_INT_STAT_1_REG = 0x0A,
GYRO_RANGE_REG = 0x0F,
GYRO_BANDWIDTH_REG = 0x10,
GYRO_LPM1_REG = 0x11,
GYRO_SOFTRESET_REG = 0x14,
GYRO_INT_CTRL_REG = 0x15
} bmi088g_reg_list_t;
enum bmi08x_intf {
/*! I2C interface */
BMI08X_I2C_INTF,
/*! SPI interface */
BMI08X_SPI_INTF
};
struct bmi08x_cfg
{
/*! power mode */
uint8_t power;
/*! range */
uint8_t range;
/*! bandwidth */
uint8_t bw;
/*! output data rate */
uint8_t odr;
};
/* bmi088 device structure */
struct bmi08x_dev
{
/*! Accel chip Id */
uint8_t accel_chip_id;
/*! Gyro chip Id */
uint8_t gyro_chip_id;
/*! Accel device Id in I2C mode, can be used for chip select pin in SPI mode */
rt_base_t accel_id;
/*! Gyro device Id in I2C mode, can be used for chip select pin in SPI mode */
rt_base_t gyro_id;
/*! Device of accel bus*/
rt_device_t accel_bus;
/*! Device of gyro bus*/
rt_device_t gyro_bus;
/*! 0 - I2C , 1 - SPI Interface */
enum bmi08x_intf intf;
/*! Structure to configure accel sensor */
struct bmi08x_cfg accel_cfg;
/*! Structure to configure gyro sensor */
struct bmi08x_cfg gyro_cfg;
/*! Config stream data buffer address will be assigned*/
const uint8_t *config_file_ptr;
/*! Max read/write length (maximum supported length is 32).
To be set by the user */
uint8_t read_write_len;
};
struct bmi088_3axes
{
rt_int16_t x;
rt_int16_t y;
rt_int16_t z;
};
struct bmi088_data
{
float x;
float y;
float z;
};
struct bmi08x_dev *bmi088_init(const char *acc_name, const char *gyro_name);
void bmi088_deinit(struct bmi08x_dev *dev);
rt_err_t bmi088a_set_power_mode(struct bmi08x_dev *dev);
rt_err_t bmi088g_set_power_mode(struct bmi08x_dev *dev);
rt_err_t bmi088a_set_meas_conf(struct bmi08x_dev *dev);
rt_err_t bmi088g_set_meas_conf(struct bmi08x_dev *dev);
rt_size_t bmi088_get_accel(struct bmi08x_dev *dev, struct bmi088_data *buf);
rt_size_t bmi088_get_gyro(struct bmi08x_dev *dev, struct bmi088_data *buf);
#endif // BMI088_H
sensor_intf_bmi088.c
c
#include "sensor_intf_bmi088.h"
#include "bmi088.h"
#include <rtdbg.h>
static struct bmi08x_dev *bmi_dev;
static rt_err_t _bmi088_init(struct rt_sensor_intf *acc_intf, struct rt_sensor_intf *gyr_intf)
{
bmi_dev = bmi088_init(acc_intf->dev_name, gyr_intf->dev_name);
if (bmi_dev == RT_NULL)
{
return -RT_ERROR;
}
return RT_EOK;
}
static rt_err_t _bmi088_set_power_mode(rt_sensor_t sensor, rt_uint8_t power)
{
if (sensor->info.type == RT_SENSOR_CLASS_ACCE)
{
if (power == RT_SENSOR_POWER_DOWN)
{
bmi_dev->accel_cfg.power = BMI08X_ACCEL_PM_SUSPEND;
}
else if (power == RT_SENSOR_POWER_NORMAL)
{
bmi_dev->accel_cfg.power = BMI08X_ACCEL_PM_ACTIVE;
}
else
{
LOG_E("Unsupported power mode %d", power);
return -RT_ERROR;
}
bmi088a_set_power_mode(bmi_dev);
}
else if (sensor->info.type == RT_SENSOR_CLASS_GYRO)
{
if (power == RT_SENSOR_POWER_DOWN)
{
bmi_dev->gyro_cfg.power = BMI08X_GYRO_PM_SUSPEND;
}
else if (power == RT_SENSOR_POWER_NORMAL)
{
bmi_dev->gyro_cfg.power = BMI08X_GYRO_PM_NORMAL;
}
else if (power == RT_SENSOR_POWER_NONE)
{
bmi_dev->gyro_cfg.power = BMI08X_GYRO_PM_DEEP_SUSPEND;
}
else
{
LOG_E("Unsupported power mode %d", power);
return -RT_ERROR;
}
bmi088g_set_power_mode(bmi_dev);
}
else
{
LOG_E("Unsupported type %d", sensor->info.type);
return -RT_ERROR;
}
return RT_EOK;
}
/**
* This function get the data of bmi088 sensor, unit: mg, mdps
*
* @param sensor the pointer of rt_sensor_device.
* @param data the pointer of rt_sensor_data
*
* @return the reading number.
*/
static rt_size_t _bmi088_get_data(rt_sensor_t sensor, struct rt_sensor_data *data)
{
rt_size_t len;
if (sensor->info.type == RT_SENSOR_CLASS_ACCE)
{
struct bmi088_data acce_m_ss;
len = bmi088_get_accel(bmi_dev, &acce_m_ss);
data->type = RT_SENSOR_CLASS_ACCE;
data->data.acce.x = acce_m_ss.x * 1000;
data->data.acce.y = acce_m_ss.y * 1000;
data->data.acce.z = acce_m_ss.z * 1000;
data->timestamp = rt_sensor_get_ts();
}
else if (sensor->info.type == RT_SENSOR_CLASS_GYRO)
{
struct bmi088_data gyro_rad_s;
len = bmi088_get_gyro(bmi_dev, &gyro_rad_s);
data->type = RT_SENSOR_CLASS_GYRO;
data->data.gyro.x = gyro_rad_s.x * rad2deg * 1000;
data->data.gyro.y = gyro_rad_s.y * rad2deg * 1000;
data->data.gyro.z = gyro_rad_s.x * rad2deg * 1000;
data->timestamp = rt_sensor_get_ts();
}
return len;
}
/**
* This function get the data of bmi088 sensor
*
* @param sensor the pointer of rt_sensor_device.
* @param buf the pointer of data buffer.
* @param len the length of data.
*
* @return the reading number.
*/
static rt_size_t _bmi088_fetch_data(struct rt_sensor_device *sensor, void *buf, rt_size_t len)
{
if (sensor->config.mode == RT_DEVICE_OFLAG_RDONLY)
{
return _bmi088_get_data(sensor, (struct rt_sensor_data *)buf);
}
else
{
return 0;
}
}
/**
* This function control the bmi088 sensor
*
* @param sensor the pointer of rt_sensor_device.
* @param cmd the type of command.
* @param args the null pointer of commmand parameter, notice the pointer is four bytes.
*
* @return the reading number.
*/
static rt_err_t _bmi088_control(struct rt_sensor_device *sensor, int cmd, void *args)//args��32λ(ָ�붼��4���ֽ�)
{
rt_err_t result = RT_EOK;
switch (cmd)
{
case RT_SENSOR_CTRL_GET_ID:
if (sensor->info.type == RT_SENSOR_CLASS_ACCE)
{
*(rt_uint8_t *)args = 0x1E;
}
else if (sensor->info.type == RT_SENSOR_CLASS_GYRO)
{
*(rt_uint8_t *)args = 0x0F;
}
break;
case RT_SENSOR_CTRL_SET_ODR:
case RT_SENSOR_CTRL_SET_RANGE:
if (sensor->info.type == RT_SENSOR_CLASS_ACCE)
{
result = bmi088a_set_meas_conf(bmi_dev);
}
else if (sensor->info.type == RT_SENSOR_CLASS_GYRO)
{
result = bmi088g_set_meas_conf(bmi_dev);
}
break;
case RT_SENSOR_CTRL_SET_POWER:
_bmi088_set_power_mode(sensor, (rt_uint32_t)args & 0xff);
break;
case RT_SENSOR_CTRL_SET_MODE:
break;
case RT_SENSOR_CTRL_SELF_TEST:
/* TODO */
result = -RT_EINVAL;
break;
default:
return -RT_EINVAL;
}
return result;
}
static struct rt_sensor_ops sensor_ops =
{
_bmi088_fetch_data,
_bmi088_control
};
/**
* This function initialize the bmi088
*
* @param name the name of bmi088, just first three characters will be used.
* @param acc_cfg the pointer of configuration structure for accelarometer.
* @param gyr_cfg the pointer of configuration structure for gyroscope.
*
* @return the reading number.
*/
rt_err_t rt_hw_bmi088_init(const char *name, struct rt_sensor_config *acc_cfg, struct rt_sensor_config *gyr_cfg)
{
rt_int8_t result;
rt_sensor_t sensor_acce = RT_NULL, sensor_gyro = RT_NULL;
//#ifdef PKG_USING_BMI088_ACCE
/* accelerometer sensor register */
{
sensor_acce = rt_calloc(1, sizeof(struct rt_sensor_device));
if (sensor_acce == RT_NULL)
{
return -1;
}
sensor_acce->info.type = RT_SENSOR_CLASS_ACCE;
sensor_acce->info.vendor = RT_SENSOR_VENDOR_BOSCH;
sensor_acce->info.model = "bmi088_acc";
sensor_acce->info.unit = RT_SENSOR_UNIT_MG;
sensor_acce->info.intf_type = RT_SENSOR_INTF_SPI;
sensor_acce->info.range_max = 16000;
sensor_acce->info.range_min = 2000;
sensor_acce->info.period_min = 5;
rt_memcpy(&sensor_acce->config, acc_cfg, sizeof(struct rt_sensor_config));
sensor_acce->ops = &sensor_ops;
result = rt_hw_sensor_register(sensor_acce, name, RT_DEVICE_FLAG_RDWR, RT_NULL);
if (result != RT_EOK)
{
LOG_E("device register err code: %d", result);
goto __exit;
}
}
//#endif
//#ifdef PKG_USING_BMI088_GYRO
/* gyroscope sensor register */
{
sensor_gyro = rt_calloc(1, sizeof(struct rt_sensor_device));
if (sensor_gyro == RT_NULL)
{
goto __exit;
}
sensor_gyro->info.type = RT_SENSOR_CLASS_GYRO;
sensor_gyro->info.vendor = RT_SENSOR_VENDOR_BOSCH;
sensor_gyro->info.model = "bmi088_gyro";
sensor_gyro->info.unit = RT_SENSOR_UNIT_MDPS;
sensor_gyro->info.intf_type = RT_SENSOR_INTF_SPI;
sensor_gyro->info.range_max = 2000000;
sensor_gyro->info.range_min = 250000;
sensor_gyro->info.period_min = 5;
rt_memcpy(&sensor_gyro->config, gyr_cfg, sizeof(struct rt_sensor_config));
sensor_gyro->ops = &sensor_ops;
result = rt_hw_sensor_register(sensor_gyro, name, RT_DEVICE_FLAG_RDWR, RT_NULL);
if (result != RT_EOK)
{
LOG_E("device register err code: %d", result);
goto __exit;
}
}
//#endif
result = _bmi088_init(&acc_cfg->intf, &gyr_cfg->intf);
if (result != RT_EOK)
{
LOG_E("_bmi088_init err code: %d", result);
goto __exit;
}
LOG_I("sensor init success");
return RT_EOK;
__exit:
if (sensor_acce)
{
rt_free(sensor_acce);
}
if (sensor_gyro)
{
rt_free(sensor_gyro);
}
if (bmi_dev)
{
bmi088_deinit(bmi_dev);
}
return -RT_ERROR;
}
sensor_intf_bmi088.h
c
#ifndef __SENSOR_INTF_BMI088_H__
#define __SENSOR_INTF_BMI088_H__
#include "sensor.h"
#include "BMI088.h"
rt_err_t rt_hw_bmi088_init(const char *name, struct rt_sensor_config *acc_cfg, struct rt_sensor_config *gyr_cfg);
#endif
- 第六步,到main.c 配置bmi088
①配置spi,配置片选引脚
c
rt_hw_spi_device_attach(BMI088_BUS_NAME, BMI088A_SPI_NAME, GPIOF, GPIO_PIN_3);
rt_hw_spi_device_attach(BMI088_BUS_NAME, BMI088G_SPI_NAME, GPIOF, GPIO_PIN_4);
②初始化bmi
c
struct rt_sensor_config acc_cfg = {0};
struct rt_sensor_config gyr_cfg = {0};
acc_cfg.intf.dev_name = BMI088A_SPI_NAME;
gyr_cfg.intf.dev_name = BMI088G_SPI_NAME;
rt_hw_bmi088_init("bmi", &acc_cfg, &gyr_cfg);
③查找 spi 设备获取设备句柄
c
acce_device_t = rt_device_find("acce_bmi");
if (acce_device_t == RT_NULL)
{
LOG_E("Can't find acce device\r\n");
}
else
{
rt_device_open(acce_device_t, RT_DEVICE_OFLAG_RDWR);
}
gyro_device_t = rt_device_find("gyro_bmi");
if (gyro_device_t == RT_NULL)
{
LOG_E("Can't find gyro device\r\n");
}
else
{
rt_device_open(gyro_device_t, RT_DEVICE_OFLAG_RDWR);
}
④读取姿态数据
c
rt_device_read(acce_device_t, 0, &acc_test, 1); //加速度
rt_device_read(gyro_device_t, 0, &gyr_test, 1); //陀螺仪
main.c
c
include <rtthread.h>
#include <rtdbg.h>
#include <rtdevice.h>
#include <board.h>
#include "bmi088.h"
#include "sensor_intf_bmi088.h"
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#define SPI_DEVICE_NAME "spi10"
#define SPI_BUS_NAME "spi1"
#define BMI088_BUS_NAME "spi1"
#define BMI088A_SPI_NAME "spi10"
#define BMI088G_SPI_NAME "spi11"
static rt_device_t acce_device_t;
static rt_device_t gyro_device_t;
struct rt_sensor_data acc_test;
struct rt_sensor_data gyr_test;
int main(void)
{
// 配置spi,配置片选引脚(要在acc、gyr初始化之前配置,因为器件初始化中涉及到引脚操作)
rt_hw_spi_device_attach(BMI088_BUS_NAME, BMI088A_SPI_NAME, GPIOF, GPIO_PIN_3);
rt_hw_spi_device_attach(BMI088_BUS_NAME, BMI088G_SPI_NAME, GPIOF, GPIO_PIN_4);
// 注册传感器
struct rt_sensor_config acc_cfg = {0};
struct rt_sensor_config gyr_cfg = {0};
acc_cfg.intf.dev_name = BMI088A_SPI_NAME;
gyr_cfg.intf.dev_name = BMI088G_SPI_NAME;
rt_hw_bmi088_init("bmi", &acc_cfg, &gyr_cfg);
/* 查找 spi 设备获取设备句柄 */
acce_device_t = rt_device_find("acce_bmi");
if (acce_device_t == RT_NULL)
{
LOG_E("Can't find acce device\r\n");
}
else
{
rt_device_open(acce_device_t, RT_DEVICE_OFLAG_RDWR);
}
gyro_device_t = rt_device_find("gyro_bmi");
if (gyro_device_t == RT_NULL)
{
LOG_E("Can't find gyro device\r\n");
}
else
{
rt_device_open(gyro_device_t, RT_DEVICE_OFLAG_RDWR);
}
while (1)
{
rt_device_read(acce_device_t, 0, &acc_test, 1); //加速度
rt_device_read(gyro_device_t, 0, &gyr_test, 1); //陀螺仪
rt_kprintf("x=%d y=%d z=%d\n",acc_test.data.acce.x,acc_test.data.acce.y,acc_test.data.acce.z);
//rt_kprintf("x=%d y=%d z=%d\n",gyr_test.data.gyro.x,gyr_test.data.gyro.y,gyr_test.data.gyro.z);
rt_thread_mdelay(500);
}
}
如下为加速度计数据: