低功耗蓝牙 - 反复更新特征值
Posted
技术标签:
【中文标题】低功耗蓝牙 - 反复更新特征值【英文标题】:Bluetooth Low Energy - updating a characteristic value repeatedly 【发布时间】:2012-05-08 10:28:54 【问题描述】:Follow-Up question on Electrical Engineering Stackexchange
我想在短时间内重复写入 Bluetooth Low Energy 特性的值(作为一个可能的用例,想象一个鼠标)。
128 位 UUID 的特征是 20 字节 长。因此,它可以写在单个 Low Energy 事务中。 写入频率为 50 Hz,相当于每 20 毫秒一次写入。 因此,写入 20 * 50 * 8 = 8 kbit/s。 我正在使用 Command / Write without response 模式来写入特征。因此,属性层上不会发生任何确认。 未连接其他蓝牙或蓝牙低功耗设备。没有通过 WLAN 执行任何操作。在测试期间不会读取或写入其他特征。我通过从 iPhone 4S 发送包含序列号的数据包来测试程序。每发送一个数据包,序列号就加一。
在接收端,使用包含CSR1000 BLE 芯片的可编程开发板接收数据包并将接收到的序列号打印到串行连接。
我的问题如下:
一段时间后,数据包开始被丢弃。前约 100 个数据包在 50 Hz 下工作正常。从那时起,数据包开始被丢弃。
0x00 - 0x46 received
0x47, 0x48 missing
0x49, 0x4a, 0x4b, 0x4c received
0x4d missing
0x4e, 0x4f, 0x50, 0x51 received
0x52 missing
0x53, 0x54, 0x55, 0x56 received
0x57 missing
...
大多数情况下,一包四个数据包可以正常传输(很少只有两个数据包)。然后,1-7 个数据包丢失。
当我减小特征值大小时,问题仍然存在。
当我以 100Hz 而不是 50Hz 写入时,图片是相同的 - 只是在大约 35 个数据包之后开始发生丢包,并且在四个数据包的成功传输之间丢包了 5-7 个数据包。
对于丢失的数据包,产生的传输速率约为 5 kbit/s,无论写入频率如何。这显然低于蓝牙低功耗技术上应该可行的约 305 kbit/s。
当我从开发板向iPhone 4S发送数据包时,问题也出现在相反的方向。同样,5 kbit/s 是我得到的最大值。通知机制用于这种情况。同样,属性层上不会发生任何确认。
当我尝试同时向两个方向发送时,事情开始恶化,以至于我必须重置开发板和 iPhone 4S。
问题:
这可能是开发板上使用的低功耗蓝牙芯片的问题吗?
如果是,为什么问题也出现在相反的方向,即 iPhone 充当接收器?
市面上有支持高频访问特性的开发板吗?
问题的根源可能是什么?
除了假设之外,还请尝试参考蓝牙规范/演示幻灯片/文章的部分内容。
市场上有蓝牙低功耗鼠标。鼠标的典型轮询速率为 125 Hz,并且必须至少发送两个 16 字节的值以及每个滴答的额外 HID 开销。因此,我的问题应该有解决方案。
更新
LE 连接完成事件在Bluetooth Specification Version 4.0 Vol 2 Part E Section 7.7.65.1中有描述。我收到以下不同连接参数的值:
Parameter Value Description
--------------------------------------------------
Conn_Interval 0x0054 Time = 105 ms
Conn_Latency 0x0000 Time = 0 ms
Supervision_Timeout 0x00fc Time = 2520 ms
Master_Clock_Accuracy 0x05 50 ppm
【问题讨论】:
你用的是什么 LE 芯片/开发板? 您为连接设置了哪些参数 - 您使用的是默认值吗? 你怎么看连接时间? @Wilhelmsen:LE 连接完成事件 公开了参数。请参阅蓝牙核心规范版本 4.0 第 2 卷 E 部分第 7.7.65.1 节。我可以在外围设备上查看这些值。 看实际的时序参数还是你设置的外设要求的参数?即,参数是“实时”数据吗? 【参考方案1】:您在丢弃数据包时看到的情况是由于 iPhone 端(我认为很可能)或主机端的缓冲区溢出。从 ios 11.2 开始,Apple 提供了一种机制,允许您在写入下一个数据包之前检查缓冲区是否准备好; canSendWriteWithoutResponse:
如果您等到 canSendWriteWithoutResponse 为真后再写入数据包,则保证已将传递放入接收缓冲区,但不保证已处理(未确认)。另一件可以提供帮助的方法是协商一个大于 20 的 MTU。Apple 支持 MTU 为 185B,最高为 251(扩展数据长度,即 EDL)。通过将数据包分块为 MTU-3 大小,每个连接间隔的数据包 ==(MTU-3) x 1。 @185B MTU,24 ms 连接间隔我的吞吐量约为 48kbps,没有丢包。从设备向 iPhone 发送数据时,该端的 SDK 将需要等效于“canSendWriteWithoutResponse”,在我使用 SiLabs 硬件/SDK 的情况下,它确实具有例如
```
do
result = gecko_cmd_gatt_server_send_characteristic_notification(
0xFF,
evt->data.evt_gatt_server_attribute_value.attribute,
chunk.length,
[chunk bytes])->result;
while(result == bg_err_out_of_memory);
//retry until buffer is empty and ready for more
//then update the offset
offset += thisChunkSize;
```
这是来自 Apple 的视频和 .pdf,解释了不同的 BLE 技术和预期速度。 MTU + 连接间隔用于确定最大吞吐量。 48kbps 应该很容易实现,96kbps 甚至更高一点是可能的。
核心蓝牙的新功能
video: https://devstreaming-cdn.apple.com/videos/wwdc/2017/712jqzhsxoww3zn/712/712_hd_whats_new_in_core_bluetooth.mp4?dl=1
pdf: https://devstreaming-cdn.apple.com/videos/wwdc/2017/712jqzhsxoww3zn/712/712_whats_new_in_core_bluetooth.pdf
【讨论】:
【参考方案2】:发布连接参数更新解决了这个问题,并将吞吐量从 5 kbit/s 提高到 ~33 kbit/s。但是,这仍然低于预期的 ~305 kbit/s。
Conn_Interval = 0x000f = 18.75 ms
Conn_Latency = 0x0000
Supervision_Timeout = 0x00fc
有什么方法可以达到完全的 ~305 kbit/s?
Follow-Up question on Electrical Engineering Stackexchange
烧掉一个 TSI 等待一个月就可以得到 Apple 的回复。
基本上,他们说这种行为是在 iOS 5.1 中设计的。它 不知何故是有道理的,因为他们不希望您的应用程序 性能取决于其他应用是使用蓝牙还是 WiFi。
根据工程师 cmets - 在 iOS 5.1 下,在连接间隔期间应该有 6 对通知,这意味着 6*packetSize*1000/间隔。这应该转换为最大约 55kbps(最小 间隔为 20 毫秒,数据包大小为 23 字节)。我们决定 限制每个间隔的对数并有一个最小间隔到期 iPhone 和 iPad 之间共享天线的事实 BT 经典版、BT LE 和 WiFi。
iOS LE 设计为低功耗传输。对于更高的吞吐量,BT 经典是一种更好的传输方法。
回到我身边 - 根据上面的工程师 cmets,如果希望实现 200 kbs 的吞吐量,经典蓝牙就是答案。 但是,如果希望使用 iPhone 上的应用程序,我 可以理解这不是简单的改变——经典BT需要MFI 许可。
【讨论】:
【参考方案3】:主要问题似乎是您正在使用的芯片上的缓冲区问题。来自核心规范,第 3 卷,第 F 部分,3.3.2:
对于没有响应PDU的通知,没有流量控制,可以随时发送通知。
不需要响应的命令没有任何流控制。注意:服务器可能会被命令淹没,更高层的规范可以定义如何防止这种情况发生。
由于缓冲区溢出或其他原因而无法处理的命令和通知应被丢弃。因此,这些 PDU 必须被认为是不可靠的。
【讨论】:
从开发板到iPhone 4S的方向也存在问题。 写命令和通知,正如这里提到的,没有任何固有的流控制机制。如果溢出堆栈的内部缓冲区会发生什么,由实现来定义。对于发生这种情况时的 iPhone 行为,请尝试在 Apple 蓝牙邮件列表中发布此问题。以上是关于低功耗蓝牙 - 反复更新特征值的主要内容,如果未能解决你的问题,请参考以下文章