STM32移植BMI088驱动全指南:SPI配置、DMA优化与避坑实战
1. 项目概述与整体设计思路1.1 BMI088是什么一颗芯片集成两颗独立传感器BMI088是Bosch推出的一款高性能6轴惯性测量单元一个封装里同时集成了三轴加速度计和三轴陀螺仪。它在无人机、机器人、云台、VR设备里用得非常多尤其是飞控领域几乎成了标配级别的IMU。相比同价位的其他IMUBMI088的噪声特性好温度漂移控制做得也不错并且同时支持SPI和I2C接口实测下来SPI模式下能稳定跑到1000Hz以上的采样率非常适合做姿态解算。这里要特别提醒第一次接触这颗芯片的朋友BMI088虽然是一个模组但内部实际上是两颗独立的传感器芯片加速度计和陀螺仪各有各的寄存器地址空间、各有各的电源管理寄存器、各有各的片选引脚。这一点和很多“一颗芯片一套寄存器”的IMU完全不一样也是后面移植驱动时最容易出问题的根源。我在刚开始移植的时候就被这个设计坑了半天以为是驱动代码的问题查了半天发现根本原因是两颗芯片不能同时独占一条SPI片选。1.2 为什么要用官方驱动而不是自己造轮子很多工程师拿到一颗新传感器第一反应就是翻开数据手册、照着寄存器表自己写驱动。对于BMI088这种寄存器比较少、时序不复杂的芯片自己写确实不难但问题在于“不难”和“稳定”之间还有很长一段距离。BMI088官方提供了C语言驱动代码量不大但已经把芯片内部的初始化流程、量程设置、带宽配置、数据读取、陀螺仪自动校准这些都处理好了而且经过了Bosch官方验证。我们移植要做的只是把它底层的“硬件抽象层”对接上STM32的SPI和定时器就能直接调用它的上层API。我见过不少项目是工程师自己写的BMI088驱动功能上也能跑但在细节上总有一些瑕疵比如陀螺仪零偏没有校准、量程切换时没有把对应状态寄存器同步、精度寄存器的高低位拼接顺序搞错。这些问题在静态测试时看不出来一旦飞机飞起来或者机器人跑起来姿态数据就会飘。所以这个项目我坚持用官方驱动做底子只在移植和优化层面做文章效率更高也稳妥得多。1.3 移植前需要准备的东西在动手配置工程之前先把软硬件环境列清楚。我的项目选的是STM32F405RG主频168MHzSPI1作为IMU通信总线。如果你的板子是F103或者F407原理上完全适用只要注意F103的SPI频率上限和F405不同即可。软件方面使用STM32CubeMX生成HAL库工程配合Keil MDK编译调试。BMI088官方驱动源码可以从Bosch公司的GitHub仓库下载搜“bmi088”就行下载后里面会有bmi088.h和bmi088.c两个核心文件以及一个可选的bmi088_wrapper.c示例文件。硬件接线方面BMI088 SPI接口需要4根线SCK、MOSI、MISO以及加速度计和陀螺仪各自的片选脚。我使用的模块是从淘宝买的六轴BMI088模块通常会把加速度计的CS接到CSB1引脚陀螺仪的CS接到CSB2引脚。除此之外模块的VDD接3.3VVDDIO接3.3VGND接GND。如果是自己画板的同学务必在VDD和VDDIO旁边加几颗100nF的退耦电容并且尽量不要用细长走线连接SCK否则高速SPI通信时会看到奇怪的数据跳变。2. STM32底层接口编写2.1 用CubeMX配置SPI和GPIO打开STM32CubeMX选择你的芯片型号然后在Pinout视图里把SPI1打开配置为Full-Duplex Master模式。关键参数要重点说波特率预设值先选一个慢的比如1Mbps因为BMI088数据手册标称SPI最高支持10MHz但新拿到板子时我建议先用低速跑通再逐步提速。CPOL设为LowCPHA设为1st Edge也就是SPI Mode 0。这个参数非常关键CPI设置错了读WHO_AM_I直接能读出0xFF或者乱码。两个片选引脚我分配为PE4和PE6分别驱动BMI088的CSB1和CSB2GPIO模式配置为推挽输出初始输出高电平。注意这里不要把片选交给SPI外设的NSS而是用普通GPIO控制原因是BMI088要求两个传感器共用一条SPI总线但片选信号必须分别控制用硬件NSS很难做到两路片选灵活切换。CubeMX配置完成后生成工程进入Keil。这时的工程只有HAL库代码还没有BMI088驱动接下来我们就要把官方驱动文件加入工程并编写底层对接函数。2.2 实现底层对接函数打开Bosch官方驱动的bmi088.h你会看到bmi088_dev结构体里面有整数形变量intf用来定义通信接口函数指针bus_read、bus_write、delay_ms用来让上层驱动调用底层硬件接口。这就是移植的核心官方驱动已经封装好了读写逻辑但它不认识STM32的HAL库需要我们把这些函数指针对接上。这里有一个很多新手容易忽略的细节官方驱动里的bus_read和bus_write的函数指针类型I2C接口的dev_addr传的是I2C从机地址而SPI接口下dev_addr是不需要传地址的。但我们依然要保持函数签名一致把dev_addr参数保留但忽略它。我在写SPI读取函数时第一版漏看了这个参数直接编译报错后来统一用int8_t作为返回值、uint8_t作为参数才把类型匹配上。下面这段是我在STM32F405上实测通过的核心代码SPI读取函数int8_t bmi088_spi_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *data, uint16_t len) { uint8_t tx_addr 0; uint8_t dummy 0; // 发读地址前把片选拉低选中对应传感器 if (dev_addr BMI088_ACC_CS) { HAL_GPIO_WritePin(BMI088_CS1_GPIO_Port, BMI088_CS1_Pin, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(BMI088_CS2_GPIO_Port, BMI088_CS2_Pin, GPIO_PIN_RESET); } // SPI读操作第一个字节是寄存器地址最高位置1表示读 tx_addr reg_addr | 0x80; HAL_SPI_Transmit(hspi1, tx_addr, 1, HAL_MAX_DELAY); // 读取数据MOSI发dummy字节MISO收到寄存器值 if (len 1) { // 多字节读取每读一个字节都要发一个dummy for (uint16_t i 0; i len; i) { HAL_SPI_TransmitReceive(hspi1, dummy, data[i], 1, HAL_MAX_DELAY); } } else { HAL_SPI_TransmitReceive(hspi1, dummy, data, 1, HAL_MAX_DELAY); } // 传输完成后片选拉高 if (dev_addr BMI088_ACC_CS) { HAL_GPIO_WritePin(BMI088_CS1_GPIO_Port, BMI088_CS1_Pin, GPIO_PIN_SET); } else { HAL_GPIO_WritePin(BMI088_CS2_GPIO_Port, BMI088_CS2_Pin, GPIO_PIN_SET); } return BMI088_OK; }这段代码里我用dev_addr来区分当前访问的是加速度计还是陀螺仪并据此选择拉低哪一路片选。这只是我的一种实现方式你也可以把这个区分逻辑拆成两个函数在初始化时给加速度计和陀螺仪分别注册不同的回调。但要记住一点BMI088官方驱动里bmi088_dev结构体是一次性注册的如果你只想用一套回调那就必须靠dev_addr参数来区分我就是这么做的。2.3 初始化调用流程底层函数写好之后初始化流程就比较清晰了。先创建bmi088_dev结构体实例给它赋上接口类型、读写函数和延时函数指针然后调用bmi088_init。下面是我工程里的初始化代码struct bmi088_dev bmi088 {0}; void bmi088_delay_ms(uint32_t ms) { HAL_Delay(ms); } void bmi088_hw_init(void) { // 传感器上电后先等一段时间让内部电源稳定 HAL_Delay(20); bmi088.intf BMI088_SPI_INTF; bmi088.bus_read bmi088_spi_read; bmi088.bus_write bmi088_spi_write; bmi088.delay_ms bmi088_delay_ms; int8_t ret bmi088_init(bmi088); if (ret ! BMI088_OK) { // 初始化失败这里可以接串口打印错误码 printf(BMI088 init failed: %d\r\n, ret); } else { printf(BMI088 init success\r\n); } // 设置加速度计量程为±6g陀螺仪量程为±2000dps bmi088_set_accel_range(bmi088, BMI088_ACCEL_RANGE_6G); bmi088_set_gyro_range(bmi088, BMI088_GYRO_RANGE_2000); }这里要特别强调延时函数的重要性。BMI088上电后内部的两个传感器芯片都要经历一个电源稳定过程如果上电后立刻就开始配置寄存器大概率会失败。官方驱动内部虽然有自己的复位和延时逻辑但在调用bmi088_init之前额外的20ms延时是我实测下来比较稳定的值。官方数据手册里给出的上电时序图上也有相关的说明一定要遵守。3. 移植过程中最容易踩的坑避坑指南3.1 读WHO_AM_I失败SPI模式、接线、供电WHO_AM_I寄存器是传感器用来标识自身型号的身份寄存器加速度计的WHO_AM_I地址是0x00返回值固定是0x1E陀螺仪的WHO_AM_I地址同样是0x00返回值固定是0x0F。移植驱动到STM32后第一件事就是读这两个ID能读对就说明SPI通路没有问题。如果你读出来是0xFF或者0x00不用怀疑代码逻辑先按顺序排查以下三个方向。第一确认SPI模式和时钟极性。BMI088只支持SPI Mode 0也就是CPOL0、CPHA0。我之前有一次在CubeMX里不小心把CPHA配成了2nd Edge结果读回来的ID全是不稳定的乱码。第二检查接线尤其时MISO和MOSI是否接反这两个信号接反最典型的现象就是发送正常但读不到有效数据。第三检查供电BMI088的VDD和VDDIO如果低于1.71V芯片根本不会正常响应很多便宜的模块在连接杜邦线时接触不良也会造成这种现象。我的建议是写一个单独的函数初始化SPI后先把加速度计和陀螺仪的ID都读一遍串口打印出来确认无误后再继续后面的操作。这一步通过了整个移植就完成了60%。3.2 SPI读地址的特殊位0x80与burst标志0x40BMI088的SPI传输协议里有一个不太直观的规则寄存器地址只有7位有效最高位用作读写标志。写操作时发送的地址最高位必须是0读操作时发送的地址最高位必须是1。比如你想读陀螺仪0x02寄存器实际通过MOSI发出的字节应该是0x82。Bosch官方驱动里很多读操作函数内部会自己处理这个最高位但如果你在调试过程中自己封装了读取函数就很容易漏掉这一步。更隐蔽的坑是burst读的地址bit6。BMI088支持多字节连续读取如果需要一次读取6个字节的加速度计原始数据应该以加速度计X轴低字节寄存器0x12为首地址但地址字节的最高位仍要置1同时第6位也要置1表示当前操作是突发读取这样传感器才能在同一个CS低电平周期内连续输出6个字节。如果你忘了置第6位你会发现数据只能读到第一个字节后面的字节全部是0。官方驱动在实现加速度计和陀螺仪数据读取时内部已经把这些标志位处理好了。我们移植时最需要小心的是在自定义SPI底层函数中不要做二次修改。比如我在最开始移植时为了图省事在底层SPI发送函数里统一给地址加了0x80结果官方驱动内部已经加了一次变成了0x80 | 0x80 0x00整个通信彻底崩溃。后来追踪了大半天才发现是地址标志位被重复加了。3.3 加速度计和陀螺仪是两颗芯片片选CS的切换我在前面已经反复提到BMI088的加速度计和陀螺仪是两个独立的芯片各自需要一个片选信号。SPI通信时必须确保只有被访问的那颗芯片的CS引脚被拉低另一颗必须保持高电平。这一点在初始化、读原始数据、设置量程等各种操作中都要贯彻到底。实际调试过程中最典型的错误就是只接了一路CS把两颗芯片的CS都接到同一个GPIO上。这样做的结果是无论访问哪个寄存器两颗芯片都会同时响应MISO上的数据就会变成两路输出打架读出来的数据完全不可用。如果板子是你自己画的画原理图时务必把CSB1和CSB2分别引到MCU的两个GPIO不要图省事把它们连在一起。另外一个容易被忽视的细节是CS引脚的时序。SPI传输过程中CS必须保持低电平不能中途翻转传输结束后CS要拉高至少一小段时间让传感器内部完成一次片选释放。我实测下来HAL库的SPI传输虽然慢一点但天然符合这个时序要求。如果你后面换成DMA优化就要特别注意CS在DMA传输期间不能被意外拉高这个问题我们在第4节再详细说。3.4 上电时序与复位BMI088对电源上电时序的要求比一般传感器严格一些。官方数据手册里写了正常情况下VDD和VDDIO可以同时上电但复位之后必须等待一段时间再做寄存器操作。我实测下来从复位信号释放到可以稳定读到WHO_AM_I至少要等10ms以上保险起见最好等20ms。这个时间不只是等内部时钟稳定还包括内部电源的上升时间。如果你在飞控板上使用BMI088往往还有一个由MCU控制的外部复位引脚RST低电平有效。这个引脚的用法是上电后先把RST拉低至少100微秒再释放然后等待20ms之后再进行初始化。如果你的模块没有引出RST引脚那就直接靠VDD上电后的软复位调用官方驱动的soft reset接口即可。BMI088的软复位也有一个坑软复位后芯片默认回到上电初始状态包括量程、带宽、电源模式都会被重置。所以软复位之后不能立刻读取加速度数据必须等复位完成重新做一遍完整的初始化流程。我在调试过程中曾经写了一个重启函数里面只做了软复位、没有重新初始化量程结果姿态解算输出的角度直接偏了一大截。3.5 量程与数据换算BMI088的加速度计量程有四档±3g、±6g、±12g、±24g陀螺仪有五档±125dps、±250dps、±500dps、±1000dps、±2000dps。量程设置直接影响原始数据的灵敏度数值。官方驱动里初始化时用bmi088_set_accel_range和bmi088_set_gyro_range这两个函数设置量程设置之后返回的原始数据是一个16位有符号整数需要通过灵敏度换算成真实的物理量。不同的量程对应的灵敏度不同换算关系可以简单记为scale 满量程 / 32768。比如加速度计±6g量程下每个LSB对应的加速度大小是6g除以32768约等于0.000183g。陀螺仪±2000dps量程下每个LSB对应的角速度大小就是2000除以32768约等于0.061dps。换算后的单位加速度可以直接用g陀螺仪用dps姿态解算库通常需要的是弧度每秒那就再乘以0.0174533。很多读者跑通驱动后看到加速度计Z轴输出大约是10920就觉得数据不对其实这个数值恰恰是1g重力加速度在±6g量程下的表现。所以看到类似数值时先不要怀疑代码先算一下当前量程的灵敏度匹配上了再继续查其他问题。这里给一个快速速查表传感器量程灵敏度加速度计±3g10920 LSB/g加速度计±6g5461 LSB/g加速度计±12g2730 LSB/g加速度计±24g1365 LSB/g陀螺仪±125dps262.144 LSB/dps陀螺仪±250dps131.072 LSB/dps陀螺仪±500dps65.536 LSB/dps陀螺仪±1000dps32.768 LSB/dps陀螺仪±2000dps16.384 LSB/dps4. SPI通信优化4.1 第一步提高SPI时钟频率官方驱动跑通之后最让人着急的就是采样率提不上去。如果你保持CubeMX里默认的SPI频率不变每次读加速度6字节加上陀螺仪6字节可能要花好几毫秒在1000Hz采样目标下CPU占用率会非常夸张。固件优化第一步就是把SPI时钟频率提上去。BMI088数据手册标称SPI最高10MHz我在STM32F405上分别测试了4MHz、6.75MHz和9MHz最终稳定运行在9MHz。9MHz下完整读取加速度计6字节加陀螺仪6字节总共不到10微秒对于1000Hz采样来说通信时间几乎可以忽略不计。但要注意SPI分频系数一旦设置太高可能超过芯片的上限导致读出来的数据出现位错误。如果你把传输时钟配置到10MHz以上大概率会开始丢数。稳妥起见不要超过9MHz。修改SPI时钟频率的方法是在CubeMX里重新配置SPI的Baud Rate PrescalerF405的SPI1挂在APB2上APB2时钟是84MHz预分频8就是10.5MHz预分频16就是5.25MHz建议预分频16稳定且余量足。如果你是F103APB1是36MHz预分频8就是4.5MHz也是可以接受的。4.2 第二步使用DMA读取降低CPU占用SPI时钟提高后单纯用阻塞方式收发其实也能跑但每次收发都要等SPI完成中断CPU在等待期间是空闲的整体效率依然不高。把SPI读取改成DMA方式是这个项目真正的性能突破口。原理很简单DMA传输期间CPU不用管数据搬运可以去做姿态解算或其他任务等DMA完成中断通知你数据已经就绪。DMA读取加速度计的代码思路是先准备一个7字节的发送缓冲区第1字节是带burst标志的寄存器地址后面6字节填0作为dummy再准备一个7字节的接收缓冲区。CS拉低后启动SPI的TransmitReceive_DMA传输长度是7字节。DMA传输完成后在SPI中断回调里把CS拉高然后从接收缓冲区第1字节开始解析6字节有效数据。static uint8_t acc_tx_data[7]; static uint8_t acc_rx_data[7]; void bmi088_start_acc_read_dma(void) { // 加速度计X轴低字节寄存器地址为0x12 // 0x80表示读0x40表示burst连续读 acc_tx_data[0] 0x12 | 0x80 | 0x40; memset(acc_tx_data[1], 0, 6); HAL_GPIO_WritePin(BMI088_CS1_GPIO_Port, BMI088_CS1_Pin, GPIO_PIN_RESET); // 启动DMA传输 HAL_SPI_TransmitReceive_DMA(hspi1, acc_tx_data, acc_rx_data, 7); } void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { if (hspi-Instance SPI1) { // DMA传输完成拉高片选 HAL_GPIO_WritePin(BMI088_CS1_GPIO_Port, BMI088_CS1_Pin, GPIO_PIN_SET); // 在这里解析acc_rx_data[1]到acc_rx_data[6] // 拼装出X、Y、Z轴的原始数据 } }这里有一个非常关键的注意点DMA传输期间CS必须保持低电平这个由硬件和代码逻辑保证但在DMA完成中断里要马上拉高CS否则传感器可能会把下一次片选误判为burst续传。还有就是在启动DMA前务必确保上一次DMA已经完成并拉高了CS否则连续两次启动DMA会导致CS时序混乱。我后来加了一个信号量只有上一次传输结束后才允许下一次传输开始。4.3 在FreeRTOS下保护SPI总线如果你的STM32工程里已经移植了FreeRTOS那就得考虑多任务共享SPI总线的问题。BMI088的SPI总线可能同时被姿态解算任务、数据记录任务、调试信息任务访问如果不加保护两个任务在时间片上交替访问SPI就会造成CS片选错乱、寄存器数据读到一半被另一任务打断。最典型的故障现象是姿态偶尔跳变概率很低但非常难排查。建议在SPI总线上加一个二值信号量所有涉及BMI088读写的地方都先获取信号量操作完成后释放。DMA方式下要注意信号量不能在启动DMA后就释放必须在DMA完成回调里释放否则下一个任务可能在传输未完成时就动手操作CS引脚一样会出问题。我在项目中做了这样一个封装实际运行了一整晚的长时间采样没有出现一次数据畸形。此外还要注意任务优先级的分配。姿态解算任务的优先级应高于普通日志和调试任务这样即使日志任务正在打印大量调试信息也不会阻塞SPI读取。如果调试串口也占CPU加上SPI阻塞读取CPU占用会瞬间飙高导致姿态解算任务错过采样周期。5. 实测结果与性能数据5.1 实测环境这次移植的测试环境如下MCU是STM32F405RGSPI1连接BMI088SPI时钟设为6.75MHzDMA方式读取采样频率为1000Hz。姿态解算算法用的Mahony互补滤波频率同样设在1000Hz。传感器模块来自淘宝常见封装没有进行额外校准。数据通过串口以200Hz的频率输出到PC端的上位机另外在MCU内部用GPIO翻转法测量了CPU占用率。整个工程除了BMI088驱动之外还运行着一个1ms周期的控制任务和一个100ms周期的状态打印任务。在这样的负载下BMI088的数据读取任务依然能稳定保持1kHz节奏。5.2 1000Hz采样下的CPU占用率对比移植结束后我做了一组对比测试分别用1MHz阻塞读取、6.75MHz阻塞读取、6.75MHz DMA读取三种方式跑1000Hz采样任务用GPIO翻转法测量数据读取相关的CPU占用。结果非常直观读取方式SPI时钟采样率读取任务CPU占用阻塞模式1MHz250Hz40%左右阻塞模式6.75MHz1000Hz15%左右DMA模式6.75MHz1000Hz4%左右从这个表能看出来采样率从250Hz提到1000Hz后如果还保持低速SPICPU几乎被读传感器占满应用程序基本跑不动。单纯提高SPI时钟就能大幅降低CPU占用但这还不够换成DMA后读取任务本身的CPU占用降到5%以内这是官方驱动加经典阻塞方式远远达不到的。我强烈建议有实时控制需求的项目直接上DMA方案。5.3 数据稳定性芯片静止在桌面上时我采集了30秒的原始数据观察换算后的物理量。加速度计三轴的数据波动很小Z轴稳定在1g附近X轴和Y轴基本在0附近。陀螺仪静止时的零偏经过官方驱动的自动校准功能处理之后可以控制在0.1dps以内这说明SPI通信质量良好没有出现位翻转或者数据丢帧。如果你在同样的测试环境下发现陀螺仪零偏达到10dps以上那多半是SPI通信问题而不是传感器本身的问题。可以先把SPI时钟降回4MHz左右对比一下数据是否明显改善。如果有所改善就是信号完整性问题需要检查PCB走线、杜邦线长度、模块供电电压这几个因素。我在测试中遇到过类似的问题最终发现是模块供电的杜邦线压降太大导致VDD只有2.8V换了粗一点的供电线就正常了。6. 常见问题速查表最后把我在移植过程中以及帮朋友调工程时遇到的各种问题整理成一张速查表按现象、原因、排查顺序三步排列直接放在下面供大家对照。现象可能原因排查与解决读WHO_AM_I返回0xFFSPI模式配置错误CS没拉低MISO接反确认SPI Mode 0用示波器/逻辑分析仪看CS和MISO电平读WHO_AM_I返回0x00传感器未上电/供电电压不足芯片处于复位检查VDD和VDDIO电压确保大于1.71V等待20ms后再读数据全0或全FF偶尔正确SPI频率过高信号反射导致位错先降到4MHz验证再检查接线长度和供电质量加速度计数据正常陀螺仪全0陀螺仪CS片选接错或未接陀螺仪处于suspend模式检查CSB2是否接到MCU确认初始化里设置过陀螺仪power mode加速度计Z轴读数接近32768/4量程设置与灵敏度换算不匹配先确认当前量程再用scale满量程/32768计算物理量DMA方式读取偶尔CS时序异常DMA完成回调没有及时拉高片选或者上一次传输未完就启动新传输在DMA回调里拉高CS并增加完成标志或信号量保护陀螺仪零偏很大、数据跳变供电纹波大传感器引脚接触不良加100nF退耦电容改用短而粗的供电线检查焊接质量官方驱动编译报错函数指针类型不匹配不同版本驱动的结构体成员名称不同以实际下载的bmi088.h为准方法上先看结构体定义再写回调函数7. 几点补充经验按照上面的流程做完你的BMI088官方驱动应该已经能在STM32上稳定跑了。这里再分享几个我在实际项目中沉淀下来的小习惯希望能帮你少走弯路。第一个习惯是把传感器相关的宏定义集中放到一个头文件里包括片选引脚、SPI句柄、量程配置、采样频率等。这样后面换板子或者换芯片型号时只需要改这个头文件不需要动驱动源码。芯片厂家的驱动文件建议保持原样你后续更新驱动版本时只需覆盖这两个官方文件即可。第二个习惯是每次上电后先用串口打印加速度计和陀螺仪的WHO_AM_I值再打印初始零点偏移。这样一旦系统出现异常数据你能第一时间判断是传感器通信问题还是算法问题不用每次都从头盯起。第三个习惯是给BMI088的供电单独设计。这颗芯片对电源噪声不算特别敏感但飞控电机转动时带来的电源波动依然会传导到传感器数据上。我建议在传感器电源输入端加一颗4.7uF钽电容加一颗100nF陶瓷电容组合电源走线尽量短粗和电机驱动电源分开铺铜。最后重申一下这次移植最核心的心得先慢后快先阻塞后DMA先验证ID再验证数据。每次改动只改一个变量测试一种配置出了问题能快速回退。这套调试方法不仅适用于BMI088移植任何传感器驱动时都管用。希望这篇经验总结能帮你一次性把BMI088驱动顺利落地。