BNO080 的 UART-RVC 模式会连续输出固定长度姿态帧。本文以 STM32F103 示例为参照,重点解释可以迁移到 MSPM0G35XX 的接收与解析方法,而不是照搬 HAL 函数名。
已确认的活动调用链
.ioc 和初始化代码确认 USART1 配置为 115200、8N1,接收使用 DMA。main() 调用 BNO080_Init(),USART1 中断路径调用空闲帧处理函数。
USART1 DMA 接收 → UART IDLE 中断 → 计算本次长度 → 扫描 RVC 帧 → 校验 → 角度缓存 → 主循环复制 → USART2 输出这条调用链在配置和源码中是连通的。真正接入硬件后,还要通过编译、串口抓包和帧统计确认运行结果。
为什么使用 DMA + IDLE
RVC 帧连续从串口到达。DMA 可以把字节搬入 128 字节缓冲区,减少每字节中断负担;IDLE 表示总线出现一段空闲,可用来判断本批接收暂时结束。
空闲中断中停止 DMA、读取剩余计数、得到有效长度,再重新启动接收。处理顺序必须避免新字节在停启窗口丢失。
对固定 19 字节帧,也可以使用环形 DMA 和读写索引持续解析,降低停 DMA 的数据空窗。
19 字节帧扫描
解析器寻找连续 0xAA 0xAA,再按固定偏移读取索引、Yaw、Pitch、Roll、三轴线性加速度、保留字节和校验和。
三个角度为小端有符号 16 位,乘 0.01 转成度。工程只消费角度,没有把线性加速度写入对外结构。
扫描时应逐字节比较帧头。原代码把缓冲区强制转换为 uint16_t*,依赖小端字节序和未对齐访问行为,不利于跨 MCU 移植。
短帧边界问题
当 data_length < 19 时,扫描循环仍可能执行一次,并访问尚未属于本批数据的缓冲区内容。
安全逻辑应先判断长度,再保证 index + 19 <= data_length。跨 DMA 批次被拆开的半帧需要保留到下一批拼接,不能直接丢弃或读取旧数据。
还应检查校验失败后的滑动策略。通常只前进一个字节继续寻找帧头,以便从噪声中重新同步。
新数据标志的消费问题
BNO080_GetData() 只把全局结构复制给调用者。主循环随后清除本地副本的 new_data_flag,全局标志仍保持为 1。
结果是同一帧可能被反复当作新数据输出。接口应在受保护的快照过程中消费全局标志,或返回递增序号,由调用者判断是否出现新帧。
如果中断和主循环同时访问多字节浮点结构,还要防止读到新旧字段混合的撕裂快照。
模式 GPIO 配置错误
BNO080_GPIO_Config() 先把 PB0 拉高,随后又把 PB0 拉低;第二次操作从注释看应针对 PB1。
该函数在 main() 中被注释,当前工程依赖外部硬件绑带选择协议模式。不能因为错误函数未调用就忽略:以后启用它会直接选错模式。
模式引脚电平和采样时机应以实际模组原理图与数据手册为准。不要仅根据示例 GPIO 注释接线。
移植到 MSPM0G35XX 的边界
可复用的是协议解析和状态消费设计,不是 STM32 HAL 函数名。迁移时需要重新实现:
- UART、DMA 与空闲检测配置;
- 单调时间戳和超时;
- 环形缓冲或跨批拼帧;
- 原子快照与新数据消费;
- 模式引脚和复位时序。
不要在 MSPM0 代码里伪造 HAL_UART_* 兼容层,除非项目确实选择了这一抽象。
推荐测试用例
- 一帧完整到达。
- 一帧被拆成两批 DMA 数据。
- 两帧连续且无空隙。
- 帧头前出现任意噪声。
- 校验错误后紧接有效帧。
- 长度为 0、1、18、19 和超过缓冲区边界。
- 主循环读取时中断同时更新数据。
移植到 MSPM0G35XX 前还要确认什么
| 检查项 | 当前示例表现 | 移植要求 |
|---|---|---|
| 接收链 | USART1 DMA 与 IDLE 中断已连通 | 用 MSPM0 DriverLib 重建 UART、DMA 与空闲检测 |
| 帧解析 | 已解析 RVC 三轴角度 | 补齐短帧、跨批拼接和校验失败恢复 |
| 线性加速度 | 帧中存在但应用层未消费 | 按需求解析,未使用时也要正确跳过字段 |
| 新数据消费 | 当前只清除了本地副本标志 | 在原子快照中消费全局标志或使用递增序号 |
| 运行验证 | 缺少当前板卡日志 | 记录帧率、丢帧、最长间隔和解析耗时 |
本篇总结
- 工程展示了完整的 UART DMA、IDLE 中断和 RVC 角度解析链。
- 短帧、跨批半帧和未对齐帧头读取需要重写。
- 当前主循环没有真正消费全局新数据标志,会重复处理旧帧。
- 模式 GPIO 函数存在 PB0/PB1 操作错误,而且当前未启用。
- 移植到 MSPM0G35XX 时应复用协议思想,重新实现外设和并发边界。