370 lines
11 KiB
C
370 lines
11 KiB
C
![]() |
/*
|
||
|
BMI088 陀螺仪+加速度计传感器。
|
||
|
|
||
|
*/
|
||
|
|
||
|
/* Includes ----------------------------------------------------------------- */
|
||
|
#include "bmi088.h"
|
||
|
|
||
|
#include <cmsis_os2.h>
|
||
|
#include <gpio.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "bsp\delay.h"
|
||
|
#include "bsp\gpio.h"
|
||
|
#include "bsp\spi.h"
|
||
|
#include "component\user_math.h"
|
||
|
|
||
|
/* Private define ----------------------------------------------------------- */
|
||
|
#define BMI088_REG_ACCL_CHIP_ID (0x00)
|
||
|
#define BMI088_REG_ACCL_ERR (0x02)
|
||
|
#define BMI088_REG_ACCL_STATUS (0x03)
|
||
|
#define BMI088_REG_ACCL_X_LSB (0x12)
|
||
|
#define BMI088_REG_ACCL_X_MSB (0x13)
|
||
|
#define BMI088_REG_ACCL_Y_LSB (0x14)
|
||
|
#define BMI088_REG_ACCL_Y_MSB (0x15)
|
||
|
#define BMI088_REG_ACCL_Z_LSB (0x16)
|
||
|
#define BMI088_REG_ACCL_Z_MSB (0x17)
|
||
|
#define BMI088_REG_ACCL_SENSORTIME_0 (0x18)
|
||
|
#define BMI088_REG_ACCL_SENSORTIME_1 (0x19)
|
||
|
#define BMI088_REG_ACCL_SENSORTIME_2 (0x1A)
|
||
|
#define BMI088_REG_ACCL_INT_STAT_1 (0x1D)
|
||
|
#define BMI088_REG_ACCL_TEMP_MSB (0x22)
|
||
|
#define BMI088_REG_ACCL_TEMP_LSB (0x23)
|
||
|
#define BMI088_REG_ACCL_CONF (0x40)
|
||
|
#define BMI088_REG_ACCL_RANGE (0x41)
|
||
|
#define BMI088_REG_ACCL_INT1_IO_CONF (0x53)
|
||
|
#define BMI088_REG_ACCL_INT2_IO_CONF (0x54)
|
||
|
#define BMI088_REG_ACCL_INT1_INT2_MAP_DATA (0x58)
|
||
|
#define BMI088_REG_ACCL_SELF_TEST (0x6D)
|
||
|
#define BMI088_REG_ACCL_PWR_CONF (0x7C)
|
||
|
#define BMI088_REG_ACCL_PWR_CTRL (0x7D)
|
||
|
#define BMI088_REG_ACCL_SOFTRESET (0x7E)
|
||
|
|
||
|
#define BMI088_REG_GYRO_CHIP_ID (0x00)
|
||
|
#define BMI088_REG_GYRO_X_LSB (0x02)
|
||
|
#define BMI088_REG_GYRO_X_MSB (0x03)
|
||
|
#define BMI088_REG_GYRO_Y_LSB (0x04)
|
||
|
#define BMI088_REG_GYRO_Y_MSB (0x05)
|
||
|
#define BMI088_REG_GYRO_Z_LSB (0x06)
|
||
|
#define BMI088_REG_GYRO_Z_MSB (0x07)
|
||
|
#define BMI088_REG_GYRO_INT_STAT_1 (0x0A)
|
||
|
#define BMI088_REG_GYRO_RANGE (0x0F)
|
||
|
#define BMI088_REG_GYRO_BANDWIDTH (0x10)
|
||
|
#define BMI088_REG_GYRO_LPM1 (0x11)
|
||
|
#define BMI088_REG_GYRO_SOFTRESET (0x14)
|
||
|
#define BMI088_REG_GYRO_INT_CTRL (0x15)
|
||
|
#define BMI088_REG_GYRO_INT3_INT4_IO_CONF (0x16)
|
||
|
#define BMI088_REG_GYRO_INT3_INT4_IO_MAP (0x18)
|
||
|
#define BMI088_REG_GYRO_SELF_TEST (0x3C)
|
||
|
|
||
|
#define BMI088_CHIP_ID_ACCL (0x1E)
|
||
|
#define BMI088_CHIP_ID_GYRO (0x0F)
|
||
|
|
||
|
#define BMI088_LEN_RX_BUFF (19)
|
||
|
/* Private macro ------------------------------------------------------------ */
|
||
|
#define BMI088_ACCL_NSS_SET() \
|
||
|
HAL_GPIO_WritePin(ACCL_CS_GPIO_Port, ACCL_CS_Pin, GPIO_PIN_SET)
|
||
|
#define BMI088_ACCL_NSS_RESET() \
|
||
|
HAL_GPIO_WritePin(ACCL_CS_GPIO_Port, ACCL_CS_Pin, GPIO_PIN_RESET)
|
||
|
|
||
|
#define BMI088_GYRO_NSS_SET() \
|
||
|
HAL_GPIO_WritePin(GYRO_CS_GPIO_Port, GYRO_CS_Pin, GPIO_PIN_SET)
|
||
|
#define BMI088_GYRO_NSS_RESET() \
|
||
|
HAL_GPIO_WritePin(GYRO_CS_GPIO_Port, GYRO_CS_Pin, GPIO_PIN_RESET)
|
||
|
|
||
|
/* Private typedef ---------------------------------------------------------- */
|
||
|
typedef enum {
|
||
|
BMI_ACCL,
|
||
|
BMI_GYRO,
|
||
|
} BMI_Device_t;
|
||
|
|
||
|
/* Private variables -------------------------------------------------------- */
|
||
|
static uint8_t buffer[2];
|
||
|
static uint8_t bmi088_rxbuf[BMI088_LEN_RX_BUFF];
|
||
|
|
||
|
static osThreadId_t thread_alert;
|
||
|
static bool inited = false;
|
||
|
|
||
|
/* Private function -------------------------------------------------------- */
|
||
|
static void BMI_WriteSingle(BMI_Device_t dv, uint8_t reg, uint8_t data) {
|
||
|
buffer[0] = (reg & 0x7f);
|
||
|
buffer[1] = data;
|
||
|
|
||
|
BSP_Delay(1);
|
||
|
switch (dv) {
|
||
|
case BMI_ACCL:
|
||
|
BMI088_ACCL_NSS_RESET();
|
||
|
break;
|
||
|
|
||
|
case BMI_GYRO:
|
||
|
BMI088_GYRO_NSS_RESET();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
HAL_SPI_Transmit(BSP_SPI_GetHandle(BSP_SPI_IMU), buffer, 2u, 20u);
|
||
|
|
||
|
switch (dv) {
|
||
|
case BMI_ACCL:
|
||
|
BMI088_ACCL_NSS_SET();
|
||
|
break;
|
||
|
|
||
|
case BMI_GYRO:
|
||
|
BMI088_GYRO_NSS_SET();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static uint8_t BMI_ReadSingle(BMI_Device_t dv, uint8_t reg) {
|
||
|
BSP_Delay(1);
|
||
|
switch (dv) {
|
||
|
case BMI_ACCL:
|
||
|
BMI088_ACCL_NSS_RESET();
|
||
|
break;
|
||
|
|
||
|
case BMI_GYRO:
|
||
|
BMI088_GYRO_NSS_RESET();
|
||
|
break;
|
||
|
}
|
||
|
buffer[0] = (uint8_t)(reg | 0x80);
|
||
|
HAL_SPI_Transmit(BSP_SPI_GetHandle(BSP_SPI_IMU), buffer, 1u, 20u);
|
||
|
HAL_SPI_Receive(BSP_SPI_GetHandle(BSP_SPI_IMU), buffer, 2u, 20u);
|
||
|
|
||
|
switch (dv) {
|
||
|
case BMI_ACCL:
|
||
|
BMI088_ACCL_NSS_SET();
|
||
|
return buffer[1];
|
||
|
|
||
|
case BMI_GYRO:
|
||
|
BMI088_GYRO_NSS_SET();
|
||
|
return buffer[0];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void BMI_Read(BMI_Device_t dv, uint8_t reg, uint8_t *data, uint8_t len) {
|
||
|
if (data == NULL) return;
|
||
|
|
||
|
switch (dv) {
|
||
|
case BMI_ACCL:
|
||
|
BMI088_ACCL_NSS_RESET();
|
||
|
break;
|
||
|
|
||
|
case BMI_GYRO:
|
||
|
BMI088_GYRO_NSS_RESET();
|
||
|
break;
|
||
|
}
|
||
|
buffer[0] = (uint8_t)(reg | 0x80);
|
||
|
HAL_SPI_Transmit(BSP_SPI_GetHandle(BSP_SPI_IMU), buffer, 1u, 20u);
|
||
|
HAL_SPI_Receive_DMA(BSP_SPI_GetHandle(BSP_SPI_IMU), data, len);
|
||
|
}
|
||
|
|
||
|
static void BMI088_RxCpltCallback(void) {
|
||
|
if (HAL_GPIO_ReadPin(ACCL_CS_GPIO_Port, ACCL_CS_Pin) == GPIO_PIN_RESET) {
|
||
|
BMI088_ACCL_NSS_SET();
|
||
|
osThreadFlagsSet(thread_alert, SIGNAL_BMI088_ACCL_RAW_REDY);
|
||
|
}
|
||
|
if (HAL_GPIO_ReadPin(GYRO_CS_GPIO_Port, GYRO_CS_Pin) == GPIO_PIN_RESET) {
|
||
|
BMI088_GYRO_NSS_SET();
|
||
|
osThreadFlagsSet(thread_alert, SIGNAL_BMI088_GYRO_RAW_REDY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void BMI088_AcclIntCallback(void) {
|
||
|
osThreadFlagsSet(thread_alert, SIGNAL_BMI088_ACCL_NEW_DATA);
|
||
|
}
|
||
|
|
||
|
static void BMI088_GyroIntCallback(void) {
|
||
|
osThreadFlagsSet(thread_alert, SIGNAL_BMI088_GYRO_NEW_DATA);
|
||
|
}
|
||
|
|
||
|
/* Exported functions ------------------------------------------------------- */
|
||
|
int8_t BMI088_Init(BMI088_t *bmi088, const BMI088_Cali_t *cali) {
|
||
|
if (bmi088 == NULL) return DEVICE_ERR_NULL;
|
||
|
if (cali == NULL) return DEVICE_ERR_NULL;
|
||
|
if (inited) return DEVICE_ERR_INITED;
|
||
|
if ((thread_alert = osThreadGetId()) == NULL) return DEVICE_ERR_NULL;
|
||
|
|
||
|
bmi088->cali = cali;
|
||
|
|
||
|
BMI_WriteSingle(BMI_ACCL, BMI088_REG_ACCL_SOFTRESET, 0xB6);
|
||
|
BMI_WriteSingle(BMI_GYRO, BMI088_REG_GYRO_SOFTRESET, 0xB6);
|
||
|
BSP_Delay(30);
|
||
|
|
||
|
/* Switch accl to SPI mode. */
|
||
|
BMI_ReadSingle(BMI_ACCL, BMI088_CHIP_ID_ACCL);
|
||
|
|
||
|
if (BMI_ReadSingle(BMI_ACCL, BMI088_REG_ACCL_CHIP_ID) != BMI088_CHIP_ID_ACCL)
|
||
|
return DEVICE_ERR_NO_DEV;
|
||
|
|
||
|
if (BMI_ReadSingle(BMI_GYRO, BMI088_REG_GYRO_CHIP_ID) != BMI088_CHIP_ID_GYRO)
|
||
|
return DEVICE_ERR_NO_DEV;
|
||
|
|
||
|
BSP_GPIO_DisableIRQ(ACCL_INT_Pin);
|
||
|
BSP_GPIO_DisableIRQ(GYRO_INT_Pin);
|
||
|
|
||
|
BSP_SPI_RegisterCallback(BSP_SPI_IMU, BSP_SPI_RX_CPLT_CB,
|
||
|
BMI088_RxCpltCallback);
|
||
|
BSP_GPIO_RegisterCallback(ACCL_INT_Pin, BMI088_AcclIntCallback);
|
||
|
BSP_GPIO_RegisterCallback(GYRO_INT_Pin, BMI088_GyroIntCallback);
|
||
|
|
||
|
/* Accl init. */
|
||
|
/* Filter setting: Normal. */
|
||
|
/* ODR: 0xAB: 800Hz. 0xAA: 400Hz. 0xA9: 200Hz. 0xA8: 100Hz. 0xA6: 25Hz. */
|
||
|
BMI_WriteSingle(BMI_ACCL, BMI088_REG_ACCL_CONF, 0xAA);
|
||
|
|
||
|
/* 0x00: +-3G. 0x01: +-6G. 0x02: +-12G. 0x03: +-24G. */
|
||
|
BMI_WriteSingle(BMI_ACCL, BMI088_REG_ACCL_RANGE, 0x01);
|
||
|
|
||
|
/* INT1 as output. Push-pull. Active low. Output. */
|
||
|
BMI_WriteSingle(BMI_ACCL, BMI088_REG_ACCL_INT1_IO_CONF, 0x08);
|
||
|
|
||
|
/* Map data ready interrupt to INT1. */
|
||
|
BMI_WriteSingle(BMI_ACCL, BMI088_REG_ACCL_INT1_INT2_MAP_DATA, 0x04);
|
||
|
|
||
|
/* Turn on accl. Now we can read data. */
|
||
|
BMI_WriteSingle(BMI_ACCL, BMI088_REG_ACCL_PWR_CTRL, 0x04);
|
||
|
BSP_Delay(50);
|
||
|
|
||
|
/* Gyro init. */
|
||
|
/* 0x00: +-2000. 0x01: +-1000. 0x02: +-500. 0x03: +-250. 0x04: +-125. */
|
||
|
BMI_WriteSingle(BMI_GYRO, BMI088_REG_GYRO_RANGE, 0x01);
|
||
|
|
||
|
/* Filter bw: 47Hz. */
|
||
|
/* ODR: 0x02: 1000Hz. 0x03: 400Hz. 0x06: 200Hz. 0x07: 100Hz. */
|
||
|
BMI_WriteSingle(BMI_GYRO, BMI088_REG_GYRO_BANDWIDTH, 0x03);
|
||
|
|
||
|
/* INT3 and INT4 as output. Push-pull. Active low. */
|
||
|
BMI_WriteSingle(BMI_GYRO, BMI088_REG_GYRO_INT3_INT4_IO_CONF, 0x00);
|
||
|
|
||
|
/* Map data ready interrupt to INT3. */
|
||
|
BMI_WriteSingle(BMI_GYRO, BMI088_REG_GYRO_INT3_INT4_IO_MAP, 0x01);
|
||
|
|
||
|
/* Enable new data interrupt. */
|
||
|
BMI_WriteSingle(BMI_GYRO, BMI088_REG_GYRO_INT_CTRL, 0x80);
|
||
|
|
||
|
BSP_Delay(10);
|
||
|
|
||
|
inited = true;
|
||
|
|
||
|
BSP_GPIO_EnableIRQ(ACCL_INT_Pin);
|
||
|
BSP_GPIO_EnableIRQ(GYRO_INT_Pin);
|
||
|
return DEVICE_OK;
|
||
|
}
|
||
|
|
||
|
bool BMI088_GyroStable(AHRS_Gyro_t *gyro) {
|
||
|
return ((gyro->x < 0.03f) && (gyro->y < 0.03f) && (gyro->z < 0.03f));
|
||
|
}
|
||
|
|
||
|
uint32_t BMI088_WaitNew() {
|
||
|
return osThreadFlagsWait(
|
||
|
SIGNAL_BMI088_ACCL_NEW_DATA | SIGNAL_BMI088_GYRO_NEW_DATA, osFlagsWaitAll,
|
||
|
osWaitForever);
|
||
|
}
|
||
|
|
||
|
int8_t BMI088_AcclStartDmaRecv() {
|
||
|
BMI_Read(BMI_ACCL, BMI088_REG_ACCL_X_LSB, bmi088_rxbuf, BMI088_LEN_RX_BUFF);
|
||
|
return DEVICE_OK;
|
||
|
}
|
||
|
|
||
|
uint32_t BMI088_AcclWaitDmaCplt() {
|
||
|
return osThreadFlagsWait(SIGNAL_BMI088_ACCL_RAW_REDY, osFlagsWaitAll,
|
||
|
osWaitForever);
|
||
|
}
|
||
|
|
||
|
int8_t BMI088_GyroStartDmaRecv() {
|
||
|
BMI_Read(BMI_GYRO, BMI088_REG_GYRO_X_LSB, bmi088_rxbuf + 7, 6u);
|
||
|
return DEVICE_OK;
|
||
|
}
|
||
|
|
||
|
uint32_t BMI088_GyroWaitDmaCplt() {
|
||
|
return osThreadFlagsWait(SIGNAL_BMI088_GYRO_RAW_REDY, osFlagsWaitAll,
|
||
|
osWaitForever);
|
||
|
}
|
||
|
|
||
|
int8_t BMI088_ParseAccl(BMI088_t *bmi088) {
|
||
|
if (bmi088 == NULL) return DEVICE_ERR_NULL;
|
||
|
|
||
|
#if 1
|
||
|
int16_t raw_x, raw_y, raw_z;
|
||
|
memcpy(&raw_x, bmi088_rxbuf + 1, sizeof(raw_x));
|
||
|
memcpy(&raw_y, bmi088_rxbuf + 3, sizeof(raw_y));
|
||
|
memcpy(&raw_z, bmi088_rxbuf + 5, sizeof(raw_z));
|
||
|
|
||
|
bmi088->accl.x = (float)raw_x;
|
||
|
bmi088->accl.y = (float)raw_y;
|
||
|
bmi088->accl.z = (float)raw_z;
|
||
|
|
||
|
#else
|
||
|
const int16_t *praw_x = (int16_t *)(bmi088_rxbuf + 1);
|
||
|
const int16_t *praw_y = (int16_t *)(bmi088_rxbuf + 3);
|
||
|
const int16_t *praw_z = (int16_t *)(bmi088_rxbuf + 5);
|
||
|
|
||
|
bmi088->accl.x = (float)*praw_x;
|
||
|
bmi088->accl.y = (float)*praw_y;
|
||
|
bmi088->accl.z = (float)*praw_z;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* 3G: 10920. 6G: 5460. 12G: 2730. 24G: 1365. */
|
||
|
bmi088->accl.x /= 5460.0f;
|
||
|
bmi088->accl.y /= 5460.0f;
|
||
|
bmi088->accl.z /= 5460.0f;
|
||
|
|
||
|
int16_t raw_temp =
|
||
|
(uint16_t)((bmi088_rxbuf[17] << 3) | (bmi088_rxbuf[18] >> 5));
|
||
|
|
||
|
if (raw_temp > 1023) raw_temp -= 2048;
|
||
|
|
||
|
bmi088->temp = (float)raw_temp * 0.125f + 23.0f;
|
||
|
|
||
|
return DEVICE_OK;
|
||
|
}
|
||
|
|
||
|
int8_t BMI088_ParseGyro(BMI088_t *bmi088) {
|
||
|
if (bmi088 == NULL) return DEVICE_ERR_NULL;
|
||
|
|
||
|
#if 1
|
||
|
/* Gyroscope imu_raw -> degrees/sec -> radians/sec */
|
||
|
int16_t raw_x, raw_y, raw_z;
|
||
|
memcpy(&raw_x, bmi088_rxbuf + 7, sizeof(raw_x));
|
||
|
memcpy(&raw_y, bmi088_rxbuf + 9, sizeof(raw_y));
|
||
|
memcpy(&raw_z, bmi088_rxbuf + 11, sizeof(raw_z));
|
||
|
|
||
|
bmi088->gyro.x = (float)raw_x;
|
||
|
bmi088->gyro.y = (float)raw_y;
|
||
|
bmi088->gyro.z = (float)raw_z;
|
||
|
|
||
|
#else
|
||
|
/* Gyroscope imu_raw -> degrees/sec -> radians/sec */
|
||
|
const int16_t *raw_x = (int16_t *)(bmi088_rxbuf + 7);
|
||
|
const int16_t *raw_y = (int16_t *)(bmi088_rxbuf + 9);
|
||
|
const int16_t *raw_z = (int16_t *)(bmi088_rxbuf + 11);
|
||
|
|
||
|
bmi088->gyro.x = (float)*raw_x;
|
||
|
bmi088->gyro.y = (float)*raw_y;
|
||
|
bmi088->gyro.z = (float)*raw_z;
|
||
|
#endif
|
||
|
|
||
|
/* FS125: 262.144. FS250: 131.072. FS500: 65.536. FS1000: 32.768.
|
||
|
* FS2000: 16.384.*/
|
||
|
bmi088->gyro.x /= 32.768f;
|
||
|
bmi088->gyro.y /= 32.768f;
|
||
|
bmi088->gyro.z /= 32.768f;
|
||
|
|
||
|
bmi088->gyro.x *= M_DEG2RAD_MULT;
|
||
|
bmi088->gyro.y *= M_DEG2RAD_MULT;
|
||
|
bmi088->gyro.z *= M_DEG2RAD_MULT;
|
||
|
|
||
|
bmi088->gyro.x -= bmi088->cali->gyro_offset.x;
|
||
|
bmi088->gyro.y -= bmi088->cali->gyro_offset.y;
|
||
|
bmi088->gyro.z -= bmi088->cali->gyro_offset.z;
|
||
|
|
||
|
return DEVICE_ERR_NULL;
|
||
|
}
|
||
|
|
||
|
float BMI088_GetUpdateFreq(BMI088_t *bmi088) {
|
||
|
(void)bmi088;
|
||
|
return 400.0f;
|
||
|
}
|