BLE打流工具设计与吞吐拉满实录:从20Kbps到1296Kbps
发布时间:2026/10/4 16:37:14 锦皓数字建站

上一组文章讲了经典蓝牙 SPP 打流工具的设计和排障吞吐从 83 修到 1208 Kbps有朋友问那 BLE 呢BLE 的吞吐极限怎么看、怎么拉满这篇就讲这个。先给结论同一份打流代码BLE 上的吞吐可以从 20 Kbps 做到 1296 Kbps相差 65 倍——决定权不在代码在三个开关。三个都拨到位BLE 能追平 BT SPP有一个没开数字直接砍到零头。一、先说业务背景为什么 BLE 要做吞吐测试BLE 大部分时间传的是命令和状态这类小数据极限吞吐用得少。真正吃吞吐上限的是三件事OTA 固件升级、传图片、传音频。一次 OTA 传 500KB 镜像700 Kbps 和 20 Kbps 的差别就是 6 秒和 3 分钟——用户握着手机等进度条的时候这个差别非常具体。但还有一半价值在测试评估侧。BLE 上没有标准的吞吐测试工具原因值得说透iperf 打流本质上是上层业务性质的测试不依赖某个特定的底层通信协议但它需要一个标准化的承载通道才可能成为通用工具。WiFi 下有 UDP/TCP 这类标准传输层iperf 才有得依附经典蓝牙有 SPP 这个标准串口通道。而 BLE 连接建立之后必须先创建 GATT 通道才能收发数据标准协议里并没有规范一个专门用于打流的 GATT 服务和通道——每个厂家都得自己建 GATT 通道、自己定义打流协议。承载通道本身没有标准化通用工具自然无从谈起。行业现状也印证了这一点大部分厂家根本没做过 BLE 饱和打流即便做也多是拿手机和设备对传一下——手机侧协议栈自己就有调度和缓冲限制链路根本打不满。测到的是能跑通不是链路极限。所以大部分产品对自己的 BLE 真实极限吞吐是不清楚的。所以打流工具只能自研机制参考 WiFi 的 iperf自建 GATT 通道一端发送、一端按秒统计跑满链路看真实上限。跑出来的数字顺便回答了另一个问题BLE 协议栈的成熟度怎么样——满带打流能把调度、缓冲、连接稳定性层面的毛病全暴露出来命令能通是看不出来的。二、应用层先把该做的做满244 字节包型的算术打流代码本身很简单。先说一个方向上的细节打流要选不需要协议栈回复的 GATT 接口。主机方向用 Write-No-Response写完不等 ACK栈才能连发从机方向用 notify主动上报同样免响应。如果主机用带响应的 Write、从机用 indication每包都要等一次协议栈回执吞吐直接被 ACK 往返拖垮——这和 SPP 篇里流控交给链路层是一个思路。发送线程主机方向write no rsp就是一个不带任何延时的忙发循环static uint32_t iperf_write_task(void *arg) { ble_iperf_data_t pkt { .head 0xAA55, .length 240, .data {0}}; write.handle conn-write_no_rsp_handle; write.len sizeof(pkt); /* 2 2 240 244 */ while (running) { ret gatt_write_no_rsp(write); if (ret ! BLE_OK ret ! BLE_BUSY) break; } }每包 244 字节整包交栈返回 BUSY 当没发生继续塞其余错误退出。没有 sleep、没有节流——什么时候等交给协议栈的流控反馈应用层不瞎掺和。这一点和之前 SPP 排障篇里固定延时是节流不是流控是同一个道理。还有一个容易忽略的配置忙发线程的优先级。它是个while(1)死循环优先级定错了两头出问题——高于底层收发接口它会抢占协议栈线程底层来不及收发吞吐反而掉甚至丢包太低又会被统计、打印这类耗时线程压住发送空转。合理的位置是夹在中间略低于底层收发、高于统计打印。这一条不看代码、只看配置表跟主频一样属于白送的吞吐。关键是 244 这个数怎么来的。三个参数咬合在一起MTU 协商到 247 → ATT PDU 数据区 247 - 3(ATT 头) 244 字节 iperf 包 head(2) length(2) data(240) 244 字节 → 恰好填满一个 ATT PDU无分片、无 padding每包如果超过 MTU-3一包会被拆成多个 ATT 传输开销翻倍小于则有 padding 浪费。MTU 247、数据 240、包头 4加起来正好压线这是一包一个 ATT PDU 的最优解。不过吞吐公式的大头不在这。在连接事件吞吐 ≈ 单个连接事件能传的 LL 字节数 ÷ 连接间隔测试固定连接间隔 100ms每秒只有 10 个连接事件。如果每个事件只能发 1 个 27 字节的 LL 包DLE 未开、Data Length 还是默认值算出来才 2 Kbps 量级。要拉满必须让每个连接事件内连续塞多个 LL 包——这就靠两个底层机制DLEData Length Extension把单个 LL PDU 从默认 27 字节扩到 251 字节发送时间片扩到 2120μs。扩完之后单个连接事件能装的数据量才够看。more data bit链路层发完一包如果上层还有数据待发就把包头的 MD 位置 1告诉对方我这还有连接事件继续拉数据直到时间片用完。100ms 这种稀疏间隔下吞吐天花板完全由单个连接事件能塞下多少字节决定而塞不塞得满就看 MD 这一位。所以应用层的配置清单是MTU 247、DLE 开满251 字节 / 2120μs、每包 244 对齐 MTU、写用 Write-No-Response 免 ACK、发送循环零节流。该做的全做了数字是多少三、第一个开关PHY1M 到 2M实测第一轮1M PHY0-1 sec avg tp 743 Kbps, rssi -23 1-2 sec avg tp 743 Kbps, rssi -24 2-3 sec avg tp 743 Kbps, rssi -22 3-4 sec avg tp 743 Kbps, rssi -22 4-5 sec avg tp 743 Kbps, rssi -22743 Kbps逐秒恒定RSSI 很近、链路很干净——这不是有问题这就是 1M PHY 的满带。BLE 默认跑 LE 1M PHY标称 1 Mbit/s 原始码率但前导、访问地址、包头、CRC 这些固定开销加上连接事件时间片的空转实际应用层载荷封顶就在 700-750 Kbps 这档。应用层配得再满也破不掉物理层的顶。这里要区分一下SPP 那篇里逐秒恒定的低是代码节流的指纹而这次恒定的 743 是物理上限的指纹——同样恒定一个在代码里一个在空口上判断依据是数字靠不靠近理论上限。要突破只有把 PHY 从 1M 协商到 2MLE 2M PHYBLE 5 的特性需要双方都支持走 PHY update 流程。这是吞吐能否翻倍的先决条件也是最容易被忽略的一项——很多团队调参数调半天从来没确认过自己实际跑在几 M 的 PHY 上。协商到 2M 之后10-11 sec avg tp 1296 Kbps, rssi -24 11-12 sec avg tp 1296 Kbps, rssi -24 12-13 sec avg tp 1296 Kbps, rssi -23 13-14 sec avg tp 1296 Kbps, rssi -221296 Kbps1.75 倍基本追平了 BT SPP 优化后的 1208 Kbps。经典蓝牙和 BLE维度对齐打满之后是一个量级的。四、另外两个开关都是踩过的坑2M PHY 是最后一个拨上的开关之前还有两个坑各砍掉过一大截吞吐。开关二CPU 主频同一颗 CPU有两种主频模式默认低功耗跑 32 MHz不休眠可跑 128 MHz。同一份打流代码两种主频下32 MHz~200 Kbps128 MHz~500 Kbps差 2.5 倍。原因不复杂满带打流时协议栈收发、LL 包处理、数据搬运全是 CPU 活主频不够连接事件的时间片内处理不过来链路再好也喂不满。打流前先确认 CPU 跑在哪个档这一条不看代码、只看配置却经常被漏掉。开关三串口打印的实现方式这条最狠。调试打流时顺手加了几条打印吞吐直接从 ~700 Kbps 掉到~20 Kbps35 倍。罪魁是打印的实现方式这个平台的 printf 是关全局中断 忙等发完一整行的阻塞式。发一行打印的功夫整个系统是冻结的——协议栈、定时器、调度全部停摆不只是打流线程被拖慢。打流热路径上每打一次链路就断一截。所以关于打印有三个层次的对策少打逐包打印全删收敛到每秒一条统计观测密度的下限快打串口波特率能上 2M 就上 2M缩短阻塞时长换实现确认平台的打印是不是关中断忙等型——若是热路径上要么换非阻塞异步打印入队后台发要么一根都不碰。第 3 条是最容易被漏的大家习惯性以为加条打印没关系但在这种阻塞实现上打印不是观测是把吸管插进吞吐里。五、三个开关拨完的完整链路状态吞吐卡在哪阻塞打印在热路径 32MHz 1M PHY~20 Kbps每行打印冻结整个系统32MHz 1M PHY打印收敛后~200 KbpsCPU 处理不过来连接事件128MHz 1M PHY~743 Kbps1M PHY 物理上限128MHz 2M PHY~1296 Kbps链路满带与 BT SPP 持平回头看这三个开关没有一个是BLE 知识PHY 是配置意识、主频是系统意识、打印是工程习惯。和 SPP 那三个坑一样全是普通工程问题只是都长在性能路径上。排障时对着这张症状表查症状最可能的位置先查什么吞吐离谱地低几十 Kbps 级打印实现是否关中断忙等阻塞串口、逐包打印吞吐卡在 200 Kbps 档上不去CPU 配置实际主频档位吞吐卡在 700-750 Kbps 恒定PHY当前连接实际 PHY 是 1M 还是 2M、对端是否支持 2M吞吐离 251 字节包模型算的数差好几倍链路层配置DLE 是否真的开到 251、MD 是否在单事件连发六、验收清单BLE 吞吐性能要立得住测试前过一遍链路侧当前连接实际 PHY不是应该协商到了要实测确认、DLE 已扩到 251 且对端同步开启、MTU 247 双端一致、连接间隔确认是预期值别信参数换算看连接更新回读值系统侧CPU 主频档位确认、打流线程优先级夹在低于底层收发、高于统计打印中间观测侧打印收敛到每秒一条、波特率 2M、确认打印实现非阻塞型数据侧逐秒统计窗口的均值方差多轮取稳态RSSI 仅作参考以综测仪为准这些开关都拨到位之后BLE 和 BT SPP 的满带吞吐就在同一量级了——BLE 天生慢是个误会它只是默认配置低。上一篇讲了打流工具的设计分层、双向角色、990B 包型第二篇讲了 SPP 排障83→1208 Kbps这篇是 BLE 侧的拉满实录20→1296 Kbps。三篇合起来是一个完整的故事测试工具值得设计测试结果值得较真。有用的话点个在看让更多工程师看到。你测 BLE 吞吐时踩过哪个开关评论区聊聊。系列文章蓝牙SPP打流工具设计篇蓝牙SPP排障篇83→1208 Kbps标签BLE 低功耗蓝牙 吞吐优化 2M PHY 嵌入式
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。