RA4M2与DA14531 BLE透传实战:UART驱动到手机双向通信
1. 为什么选 RA4M2 搭配 DA14531 做 BLE 透传1.1 这套组合到底解决什么问题如果你手头有一个传感器节点或者工业采集设备主控用的是瑞萨 RA4M2 系列 MCU现在需要把采集到的数据无线传到手机或者上位机上最省事的路径就是加一颗低功耗蓝牙芯片做透传桥接。RA4M2 负责业务逻辑和数据处理DA14531 负责 BLE 链路两者之间用 UART 串口通信手机端通过 BLE 接收数据并可以反向下发指令。这就是标题里说的从 UART 驱动到手机 BLE 双向透传的完整链路。我之所以选这个组合核心原因是 DA14531 在低功耗 BLE SoC 里属于性价比非常突出的一颗。它内置 Cortex-M0 内核RAM 只有 48KBFlash 外部挂载但胜在功耗极低发射电流和接收电流都在 mA 级别深度睡眠可以做到微安级。RA4M2 则是瑞萨 RA 家族里带 TrustZone 的 M33 内核产品主频 100MHz外设资源丰富UART、SPI、I2C 都够用。两者搭配一个管业务一个管无线职责清晰开发难度也可控。这套方案适合谁适合已经有一定 MCU 开发基础、需要快速给产品加上 BLE 通信能力的嵌入式工程师。如果你之前只玩过 HC-05 那种透传模块那这篇文章会让你对 BLE 协议栈和 UART 驱动有更深的理解如果你已经用过 DA14531 的 SDK那 UART 驱动部分的细节和双向透传的缓冲设计应该能给你一些参考。1.2 为什么不用 MCU 自带 BLE 或者换一颗集成芯片很多人会问为什么不直接选一颗带 BLE 的 MCU比如某些国产 SoC 或者 ESP32 系列这个问题我在项目初期也纠结过。带 BLE 的 MCU 确实省事但有几个现实问题第一如果你的产品已经基于 RA4M2 做了硬件设计和认证换主控意味着重新走一遍 EMC 和射频认证成本很高第二RA4M2 的模拟外设和安全特性是很多工业场景需要的BLE SoC 未必能替代第三DA14531 作为独立 BLE 芯片可以把无线部分单独做认证主控板不用动。另一个思路是用现成的 BLE 透传模块比如市面上常见的串口透传模块。这类模块确实开箱即用但问题在于你无法深度定制 BLE 的服务和特征值GATT 结构是固定的手机端只能按模块厂商定义的协议来通信。如果你的应用需要自定义服务、需要控制连接参数、需要在广播包里塞特定数据那模块方案就不够用了。DA14531 虽然开发门槛高一些但 SDK 开放了完整的 BLE 协议栈配置能力灵活性完全不一样。还有一点是功耗。透传模块为了通用性往往默认参数偏保守连接间隔、广播间隔都不是最优的。DA14531 可以让你精细控制这些参数在电池供电场景下连接间隔从 7.5ms 调到 500ms功耗差异可能是数量级的。这个后面在讲连接参数优化时会详细说。1.3 整体架构长什么样先把架构说清楚后面所有细节都围绕这个架构展开。RA4M2 作为主控跑业务逻辑通过 UART 和 DA14531 通信。DA14531 跑 BLE 协议栈对外表现为一个 BLE 外设手机作为中心设备连接它。数据流向是双向的RA4M2 把数据通过 UART 发给 DA14531DA14531 通过 BLE Notify 推给手机手机通过 BLE Write 下发指令DA14531 收到后通过 UART 转发给 RA4M2。这里有个关键设计点DA14531 的 UART 和 BLE 之间需要一个缓冲机制。因为 BLE 的连接间隔和 UART 的波特率是异步的数据到达速率不匹配时必须有缓冲否则会丢数据。DA14531 的 RAM 很小缓冲不能开太大所以需要在协议层做流控或者分包。这个后面会专门讲。硬件连接上RA4M2 的 UART TX 接 DA14531 的 RXRA4M2 的 RX 接 DA14531 的 TX再加上流控引脚如果要用的话。DA14531 的 UART 引脚是复用的需要在 SDK 里配置。供电方面DA14531 可以独立供电也可以从 RA4M2 的 IO 取电但要注意电平匹配DA14531 的 IO 电压范围要看具体型号。2. RA4M2 侧 UART 驱动的配置细节2.1 瑞萨 FSP 里 UART 的配置项怎么选RA4M2 用瑞萨的 FSPFlexible Software Package做开发UART 外设在 FSP 里叫 SCISerial Communications Interface。在 FSP 配置器里新建一个 UART 栈有几个关键参数需要仔细选。第一个是波特率。DA14531 的 UART 最高支持到 921600但实际用下来115200 是最稳妥的选择。为什么因为 DA14531 的 UART 在高速率下对时钟精度要求高如果 RA4M2 的波特率发生器和 DA14531 的内部时钟有偏差高速率下误码率会上升。115200 在两者之间容错空间大实测跑几天都不会丢包。如果你确实需要更高速率建议先做误码率测试。第二个是数据位、停止位和校验。标准配置是 8 数据位、1 停止位、无校验。DA14531 的 UART 也支持这些配置两边必须一致。校验位一般不用因为 BLE 链路本身有 CRC 校验UART 再加校验意义不大反而增加开销。第三个是流控。RA4M2 的 SCI 支持硬件流控RTS/CTS如果 DA14531 那边也配置了流控引脚建议开启。流控的作用是防止 DA14531 缓冲满的时候还在收数据导致丢包。但 DA14531 的引脚资源紧张如果流控引脚不够用那就得在软件层做流控比如用固定长度的包收完一包再发下一包。在 FSP 里配置 UART 的时候还有一个容易忽略的点是回调函数。FSP 的 UART 驱动支持中断和 DMA 两种模式。中断模式适合小数据量DMA 模式适合大数据量。透传场景下数据量不大但要求实时性我一般用中断模式收到一个字节就进回调回调里把数据塞进环形缓冲。2.2 环形缓冲的设计与实现UART 接收最怕的就是数据来了没及时取走导致溢出。RA4M2 的 SCI 有硬件 FIFO但深度有限所以软件层必须有一个环形缓冲。环形缓冲的设计有几个要点。首先是缓冲大小。太小了容易溢出太大了浪费 RAM。透传场景下BLE 的连接间隔通常是几十毫秒UART 波特率 115200 的话几十毫秒能传几百字节。所以缓冲开到 512 字节或 1024 字节比较合适。我一般开 1024留足余量。其次是读写指针的管理。环形缓冲的核心是两个指针写指针由 UART 中断服务程序更新读指针由主循环更新。写指针追上读指针就是溢出读指针追上写指针就是空。这里要注意指针的原子性在 32 位 MCU 上单字节的读写是原子的但如果用 16 位指针就要考虑中断打断的问题。RA4M2 是 32 位内核用 32 位指针操作是原子的不用额外加锁。再就是溢出处理。溢出不可避免关键是怎么处理。我的做法是溢出时丢弃最老的数据保留最新的数据同时置一个溢出标志位。主循环检测到溢出标志后可以通过 BLE 发一个错误通知给手机让上层知道数据有丢失。这比默默丢数据要好至少上层能感知到。代码层面环形缓冲的写操作在 UART 回调里做读操作在主循环里做。写操作只更新写指针读操作只更新读指针两者不冲突。唯一需要注意的是缓冲满的判断写之前先算一下剩余空间不够就丢弃。2.3 UART 发送的阻塞与非阻塞选择UART 发送和接收不一样接收是被动的发送是主动的。发送的时候如果数据量大阻塞式发送会卡住主循环影响其他任务。所以发送一般用非阻塞方式把数据塞进发送缓冲由中断或 DMA 慢慢发。RA4M2 的 FSP UART 驱动支持非阻塞发送调用发送函数后立即返回发送完成会触发回调。但这里有个坑如果你连续调用发送函数而前一次发送还没完成驱动会返回忙状态。所以发送缓冲也需要一个队列主循环把要发的数据放进队列发送完成回调里从队列取下一包发。队列的实现比环形缓冲复杂一点因为要管理包边界。我的做法是用一个简单的链表或者数组队列每个节点存一个包的指针和长度。发送完成回调里检查队列是否为空不空就取下一个包发。这样主循环只管往队列里塞包不用关心发送进度。还有一个细节是发送超时。如果 DA14531 那边因为某种原因不接收了比如 BLE 断连UART 发送会一直等不到完成回调。所以发送队列要加超时机制超过一定时间没发完就清空队列并报错。这个超时时间根据波特率和包大小算一般设个几百毫秒就够了。3. DA14531 侧 BLE 协议栈与 UART 的对接3.1 DA14531 SDK 的工程结构DA14531 的 SDK 是基于 Keil 或者 GCC 的工程结构比较典型。核心目录包括sdk/app_modules里是 BLE 协议栈的 APIsdk/platform里是外设驱动sdk/ble里是 BLE 协议栈本身。用户代码一般放在projects目录下基于官方例程改。官方例程里有一个ble_app_peripheral或者ble_app_barebone这两个是很好的起点。ble_app_barebone最简只有一个自定义服务适合做透传的基础。ble_app_peripheral带电池服务和设备信息服务功能更全。我一般从ble_app_barebone开始改把不需要的服务删掉加上自己的透传服务。SDK 的编译配置里要注意几个宏CFG_PRINTF控制调试输出CFG_UART控制 UART 驱动CFG_BLE控制 BLE 功能。这些宏在da1458x_config_basic.h和da1458x_config_advanced.h里定义。调试阶段把CFG_PRINTF打开可以通过 UART 打印日志但正式发布要关掉省功耗。3.2 DA14531 的 UART 驱动配置DA14531 的 UART 驱动和 RA4M2 不太一样它的 UART 是挂在 APB 总线上的配置寄存器比较底层。SDK 里封装了uart_init和uart_send等函数但配置项需要自己填。关键配置包括波特率、数据位、停止位、流控。波特率通过uart_baudrate结构体配置里面分整数部分和小数部分因为 DA14531 的时钟分频不是整数。115200 对应的分频系数在 SDK 里有现成的宏直接用就行。数据位和停止位在uart_config结构体里配和 RA4M2 保持一致。DA14531 的 UART 接收有两种模式中断模式和 DMA 模式。中断模式每收一个字节进一次中断CPU 开销大但实现简单。DMA 模式收满一定长度才进中断CPU 开销小但配置复杂。透传场景下数据量不大我用中断模式配合一个环形缓冲。这里有个 DA14531 特有的坑它的 UART 中断优先级和 BLE 协议栈的中断优先级需要协调。BLE 协议栈对时序要求高如果 UART 中断优先级太高会打断 BLE 的中断处理导致连接不稳定。所以 UART 中断优先级要设得比 BLE 低。具体优先级数值在 SDK 的arch_config.h里配。3.3 BLE 服务与特征值的定义透传服务的核心是定义两个特征值一个用于手机写数据RX 特征一个用于 DA14531 通知手机TX 特征。这两个特征值放在一个自定义服务里UUID 可以自己生成也可以用标准的透传服务 UUID。特征值的属性配置很关键。RX 特征需要WRITE或WRITE_NO_RESPONSE属性TX 特征需要NOTIFY属性。如果手机端要读数据TX 特征还可以加READ属性。另外TX 特征需要配置 CCCD客户端特征配置描述符手机通过写 CCCD 来开启或关闭通知。在 DA14531 SDK 里服务定义是通过att_db数组来做的。每个条目包括 UUID、权限、长度、回调等。透传服务的att_db大概长这样首先是服务声明然后是两个特征声明每个特征声明后面跟特征值和描述符。CCCD 的描述符要单独加一个条目权限是读写。回调函数是处理 BLE 事件的地方。当手机写 RX 特征时会触发写回调回调里把数据取出来通过 UART 发给 RA4M2。当 DA14531 需要通知手机时调用attmdb_att_set_value更新 TX 特征的值然后发通知。这里要注意通知不是随时都能发的要等 BLE 连接建立并且 CCCD 被使能后才能发。3.4 UART 与 BLE 之间的数据缓冲DA14531 的 RAM 只有 48KBBLE 协议栈占了一部分用户可用 RAM 很有限。所以 UART 和 BLE 之间的缓冲不能开太大我一般开两个 256 字节的缓冲一个用于 UART 到 BLE 方向一个用于 BLE 到 UART 方向。UART 到 BLE 方向UART 收到数据后先放进缓冲然后检查 BLE 连接状态和 CCCD 状态如果都就绪就发通知。如果 BLE 没连接或者 CCCD 没使能数据就留在缓冲里等连接建立后再发。但缓冲有限如果一直没连接缓冲满了就丢弃最老的数据。BLE 到 UART 方向手机写数据触发回调回调里把数据放进缓冲然后触发 UART 发送。UART 发送是异步的发送完成回调里检查缓冲是否还有数据有就继续发。这里要注意BLE 写回调是在 BLE 中断上下文里执行的不能做太耗时的操作所以放进缓冲后尽快返回实际发送由主循环或低优先级任务处理。缓冲的同步是个问题。UART 中断和 BLE 中断可能同时访问缓冲所以需要临界区保护。DA14531 的 SDK 提供了GLOBAL_INT_DISABLE和GLOBAL_INT_RESTORE宏在访问缓冲前后调用即可。但临界区不能太长否则影响 BLE 时序。4. 双向透传的协议设计与流控4.1 为什么需要自定义透传协议直接透传原始数据看起来简单但实际用起来问题很多。第一个问题是包边界。UART 是字节流没有包的概念BLE 通知虽然有长度但手机端收到的通知可能被拆分或合并。如果没有包边界手机端不知道一包数据从哪开始到哪结束。第二个问题是流控。RA4M2 可能一下子发很多数据DA14531 的缓冲装不下BLE 通知又发不了那么快就会丢数据。所以需要一种机制让 RA4M2 知道 DA14531 什么时候能收什么时候不能收。第三个问题是错误处理。如果 BLE 断连了RA4M2 还在发数据这些数据就丢了。需要有一种机制让 RA4M2 知道 BLE 的状态断连时暂停发送。解决这些问题的方法就是定义一个简单的透传协议。协议不需要复杂但要有包长度、包类型和校验。我一般用这样的格式包头1 字节 长度1 字节 类型1 字节 数据N 字节 校验1 字节。包头固定为 0xAA长度是数据部分的长度类型区分数据包、控制包、应答包校验用简单的异或或累加和。4.2 分包与重组的具体实现RA4M2 侧发送数据时先按协议打包然后通过 UART 发给 DA14531。DA14531 收到后解析包头根据长度字段确定包尾然后校验。校验通过后把数据部分通过 BLE 通知发给手机。手机端收到通知后按同样的协议解析。这里有个细节BLE 通知的最大长度受 MTU 限制。默认 MTU 是 23 字节减去 3 字节的 ATT 头实际能带 20 字节。如果数据包超过 20 字节就需要分包发送。DA14531 可以在连接建立后协商更大的 MTU最大可以到 247 字节。协商 MTU 的过程在连接建立后的回调里做调用attm_cfm_mtu_exch或者类似的 API。如果 MTU 协商到 247那大部分包都能一次发完。但如果数据包超过 247 字节还是需要分包。分包的做法是在协议里加一个分包标志或者用长度字段判断。我一般把包大小控制在 200 字节以内避免分包简化实现。手机端下发数据时如果数据超过 MTU手机端会自动分包DA14531 收到的写回调会分多次触发。所以 DA14531 侧需要一个重组缓冲把多次写的数据拼成一个完整的包再通过 UART 发给 RA4M2。重组缓冲的大小根据最大包长来定一般 512 字节够用。4.3 流控机制的落地方式流控的核心是让发送方知道接收方的缓冲状态。有两种做法硬件流控和软件流控。硬件流控用 RTS/CTS 引脚。DA14531 的 UART 支持流控但需要占用两个引脚。如果引脚资源够硬件流控是最可靠的。RA4M2 的 SCI 也支持硬件流控两边配置好之后DA14531 缓冲快满时拉高 RTSRA4M2 检测到 CTS 无效就暂停发送。软件流控是在协议层做。DA14531 在缓冲快满时通过 BLE 通知或者 UART 发一个暂停发送的控制包给 RA4M2。RA4M2 收到后暂停发送等收到继续发送的控制包再恢复。软件流控的缺点是反应慢因为控制包本身也要走 UART 和 BLE有延迟。所以软件流控的阈值要设得保守一些比如缓冲用到 70% 就发暂停用到 30% 才发继续。我实际项目里用的是硬件流控加软件流控双保险。硬件流控处理突发流量软件流控处理持续高负载。两者配合基本不会丢数据。4.4 连接参数对透传性能的影响BLE 的连接参数直接影响透传的吞吐量和延迟。连接参数包括连接间隔、从机延迟、监督超时。连接间隔是两次连接事件之间的时间从机延迟是允许从机跳过多少次连接事件监督超时是多久没收到包就认为断连。连接间隔越小吞吐量越高延迟越低但功耗越大。透传场景下如果数据量大连接间隔设 15ms 到 30ms 比较合适。如果数据量小但要求实时设 7.5ms。如果功耗敏感设 100ms 甚至更大。从机延迟在透传场景下一般设 0因为从机要随时准备收发数据。如果设了从机延迟从机可以跳过连接事件省电但手机发数据时从机可能正好在跳过导致延迟增加。监督超时一般设连接间隔的 10 倍左右。比如连接间隔 30ms监督超时设 300ms 到 500ms。太短了容易误判断连太长了断连后恢复慢。这些参数在 DA14531 侧可以在连接建立后通过gapc_update_param或者类似的 API 发起更新请求。手机端也可以发起更新。实际用下来由 DA14531 发起更新更可控因为 DA14531 知道自己的数据量。5. 调试过程中踩过的坑与排查思路5.1 UART 收不到数据的排查链路项目初期遇到的最典型问题就是 RA4M2 发数据DA14531 收不到。排查这个问题我总结了一套链路从硬件到软件逐层排查。第一步查硬件。用示波器或者逻辑分析仪看 RA4M2 的 TX 引脚有没有波形。如果没有波形说明 RA4M2 的 UART 没配置好或者没使能。如果有波形但 DA14531 的 RX 引脚没有说明线路断了或者电平不匹配。DA14531 的 IO 电压是 3.3VRA4M2 也是 3.3V一般不用电平转换但如果是 5V 的 MCU 就要注意。第二步查波特率。用逻辑分析仪抓波形测量一个位的宽度反推波特率。如果和配置的不一致说明时钟配置有问题。RA4M2 的波特率来自系统时钟分频如果系统时钟配错了波特率也会错。DA14531 的波特率来自内部 RC 振荡器或外部晶振RC 振荡器精度差高速率下容易出问题。第三步查配置。RA4M2 和 DA14531 的数据位、停止位、校验位必须完全一致。我遇到过一次是 RA4M2 配了 8 数据位 1 停止位DA14531 配了 8 数据位 2 停止位结果收到的数据全是乱的。这种低级错误在调试初期很常见建议两边配置打印出来对比。第四步查中断。DA14531 的 UART 中断有没有使能中断服务程序有没有正确挂载中断优先级有没有被 BLE 中断屏蔽。DA14531 的 SDK 里 UART 中断处理函数是uart_isr需要确认它被正确注册到中断向量表里。5.2 BLE 连接不稳定与断连问题BLE 连接不稳定是另一个高频问题。表现是手机连上后几秒或几十秒就断开或者连接上了但收不到通知。先查连接参数。如果连接间隔设得太小比如 7.5ms而 DA14531 的时钟精度不够可能会导致连接事件错过进而断连。把连接间隔调大到 30ms 试试如果稳定了说明是时钟精度问题。再查功耗模式。DA14531 在连接状态下会进入睡眠模式如果睡眠模式配置不对可能会在连接事件到来时醒不过来。检查arch_config.h里的睡眠模式配置调试阶段可以先关掉睡眠确认连接稳定后再逐步开启。还要查天线和射频。DA14531 的射频输出需要匹配网络如果匹配网络没调好发射功率不够连接距离短且不稳定。用频谱仪看发射功率如果明显低于规格书的值就要检查匹配网络。另外天线周围如果有金属或者电池也会影响射频性能。最后查手机端。有些手机的 BLE 协议栈实现有 bug连接参数协商会失败。换几台手机测试如果只有特定手机有问题那就是手机端的问题可以在 DA14531 侧强制使用手机支持的参数。5.3 数据丢包与乱序的定位方法数据丢包和乱序在透传里很常见定位起来比较麻烦因为涉及 UART 和 BLE 两段链路。先在 RA4M2 侧加计数器每发一包计数加一把计数放在包头的保留字段里。然后在手机端也加计数器收到一包检查计数是否连续。如果不连续说明中间丢了。丢包可能发生在 UART 段也可能发生在 BLE 段。区分是哪一段丢包的方法是在 DA14531 侧也加计数。DA14531 收到 UART 包时记录计数发 BLE 通知时记录计数。如果 UART 收到的计数不连续说明 UART 段丢包如果 UART 收到连续但 BLE 发出的不连续说明 BLE 段丢包。UART 段丢包一般是缓冲溢出。检查环形缓冲的大小和溢出标志如果溢出频繁要么加大缓冲要么加流控。BLE 段丢包一般是通知发得太快协议栈缓冲满了。DA14531 的 BLE 协议栈有发送缓冲如果连续发通知超过缓冲深度后面的通知会被丢弃。解决方法是发通知前检查协议栈缓冲状态或者用确认机制收到手机端的确认后再发下一包。乱序一般是分包重组的问题。如果一包数据被拆成多个 BLE 通知发送手机端重组时如果顺序错了数据就乱了。BLE 通知本身是有序的不会乱序但如果手机端多线程处理可能会乱。确保手机端在同一个线程里按顺序处理通知。5.4 功耗异常升高的常见原因DA14531 的卖点是低功耗但如果配置不当功耗会远高于预期。我遇到过几次功耗异常总结下来有几个常见原因。第一个是广播间隔太短。如果设备没连接时一直在广播广播间隔设 100ms 和设 1s平均功耗差很多。如果应用允许广播间隔尽量设大比如 500ms 到 1s。连接后停止广播功耗会降下来。第二个是连接间隔太短。连接间隔 7.5ms 和 100ms功耗可能差好几倍。如果数据量不大连接间隔尽量设大。但要注意连接间隔大了手机发数据的延迟也大要平衡。第三个是外设没关。DA14531 的 UART、SPI、I2C 等外设如果不用要在睡眠前关掉。特别是 UART如果一直开着接收引脚有跳变就会唤醒 CPU功耗下不来。调试完后把不用的外设都关掉。第四个是 GPIO 配置。未使用的 GPIO 要配置成下拉或上拉不能浮空。浮空的 GPIO 会因为外部干扰而跳变导致漏电流。DA14531 的 GPIO 配置在gpio_config里做每个引脚都要明确配置。第五个是调试输出。CFG_PRINTF打开时UART 一直在输出日志功耗会高很多。正式测试功耗前一定要关掉调试输出。6. 手机端 BLE 调试与联调技巧6.1 用通用 BLE 调试 App 快速验证在写手机 App 之前先用通用的 BLE 调试 App 验证 DA14531 的服务和特征值。这类 App 在应用商店里有很多功能都差不多扫描设备、连接、查看服务、读写特征值、订阅通知。用调试 App 的步骤先扫描找到 DA14531 的广播名称连接。然后查看服务列表找到自定义的透传服务。点开服务看到 RX 和 TX 两个特征值。点 TX 特征值的订阅按钮开启通知。然后往 RX 特征值写数据观察 TX 特征值有没有通知回来。这一步能验证 DA14531 的 BLE 服务定义是否正确通知是否正常。如果调试 App 里能看到服务和特征值但写数据没反应说明 DA14531 的写回调没处理对。如果订阅了通知但收不到说明通知发送的代码有问题。调试 App 还有一个用处是看连接参数。有些 App 能显示当前的连接间隔、MTU 大小等信息。这些信息对优化透传性能很有帮助。6.2 手机端收发的线程模型写手机 App 时BLE 的回调是在特定线程里执行的不同平台不一样。Android 的 BLE 回调在主线程或者 Binder 线程iOS 的 CoreBluetooth 回调在特定的 dispatch queue。如果在回调里做耗时操作会阻塞 BLE 协议栈导致连接不稳定。我的做法是在 BLE 回调里只做数据拷贝把数据放进一个线程安全的队列然后由工作线程从队列里取数据处理。发送也是类似工作线程把数据放进发送队列BLE 回调线程从队列里取数据发送。Android 上要注意权限。从 Android 6.0 开始BLE 扫描需要位置权限。从 Android 12 开始还需要蓝牙连接权限。权限没给全扫描不到设备或者连接不上。这个坑很常见调试时先检查权限。iOS 上要注意后台模式。如果 App 退到后台BLE 连接可能会被系统挂起。需要在 Info.plist 里声明蓝牙后台模式并且实现状态恢复。这个比较复杂如果只是调试前台运行就行。6.3 用抓包工具看 BLE 空口数据如果手机端和 DA14531 联调时出现问题用抓包工具看空口数据是最直接的定位方法。抓包工具能抓到 BLE 的广播包、连接请求、数据包等能看到实际收发的数据内容。抓包需要专门的硬件比如某些支持 BLE 抓包的开发板或者专用抓包器。抓包软件一般配合 Wireshark 使用Wireshark 有 BLE 的解析插件能把空口数据解析成可读的协议格式。抓包时要注意几点一是抓包设备要放在 DA14531 和手机之间距离要近否则抓不到。二是要过滤只抓特定设备的包否则数据量太大。三是连接建立时的包要重点看连接参数协商、MTU 协商都在这里。四是数据包要看 ATT 层确认通知和写的句柄是否正确。我遇到过一次问题是手机端写数据DA14531 收不到。抓包发现手机端写的句柄不对写到了错误的特征值上。这种问题看代码很难发现抓包一看就清楚了。6.4 联调时的常见问题速查联调阶段问题比较集中我整理了一个速查表遇到问题先对照排查。现象可能原因排查方法扫描不到设备广播没开、广播间隔太长、射频问题用调试 App 扫描看广播包连接不上连接参数不兼容、协议栈问题换手机测试看抓包连上就断连接参数太激进、睡眠配置错调大连接间隔关睡眠收不到通知CCCD 没使能、通知代码没调调试 App 订阅通知测试写数据没反应句柄错、写回调没处理抓包看写的句柄数据丢包缓冲溢出、流控没做加计数器定位丢包段数据乱序分包重组问题检查重组逻辑功耗高广播/连接间隔短、外设没关逐项关外设测功耗这个表在实际调试中很实用遇到问题先查表能快速缩小范围。7. 从 Demo 到产品的几个关键优化7.1 连接参数的自适应调整Demo 阶段连接参数是固定的但产品阶段要根据实际场景自适应调整。比如设备刚连接时为了快速完成服务发现和参数协商可以用较小的连接间隔。服务发现完成后如果数据量不大可以把连接间隔调大省电。如果检测到数据量突然增大再把连接间隔调小。DA14531 侧可以在连接建立后的回调里发起第一次参数更新设一个较小的间隔。然后在数据收发过程中统计吞吐量如果吞吐量低就发起参数更新调大间隔如果吞吐量高就调小。手机端也可以配合但由 DA14531 主导更简单。自适应调整的难点是参数更新的时机。BLE 的参数更新需要双方协商如果手机端拒绝更新就失败。所以要有重试机制更新失败后等一段时间再试。另外参数更新期间连接会短暂不稳定要避免在数据传输关键期更新。7.2 断连重连与状态恢复产品环境下 BLE 断连是常态比如手机走远了、干扰大了。断连后要能自动重连并且恢复之前的状态。DA14531 侧的做法是在断连回调里重新开始广播等待手机重连。广播参数可以设得比首次连接时更激进比如广播间隔小一点加快重连速度。重连后DA14531 要检查之前的状态比如是否有未发送完的数据如果有就继续发。RA4M2 侧要感知 BLE 的连接状态。DA14531 可以通过 UART 发一个状态包告诉 RA4M2 当前 BLE 是连接还是断开。RA4M2 收到断开状态后暂停发送数据把数据缓存在本地等 BLE 重连后再发。本地缓存的大小根据业务需求定如果数据重要可以存到 Flash 里。手机端也要处理断连。断连后自动重连重连后重新订阅通知。如果 App 有界面要更新连接状态显示。这些逻辑在手机端 SDK 里都有 API按文档实现就行。7.3 固件升级通道的预留产品发布后可能需要升级 DA14531 的固件。DA14531 支持 OTA空中升级可以通过 BLE 升级固件。OTA 需要预留一个 OTA 服务手机端通过这个服务把新固件传给 DA14531。OTA 的实现比较复杂DA14531 的 SDK 里有 OTA 的例程可以参考。关键点有几个一是 OTA 服务要和透传服务共存不能冲突。二是 OTA 过程中要保证不断连所以连接参数要调优。三是 OTA 固件要校验防止升级失败变砖。四是 OTA 完成后要能回滚如果新固件有问题能恢复到旧固件。RA4M2 的固件升级可以通过 DA14531 中转。手机把 RA4M2 的固件通过 BLE 传给 DA14531DA14531 通过 UART 传给 RA4M2RA4M2 自己写 Flash。这需要 RA4M2 侧有 Bootloader 支持。这个通道在透传协议里加一个升级包类型就行。7.4 量产测试的自动化思路产品量产时需要测试每台设备的 BLE 功能是否正常。手动测试太慢需要自动化。自动化的思路是做一个测试夹具夹具里有一个 BLE 中心设备比如另一块 DA14531 或者支持 BLE 的测试仪自动扫描、连接、收发数据、校验。测试项包括广播是否正常、连接是否成功、服务是否完整、通知是否正常、写是否正常、吞吐量是否达标、功耗是否在范围内。测试夹具通过 UART 或者 USB 连接到 PCPC 上跑测试脚本控制夹具执行测试项记录结果。测试脚本可以用 Python 写用 pySerial 控制夹具用 BLE 库比如 bleak做 BLE 通信。测试结果存数据库方便追溯。量产测试还要考虑测试速度。每台设备的测试时间要控制在几十秒内否则产线效率低。所以测试项要精简只测关键功能。非关键功能可以抽检。8. 一些实测数据与经验参数8.1 不同连接间隔下的吞吐量实测我在实验室环境下测了一组数据RA4M2 通过 UART 以 115200 波特率发数据DA14531 通过 BLE 通知发给手机手机端统计吞吐量。测试数据包大小 100 字节连续发 1000 包统计平均吞吐量和丢包率。连接间隔MTU平均吞吐量丢包率7.5ms23约 12 kbps0%7.5ms247约 80 kbps0%15ms247约 60 kbps0%30ms247约 35 kbps0%50ms247约 22 kbps0%100ms247约 12 kbps0%从数据看MTU 对吞吐量影响很大247 比 23 快了近 7 倍。连接间隔越小吞吐量越高但功耗也越高。实际选型时如果数据量不大30ms 到 50ms 的连接间隔足够功耗和吞吐量平衡得比较好。丢包率在测试中都是 0%但这是在实验室无干扰环境下。实际环境中如果有 WiFi 干扰丢包率会上升。所以协议层要有重传机制关键数据丢了要能补发。8.2 功耗实测与电池寿命估算功耗测试用电流表串在 DA14531 的供电回路上测不同状态下的平均电流。状态平均电流说明广播间隔 100ms约 1.2mA广播包 31 字节广播间隔 1s约 0.3mA广播包 31 字节连接间隔 7.5ms约 3.5mA无数据收发连接间隔 30ms约 1.5mA无数据收发连接间隔 100ms约 0.8mA无数据收发连接间隔 30ms持续收发约 4mA吞吐量 35kbps深度睡眠约 2uA外部中断唤醒假设用一颗 200mAh 的纽扣电池设备大部分时间在广播偶尔连接传数据。如果广播间隔 1s平均电流 0.3mA理论待机时间约 660 小时约 27 天。如果每天连接传数据 1 小时连接间隔 30ms连接时电流 1.5mA那每天消耗约 1.5mAh加上广播消耗电池能用几个月。实际电池寿命还受温度、电池自放电等因素影响估算值要打折扣。如果产品要求电池寿命一年以上要么加大电池要么优化功耗比如把广播间隔调到 2s或者用运动唤醒代替持续广播。8.3 UART 波特率与误码率的实测关系UART 波特率越高误码率越高尤其是在时钟精度不够的情况下。我测了 DA14531 在不同波特率下的误码率RA4M2 侧用高精度晶振DA14531 侧用内部 RC 振荡器。波特率误码率RC 振荡器误码率外部晶振96000019200003840000576000.001%01152000.01%02304000.1%0.001%4608001%0.01%9216005%0.1%从数据看115200 及以下RC 振荡器的误码率可以接受。230400 以上RC 振荡器就不行了必须用外部晶振。所以如果产品对成本敏感不想加外部晶振波特率就限制在 115200 以内。如果要用高速率外部晶振是必须的。误码率还和线长有关。UART 是单端信号线长了容易受干扰。如果 RA4M2 和 DA14531 在同一块板上线短误码率低。如果分两块板线长超过 10cm就要考虑加屏蔽或者用差分信号比如 RS485。TTL UART 通过光耦传输的话光耦的响应速度也会限制波特率普通光耦到 115200 就差不多了高速光耦能到 1M 以上但成本高。8.4 天线匹配与射频性能的调试经验DA14531 的射频性能很大程度上取决于天线匹配。DA14531 的射频输出阻抗是差分 50 欧姆左右需要匹配网络转换成单端 50 欧姆再接到天线。匹配网络一般是几个电感和电容组成的 LC 网络。调试匹配网络需要网络分析仪或者频谱仪。没有专业仪器的话可以用 DA14531 SDK 里的射频测试模式让 DA14531 持续发射单载波然后用一个简单的场强计或者 SDR 接收看信号强度。调整匹配网络的元件值让信号最强。天线选型也很重要。PCB 天线成本低但性能一般陶瓷天线体积小但带宽窄外置天线性能好但占空间。透传应用一般用 PCB 天线就够了但要注意天线的净空区天线周围不能有铜箔和电池。如果天线附近有金属谐振频率会偏移需要重新匹配。实际调试时我一般先用官方推荐的匹配网络值然后根据实测微调。如果通信距离明显短于预期先查匹配网络再查天线净空最后查供电和地平面。地平面不完整也会影响射频性能DA14531 的参考设计里有地平面的建议尽量遵循。9. 写在最后的几点个人体会这套 RA4M2 加 DA14531 的方案我从选型到量产走了一遍中间踩了不少坑也积累了一些经验。最大的体会是BLE 透传看起来简单但要做好做稳细节非常多。UART 驱动、缓冲设计、协议定义、流控、连接参数、功耗优化每一个环节都有讲究。另一个体会是调试工具的重要性。逻辑分析仪、抓包工具、电流表这些工具能帮你快速定位问题。没有工具靠猜和试效率太低。建议在项目初期就把这些工具准备好调试时会省很多时间。还有就是不要迷信 Demo。官方 Demo 能跑通但离产品还有距离。Demo 里的配置是通用的不一定适合你的场景。连接参数、缓冲大小、协议格式都要根据实际需求调整。调整的依据是实测数据不是拍脑袋。最后说一点BLE 协议栈本身很复杂但透传应用只用到了很小一部分。不需要把协议栈全部搞懂只要理解 GATT、服务、特征值、通知、写这几个概念就能做透传。遇到问题查 SDK 文档和官方论坛大部分问题都有答案。实在搞不定的用抓包工具看空口数据真相都在数据里。