使用deepseek生成BMI088 驱动代码并移植到PH47框架
前期通过对dp各方面的使用和测试,已初步感受到dp的强大。那么就尝试着通过一个实际案例来验证下dp生成BMI驱动程序代码的易用性与可用性。
前期通过对dp各方面的使用和测试,已初步感受到dp的强大。那么就尝试着通过一个实际案例来验证下dp生成程序代码的易用性与可用性。
为何要选择写BMI088的驱动作为测试用例呢?首先BMI088是一款性能优异的IMU芯片。其次,也是最主要的原因,BMI088是个很坑的缝合怪芯片,就像是强行用胶水把一个加速度计和一个陀螺仪粘一块的感觉。输出速率不一样、驱动方式不一样、片选引脚不一样、ID不一样……对比ICM42688,感觉就非常古怪。之前写过它的驱动,但没搞定也不确定究竟是软件还是硬件方面有问题,然后就一直搁置了(反正有ICM42688镇场子~~~)。
所以用BMI088这个缝合怪来测试DP的能力,既有一定难度,又符合实战条件。嗯,比较合适,开始动手。
经过几轮DP问答测试,精确限定驱动代码适用的软硬件环境后,最终给出的提示词:
适用于 stm32f4系列,通过spi读写,不使用dma,但要使用bmi088的fifo机制,数据刷新速率500hz以上,输出加速度及陀螺数据。应用于无人机产品,要对滤波器进行针对性设置。代码要完整,包括头文件内容,以及完整示例程序。
贴一下首次生成的代码,很漂亮,还有贴心且准确的注释,可惜移植到PH47框架下却无法正常运行,接下来会讲述其中的bug和坑(读者可快速掠过fifo相关部分)。
/* bmi088.h */
#ifndef __BMI088_H
#define __BMI088_H
#include "stm32f4xx_hal.h"
// 寄存器地址定义
#define BMI088_ACC_CHIP_ID 0x00
#define BMI088_ACC_CONF 0x40
#define BMI088_ACC_RANGE 0x41
#define BMI088_ACC_FIFO_CONFIG 0x48
#define BMI088_GYR_CHIP_ID 0x00
#define BMI088_GYR_RANGE 0x0F
#define BMI088_GYR_BANDWIDTH 0x10
#define BMI088_FIFO_LENGTH 0x22
// 传感器配置参数
#define ACC_ODR_1000HZ 0x05
#define ACC_RANGE_24G 0x03
#define GYRO_ODR_2000HZ 0x07
#define GYRO_RANGE_2000DPS 0x00
#define GYRO_BW_532HZ 0x04
typedef struct {
SPI_HandleTypeDef *hspi;
GPIO_TypeDef *acc_cs_port;
uint16_t acc_cs_pin;
GPIO_TypeDef *gyr_cs_port;
uint16_t gyr_cs_pin;
} BMI088_HandleTypeDef;
// 函数声明
void BMI088_Init(BMI088_HandleTypeDef *hdev);
void BMI088_ReadFIFO(BMI088_HandleTypeDef *hdev, int16_t *acc, int16_t *gyro);
#endif
.c 文件
/* bmi088.c */
#include "bmi088.h"
static void SPI_WriteRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef* cs_port,
uint16_t cs_pin, uint8_t reg, uint8_t data)
{
uint8_t tx[2] = {reg & 0x7F, data};
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(hspi, tx, 2, 100);
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_SET);
}
static uint8_t SPI_ReadRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef* cs_port,
uint16_t cs_pin, uint8_t reg)
{
uint8_t tx = reg | 0x80;
uint8_t rx[2] = {0};
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(hspi, &tx, rx, 2, 100);
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_SET);
return rx[1];
}
void BMI088_Init(BMI088_HandleTypeDef *hdev)
{
// 加速度计SPI模式切换(伪读操作)
SPI_ReadRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin, 0x7E);
HAL_Delay(50);
// 加速度计配置
SPI_WriteRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin,
BMI088_ACC_CONF, ACC_ODR_1000HZ);
SPI_WriteRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin,
BMI088_ACC_RANGE, ACC_RANGE_24G);
SPI_WriteRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin,
BMI088_ACC_FIFO_CONFIG, 0x01); // FIFO流模式
// 陀螺仪配置
SPI_WriteRegister(hdev->hspi, hdev->gyr_cs_port, hdev->gyr_cs_pin,
BMI088_GYR_RANGE, GYRO_RANGE_2000DPS);
SPI_WriteRegister(hdev->hspi, hdev->gyr_cs_port, hdev->gyr_cs_pin,
BMI088_GYR_BANDWIDTH, (GYRO_ODR_2000HZ << 4) | GYRO_BW_532HZ);
}
void BMI088_ReadFIFO(BMI088_HandleTypeDef *hdev, int16_t *acc, int16_t *gyro)
{
uint8_t buffer[12];
// 读取加速度计数据
uint8_t reg = BMI088_FIFO_LENGTH | 0x80;
HAL_GPIO_WritePin(hdev->acc_cs_port, hdev->acc_cs_pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(hdev->hspi, ®, 1, 100);
HAL_SPI_Receive(hdev->hspi, buffer, 6, 100); // 包含伪字节[9]
acc[0] = (buffer[1] << 8) | buffer[2];
acc[1] = (buffer[3] << 8) | buffer[4];
acc[2] = (buffer[5] << 8) | buffer[6];
HAL_GPIO_WritePin(hdev->acc_cs_port, hdev->acc_cs_pin, GPIO_PIN_SET);
// 读取陀螺仪数据
reg = 0x02 | 0x80;
HAL_GPIO_WritePin(hdev->gyr_cs_port, hdev->gyr_cs_pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(hdev->hspi, ®, 1, 100);
HAL_SPI_Receive(hdev->hspi, buffer, 6, 100);
gyro[0] = (buffer[0] << 8) | buffer[1];
gyro[1] = (buffer[2] << 8) | buffer[3];
gyro[2] = (buffer[4] << 8) | buffer[5];
HAL_GPIO_WritePin(hdev->gyr_cs_port, hdev->gyr_cs_pin, GPIO_PIN_SET);
}
示例文件:
/* main.c 示例 */
#include "main.h"
#include "bmi088.h"
BMI088_HandleTypeDef hbmi = {
.hspi = &hspi1,
.acc_cs_port = GPIOB,
.acc_cs_pin = GPIO_PIN_0,
.gyr_cs_port = GPIOB,
.gyr_cs_pin = GPIO_PIN_3
};
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_SPI1_Init();
BMI088_Init(&hbmi);
int16_t acc[3], gyro[3];
while(1) {
BMI088_ReadFIFO(&hbmi, acc, gyro);
// 转换为实际物理量(示例)
float acc_x = acc[0] * 24.0f / 32768.0f;
float gyro_x = gyro[0] * 2000.0f / 32768.0f;
printf("Acc: %.2fg\tGyro: %.2fdps\r\n", acc_x, gyro_x);
HAL_Delay(2); // 500Hz采样率
}
}
以上生成的程序为使用FIFO机制时,为了减小程序调试难度,令DP重新生成不使用FIFO机制时程序代码,提示词如下:
请再给出不使用fifo机制 时候完整的数据读取代码
DP生成代码如下:
/* 修改后的bmi088.h */
// 添加数据寄存器定义
#define BMI088_ACC_X_LSB 0x12
#define BMI088_ACC_Y_LSB 0x14
#define BMI088_ACC_Z_LSB 0x16
#define BMI088_GYR_X_LSB 0x02
// 新增函数声明
void BMI088_ReadRawData(BMI088_HandleTypeDef *hdev, int16_t *acc, int16_t *gyro);
.c 文件
/* 修改后的bmi088.c */
void BMI088_Init(BMI088_HandleTypeDef *hdev)
{
// ...保持之前的配置...
// 禁用加速度计FIFO(修改此行)
SPI_WriteRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin,
BMI088_ACC_FIFO_CONFIG, 0x00); // 关闭FIFO
}
新增直接从寄存器读取acc及gyro
void BMI088_ReadRawData(BMI088_HandleTypeDef *hdev, int16_t *acc, int16_t *gyro)
{
uint8_t buffer[6];
// 读取加速度计数据(0x12~0x17)
HAL_GPIO_WritePin(hdev->acc_cs_port, hdev->acc_cs_pin, GPIO_PIN_RESET);
uint8_t reg = BMI088_ACC_X_LSB | 0x80; // 读操作标记
HAL_SPI_Transmit(hdev->hspi, ®, 1, 100);
HAL_SPI_Receive(hdev->hspi, buffer, 6, 100);
HAL_GPIO_WritePin(hdev->acc_cs_port, hdev->acc_cs_pin, GPIO_PIN_SET);
acc[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴
acc[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴
acc[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴
// 读取陀螺仪数据(0x02~0x07)
HAL_GPIO_WritePin(hdev->gyr_cs_port, hdev->gyr_cs_pin, GPIO_PIN_RESET);
reg = BMI088_GYR_X_LSB | 0x80;
HAL_SPI_Transmit(hdev->hspi, ®, 1, 100);
HAL_SPI_Receive(hdev->hspi, buffer, 6, 100);
HAL_GPIO_WritePin(hdev->gyr_cs_port, hdev->gyr_cs_pin, GPIO_PIN_SET);
gyro[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴
gyro[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴
gyro[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴
}
修改后的main.c
int main(void)
{
// ...初始化部分保持不变...
int16_t acc[3], gyro[3];
while(1) {
BMI088_ReadRawData(&hbmi, acc, gyro); // 改为调用新函数
// 数据转换(注意符号处理)
float acc_x = (int16_t)acc[0] * 24.0f / 32768.0f;
float gyro_x = (int16_t)gyro[0] * 2000.0f / 32768.0f;
printf("Acc: %.2fg\tGyro: %.2fdps\r\n", acc_x, gyro_x);
HAL_Delay(1); // 可提升到1ms间隔(1000Hz)
}
}
将代码移植到PH47框架后,编译烧写运行。接着就出现了一个比一个诡异的问题:
1、缝合怪BMI088输出了陀螺仪数据,加速度计输出数据始终为零。
陀螺仪输出正常数据,至少说明缝合怪的陀螺仪部分、以及mcu的spi接口、以及PH47框架部分没有问题,bug应当是在缝合怪的加速度计部分。
向DP再次提问:
有陀螺数据,但是没有加速度数据。可以确认是软件代码出错了,那具体是什么地方出问题了?
DP给出几种可能:
1. SPI模式切换问题 (关键问题)
// 原代码中的伪读操作需要修正:
// 正确操作应写入0x0B到ACC_PWR_CTRL寄存器
SPI_WriteRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin, 0x7C, 0x00); // 解锁配置
SPI_WriteRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin, 0x7E, 0x0B); // 切换至SPI模式
HAL_Delay(50);
错误现象:加速度计始终处于I2C模式,无法响应SPI命令
解决方案:增加电源控制寄存器的配置流程
2. 加速度计电源管理配置
// 添加电源控制配置(必须步骤)
SPI_WriteRegister(hdev->hspi, hdev->acc_cs_port, hdev->acc_cs_pin, 0x7D, 0x04); // 上电加速度计
HAL_Delay(10);
错误现象:加速度计处于休眠模式。手册要求:必须配置0x7D寄存器为0x04才能激活
3. 数据寄存器地址错误......
4. 字节顺序处理错误……
5. SPI时序模式不匹配……
6. 状态寄存器检测(调试建议)......
经对照BMI088 芯片手册以及先前驱动代码,怀疑为加速度计电源未打开。随后在芯片的初始化函数中加入如下代码(已经做了适应PH47框架的修改):
// Accelerometer on
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, REG_ACC_PWR_CTRL, 0x04);
编译烧写运行,好消息是加速度计开始输出数据了。说BMI088是个缝合怪一点都不过吧,同一个芯片,Acc需要打开电源操作,Gyro就不需要,不是缝合怪是啥?
坏消息是,输出Acc数据不对,是个随机值,随机值!
2、加速度计输出数据为随机值问题
此bug一般要么为lsb数据处理有问题,要么是spi接口设置有问题。经检查,加速度从lsb处理为m/s2 单位,计算过程没有问题。那么估计问题出在spi接口方面(这个问题很诡异,上一次写驱动的时候就栽在这里了)。
追问DP,给出以下可能:
2.1、伪数据处理不当
BMI088加速度计读取时存在"首字节伪数据"机制。若未正确跳过首字节,会导致后续数据解析错误:
// 错误示例(未处理伪数据)
HAL_SPI_Receive(hspi, buffer, 6, 100); // 直接读取6字节
// 正确方法(读取7字节并舍弃首字节)
uint8_t dummy;
HAL_SPI_Receive(hspi, &dummy, 1, 100); // 舍弃伪数据
HAL_SPI_Receive(hspi, buffer, 6, 100); // 读取有效数据
典型症状:数据呈现周期性跳跃(如±2000 LSB的突变)
2.2、字节序与符号处理错误......
2.3、机械振动干扰......
2.4、温度漂移未补偿......
2.5、电源噪声干扰......
2.6、SPI信号完整性问题......
2.7、滤波器参数不匹配......
2.8、量程与动态范围不匹配......
2.9、校准与算法缺陷......
bug有很多种可能,只能逐一排查,“1、伪数据处理不当”嫌疑很大,DP也指出在芯片手册中有专门提醒:
既然如此,按照DP的给出的方法修改代码,奇迹出现了,缝合怪开始稳定输出正确的加速度数据。修改后程序代码如下:
void CBMI088_DP::BMI088_ReadRawData(int16_t *acc, int16_t *gyro)
{
uint8_t dummy; // 修改代码
uint8_t buffer[6];
// 读取加速度计数据(0x12~0x17)
HAL_GPIO_WritePin(_hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, GPIO_PIN_RESET);
uint8_t reg = BMI088_ACC_X_LSB | 0x80; // 读操作标记
HAL_SPI_Transmit(_hImuDev.hspi, ®, 1, 10);
HAL_SPI_Receive(_hImuDev.hspi, &dummy, 1, 10); // 修改代码,Acc需要读取1个伪字节
HAL_SPI_Receive(_hImuDev.hspi, buffer, 6, 10);
HAL_GPIO_WritePin(_hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, GPIO_PIN_SET);
acc[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴
acc[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴
acc[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴
// 读取陀螺仪数据(0x02~0x07)
HAL_GPIO_WritePin(_hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, GPIO_PIN_RESET);
reg = BMI088_GYR_X_LSB | 0x80;
HAL_SPI_Transmit(_hImuDev.hspi, ®, 1, 10);
HAL_SPI_Receive(_hImuDev.hspi, buffer, 6, 10);
HAL_GPIO_WritePin(_hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, GPIO_PIN_SET);
gyro[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴
gyro[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴
gyro[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴
}
你就说这缝合怪坑不坑吧,一个加速度计整出这么多幺蛾子出来。相比之下,陀螺仪就是个超级正常的乖宝宝。
然额,不出意外的又出意外了。偶然发现,缝合怪在keil的debug模式下加速度计输出数据正常,而在脱离了keil的调试环境的正常运行条件下,加速度计输出数据又双叒叕错了,输出数值大概是正常数值的4倍左右(Acc 怎么又是你?!)
3、加速度计输出数据在脱离keil 的Debug环境下输出数据错误问题
这个问题再次问了DP,DP也麻了,胡说八道了一大通没啥参考价值。
按经验,spi输出数据比正常值大了2的N次方倍,很有可能是数据错误移位了,具体可能是spi口的CPOA与CPOL设置错误了。但是经过反复修改设置测试,故障依旧。无奈之下,按照遇事不决再啃手册的金科玉律,又仔细看了缝合怪的datasheet,发现有这么个东西:
尤其是reset value为suspend mode显得更加可疑,在缝合怪BMI088的初始化函数中加入如下代码,在初始化过程中将acc从suspend挂起状态切换到激活状态:
// 必须加入该段代码,否则在debug模式下数据正常,普通运行模式下输出数据比正常模式大4倍
// Switch to Active mode, default is suspend mode
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, REG_ACC_PWR_CONFIG, 0x00);
HAL_Delay(2);
编译运行,一切都正常了,缝合怪终于不作妖了。BMI088输出的acc,gyro数据一切正常了。至此,使用DP生成BMI088驱动代码的工作初步完成。至于BMI088的高级功能,如fifo及DMA机制的使用,感兴趣的同学可进一步尝试。至于为何在keil的debug模式下不需要上述操作即可正常工作,整不明白,明白的同学请多指教。
4、总结,仅就这一次测试得出DP生成代码的评价:
优点:
- 生成代码非常简洁、耦合度低、阅读理解的难度极低。
- 与此同时代码完整程度较高,包含了常量定义、驱动代码、示例代码等,基本到了拿来即可用的地步。
- 能够按照指定的软硬件条件精确生成代码;
- 可以辅助debug,能够提出有价值的观点。
缺点:
- 首次生成的代码是存在错误不能运行的。经过后续追问,可以给出包含了正确解决途径在内的多个建议,但需要人工进行甄别(那你为啥不一开始就给出正确代码呢,你个浓眉大眼的DP也学会摸鱼了??)
最重要的事情,说三遍!
使用DP之前,要对芯片的datasheet有个初步但清楚地了解,这样才能有效的引导DP扮演好初级程序员的角色,而不是被它带偏。在此前提之下,DP应该是一个合格的初级程序员。
以下是PH47框架下BMI088驱动的完整代码:
BMI088_DP.h 文件
#ifndef __BMI088_DP_H__
#define __BMI088_DP_H__
/************************************************
- Lib safe include (.h)
- ReadOnly to user
- All LIBs must be compiled after modify
*************************************************/
#include "./ImuPort.h"
// 寄存器地址定义
#define BMI088_ACC_CHIP_ID 0x00
#define BMI088_ACC_CONF 0x40
#define BMI088_ACC_RANGE 0x41
#define BMI088_ACC_FIFO_CONFIG 0x48
#define BMI088_GYR_CHIP_ID 0x00
#define BMI088_GYR_RANGE 0x0F
#define BMI088_GYR_BANDWIDTH 0x10
#define BMI088_FIFO_LENGTH 0x22
#define REG_ACC_PWR_CONFIG 0x7C // My code, not AI
#define REG_ACC_PWR_CTRL 0x7D // My code, not AI
#define REG_ACC_SOFT_RESET 0x7E
// 添加数据寄存器定义
#define BMI088_ACC_X_LSB 0x12
#define BMI088_ACC_Y_LSB 0x14
#define BMI088_ACC_Z_LSB 0x16
#define BMI088_GYR_X_LSB 0x02
// 传感器配置参数
#define ACC_ODR_1000HZ 0x05
#define ACC_RANGE_24G 0x03
#define GYRO_ODR_2000HZ 0x07
#define GYRO_RANGE_2000DPS 0x00
#define GYRO_BW_532HZ 0x04
#define CALL_BMI088_DEBUG 11
typedef struct
{
SPI_HandleTypeDef *hspi;
GPIO_TypeDef *acc_cs_port;
uint16_t acc_cs_pin;
GPIO_TypeDef *gyr_cs_port;
uint16_t gyr_cs_pin;
} BMI088_HandleTypeDef;
struct DAT_OUT_BMI088
{
Vector3f vAccel;
Vector3f vGyro;
};
class CBMI088_DP : public CImu_Port
{
public:
CBMI088_DP() {};
virtual void Init(GPIO_TypeDef *pGPIOx_CS, uint32_t uPinMask_CS);
virtual uint8_t Update();
virtual void* Function(uint8_t uCallType, void *pDataIn);
virtual uint8_t ReadID(void);
private:
void SPI_WriteRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef* cs_port, uint16_t cs_pin, uint8_t reg, uint8_t data);
uint8_t SPI_ReadRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef* cs_port, uint16_t cs_pin, uint8_t reg);
void BMI088_ReadRawData(int16_t *acc, int16_t *gyro);
void BMI088_ReadFIFO(int16_t *acc, int16_t *gyro);
float lsb_to_mps2(int16_t val, int8_t g_range, uint8_t bit_width);
BMI088_HandleTypeDef _hImuDev;
DAT_OUT_BMI088 _sImuDat;
};
#endif
BMI088_DP.cpp 文件:
/************************************************
- Lib safe include (.h)
- ReadOnly to user
- All LIBs must be compiled after modify
*************************************************/
#include "./BMI088_DP.h"
#include "../McuDev.h"
extern CMcuDev &mcu;
#include "../../Frame/Core/FrameCore.h"
extern CFrameCore &core;
#include "../../../BBP/Inc/main.h" // Addtional code
#include "../../../bbp/Inc/spi.h"
void CBMI088_DP::Init(GPIO_TypeDef *pGPIOx_CS, uint32_t uPinMask_CS)
{
// _hImuDev 初始化
_hImuDev.hspi = &(hspi2); // 临时措施
// Acc CS: PB12
_hImuDev.acc_cs_port = CS_SPI2_IMU_GPIO_Port;
_hImuDev.acc_cs_pin = CS_SPI2_IMU_Pin;
// Gyr CS: PA15
_hImuDev.gyr_cs_port = CS2_SPI2_IMU_GPIO_Port;
_hImuDev.gyr_cs_pin = CS2_SPI2_IMU_Pin;
// 加速度计SPI模式切换(伪读操作)
SPI_ReadRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, REG_ACC_SOFT_RESET); //
HAL_Delay(20);
// My code, not AI
// 必须加入该段代码,否则在debug模式下输出数据比正常模式大4倍
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, REG_ACC_PWR_CONFIG, 0x00); // Switch to Active mode, default is suspend mode
HAL_Delay(2);
// AI sugest
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, REG_ACC_PWR_CTRL, 0x04); // Accelerometer on
gDelay_us(500);
// 加速度计配置
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, BMI088_ACC_CONF, ACC_ODR_1000HZ);
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, BMI088_ACC_RANGE, ACC_RANGE_24G);
//SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, BMI088_ACC_FIFO_CONFIG, 0x01); // FIFO流模式
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, BMI088_ACC_FIFO_CONFIG, 0x00); // 关闭FIFO
// 陀螺仪配置
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, BMI088_GYR_RANGE, GYRO_RANGE_2000DPS);
SPI_WriteRegister(_hImuDev.hspi, _hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, BMI088_GYR_BANDWIDTH, (GYRO_ODR_2000HZ << 4) | GYRO_BW_532HZ);
}
uint8_t CBMI088_DP::ReadID(void)
{
uint8_t uID = SPI_ReadRegister(_hImuDev.hspi, _hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, BMI088_ACC_CHIP_ID);
return uID;
}
void* CBMI088_DP::Function(uint8_t uCallType, void *pDataIn)
{
void *pRet = NULL;
if(uCallType == GET_DATA_OUT_BMI088)
{
pRet = (void *) (&_sImuDat);
}
else if(uCallType == CALL_BMI088_DEBUG)
{
int16_t acc[3], gyro[3];
BMI088_ReadRawData(acc, gyro); // 改为调用新函数
// 数据转换(注意符号处理)
_sImuDat.vAccel.x = (int16_t)acc[0] * 24.0f * GRAVITY_MSS / 32768.0f;
_sImuDat.vAccel.y = (int16_t)acc[1] * 24.0f * GRAVITY_MSS / 32768.0f;
_sImuDat.vAccel.z = (int16_t)acc[2] * 24.0f * GRAVITY_MSS / 32768.0f;
/*
float acc_x = lsb_to_mps2(acc[0], 24, 16);
float acc_y = lsb_to_mps2(acc[1], 24, 16);
float acc_z = lsb_to_mps2(acc[2], 24, 16); */
_sImuDat.vGyro.x = (int16_t)gyro[0] * 2000.0f / 32768.0f;
_sImuDat.vGyro.y = (int16_t)gyro[1] * 2000.0f / 32768.0f;
_sImuDat.vGyro.z = (int16_t)gyro[2] * 2000.0f / 32768.0f;
TRACE("\r\n> Acc: %.2f %.2f %.2f m/s2", _sImuDat.vAccel.x, _sImuDat.vAccel.y, _sImuDat.vAccel.z);
TRACE("\r\n> Gyr: %.2f %.2f %.2f dps", _sImuDat.vGyro.x, _sImuDat.vGyro.y, _sImuDat.vGyro.z);
}
return pRet;
}
uint8_t CBMI088_DP::Update()
{
if(_hImuDev.hspi == NULL)
return 0;
int16_t acc[3], gyro[3];
BMI088_ReadRawData(acc, gyro); // 改为调用新函数
// Accel
_sImuDat.vAccel.x = (int16_t)acc[0] * 24.0f * GRAVITY_MSS / 32768.0f;
_sImuDat.vAccel.y = (int16_t)acc[1] * 24.0f * GRAVITY_MSS / 32768.0f;
_sImuDat.vAccel.z = (int16_t)acc[2] * 24.0f * GRAVITY_MSS / 32768.0f;
// Gyro
_sImuDat.vGyro.x = (int16_t)gyro[0] * 2000.0f / 32768.0f;
_sImuDat.vGyro.y = (int16_t)gyro[1] * 2000.0f / 32768.0f;
_sImuDat.vGyro.z = (int16_t)gyro[2] * 2000.0f / 32768.0f;
return 1;
}
void CBMI088_DP::SPI_WriteRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef* cs_port, uint16_t cs_pin, uint8_t reg, uint8_t data)
{
uint8_t tx[2] = {reg & 0x7F, data};
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(hspi, tx, 2, 100);
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_SET);
}
uint8_t CBMI088_DP::SPI_ReadRegister(SPI_HandleTypeDef *hspi, GPIO_TypeDef* cs_port, uint16_t cs_pin, uint8_t reg)
{
uint8_t tx = reg | 0x80;
uint8_t rx[2] = {0};
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive(hspi, &tx, rx, 2, 100);
HAL_GPIO_WritePin(cs_port, cs_pin, GPIO_PIN_SET);
return rx[1];
}
void CBMI088_DP::BMI088_ReadRawData(int16_t *acc, int16_t *gyro)
{
uint8_t dummy;
uint8_t buffer[6];
uint32_t uPrev = gGetMicros();
// 读取加速度计数据(0x12~0x17)
HAL_GPIO_WritePin(_hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, GPIO_PIN_RESET);
uint8_t reg = BMI088_ACC_X_LSB | 0x80; // 读操作标记
HAL_SPI_Transmit(_hImuDev.hspi, ®, 1, 10);
HAL_SPI_Receive(_hImuDev.hspi, &dummy, 1, 10); // 读取1个伪字节
HAL_SPI_Receive(_hImuDev.hspi, buffer, 6, 100);
HAL_GPIO_WritePin(_hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, GPIO_PIN_SET);
acc[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴
acc[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴
acc[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴
// 读取陀螺仪数据(0x02~0x07)
HAL_GPIO_WritePin(_hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, GPIO_PIN_RESET);
reg = BMI088_GYR_X_LSB | 0x80;
HAL_SPI_Transmit(_hImuDev.hspi, ®, 1, 100);
HAL_SPI_Receive(_hImuDev.hspi, buffer, 6, 100);
HAL_GPIO_WritePin(_hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, GPIO_PIN_SET);
gyro[0] = (int16_t)((buffer[1] << 8) | buffer[0]); // X轴
gyro[1] = (int16_t)((buffer[3] << 8) | buffer[2]); // Y轴
gyro[2] = (int16_t)((buffer[5] << 8) | buffer[4]); // Z轴
}
void CBMI088_DP::BMI088_ReadFIFO(int16_t *acc, int16_t *gyro)
{
uint8_t buffer[12];
// 读取加速度计数据
uint8_t reg = BMI088_FIFO_LENGTH | 0x80;
HAL_GPIO_WritePin(_hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(_hImuDev.hspi, ®, 1, 100);
HAL_SPI_Receive(_hImuDev.hspi, buffer, 6, 100); // 包含伪字节[9]
acc[0] = (buffer[1] << 8) | buffer[2];
acc[1] = (buffer[3] << 8) | buffer[4];
acc[2] = (buffer[5] << 8) | buffer[6];
HAL_GPIO_WritePin(_hImuDev.acc_cs_port, _hImuDev.acc_cs_pin, GPIO_PIN_SET);
// 读取陀螺仪数据
reg = 0x02 | 0x80;
HAL_GPIO_WritePin(_hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, GPIO_PIN_RESET);
HAL_SPI_Transmit(_hImuDev.hspi, ®, 1, 100);
HAL_SPI_Receive(_hImuDev.hspi, buffer, 6, 100);
gyro[0] = (buffer[0] << 8) | buffer[1];
gyro[1] = (buffer[2] << 8) | buffer[3];
gyro[2] = (buffer[4] << 8) | buffer[5];
HAL_GPIO_WritePin(_hImuDev.gyr_cs_port, _hImuDev.gyr_cs_pin, GPIO_PIN_SET);
}
float CBMI088_DP::lsb_to_mps2(int16_t val, int8_t g_range, uint8_t bit_width)
{
float gravity;
float half_scale = ((1 << bit_width) / 2.0f);
gravity = (float)((GRAVITY_MSS * val * g_range) / half_scale);
return gravity;
}
更多推荐
所有评论(0)