电子说
RTT 那边的 Kconfig 配置完成,项目的基本开发内容就完成了。然后再对协议栈在 Bluenrg2 芯片上采用 SPI 作为 HCI 的数据传输进行测试。
数据传输使用的是 zephyr_polling 的 thoughput Example。
配置
软件包配置
数据传输
数据吞吐例程内部逻辑是将接收到的数据转发回中心设备。主要提供了两个 GATT 服务:write 和 notify。前者用于接收中心设备发来的数据,后者用于向连接的中心设备发送数据。
输入zephyr运行Example。
手机端使用 BLE调试宝(类似的BLE APP应该都行)连接设备,开启notify服务:
数据传输
数据吞吐例程内部逻辑是将接收到的数据转发回中心设备。主要提供了两个 GATT 服务:write 和 notify。前者用于接收中心设备发来的数据,后者用于向连接的中心设备发送数据。
输入zephyr运行Example。
手机端使用 BLE调试宝(类似的BLE APP应该都行)连接设备,开启notify服务:
连续发送数据:
收发数据没有丢包。
串口打印如下:
initialize rti_board_start:0 done
initialize drv_pm_hw_init:0 done
initialize rt_hw_spi_init:0 done
| /
RT - Thread Operating System
/ | 5.0.1 build Sep 20 2023 22:39:47
2006 - 2022 Copyright by RT-Thread team
do components initialization.
initialize rti_board_end:0 done
initialize stm32l4_hw_lptim_init:0 done
initialize finsh_system_init:0 done
msh >zephyr
zephyr_polling_init
bt_init_hci_driver
SPI_init_process device_name: spi10, spi_name: spi1, rate: 1000000, databits: 8, LSB_MSB: 1, Master_Slave: 0, CPOL: 0, CPHA: 1
SPI_init_process cs_pin_num: 1, irq_pin_num: 0
hci_driver_open, SPI_config_finish
I: (bt_hci_core)hci_init():3230: work start.
msh >prepare_event_process, step: 1
prepare_event_process, step: 2
prepare_event_process, step: 3
prepare_event_process, step: 4
prepare_event_process, step: 5
I: (bt_hci_core)hci_init_end():3205: work end.
E: (bt_smp)smp_self_test():5695: smp_self_test start
I: (bt_hci_core)bt_dev_show_info():3008: Identity: 02:80:e1:00:00:f5 (public)
I: (bt_hci_core)bt_dev_show_info():3042: HCI: version 5.2 (0x0b) revision 0x1222, manufacturer 0x0030
I: (bt_hci_core)bt_dev_show_info():3044: LMP: version 5.2 (0x0b) subver 0x0015
Bluetooth initialized
throughput_svc_init()
Advertising successfully started
I: (bt_hci_core)bt_sleep_prepare_work():4040: start
I: (bt_hci_core)bt_sleep_prepare_work():4046: end
I: (bt_hci_core)bt_sleep_wakeup_work_start():4058: start
I: (bt_hci_core)bt_sleep_wakeup_work_start():4061: end
I: (bt_hci_core)bt_sleep_wakeup_work_end():4072: start
I: (bt_hci_core)bt_sleep_wakeup_work_end():4074: end
Connected
数据传输测试
数据传输测试首先是保证传输的稳定性,保证没有丢包误码。在保证可靠的前提下,再对数据传输的速率进行测试。测试包括双工的收发速率测试和单口的传输速率测试。
测试传输的单个数据包大小为 20 字节。
这里有一个测试方案的问题,一开始使用的方案不对,测得的数据不能保证准确性(没有保证可靠传输),在社区导师的帮助下才得到了比较准确的测试结果。
测试单口传输速率
单口传输的话需要把 thoughput 例程中的发送关闭。此时由于没有给 APP 端反馈,为了保证可靠传输,需要在接收处对接收的数据进行计数,并启动一个软件定时器,定时打印计数。将打印得到的接收字节数与 APP 端的发送字节数对比,二者相符则可以基本保证可靠传输。再根据打印的计数,计算传输速率。
exampleperipheral_throughputthroughput_service.c
关闭发送:
static void throughput_tx_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
// tx_enable = notif_enabled;
// 修改为
tx_enable = 0;
}
在接收处添加计数
static ssize_t data_rx(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
uint16_t len, uint16_t offset, uint8_t flags)
{
...
recv_count += len;
return len;
}
使用协议栈的软件定时器打印计数:
struct k_timer count_work;
...
void count_timeout(struct k_timer *timer)
{
printf("count_timeout(): %dn", recv_count);
recv_count = 0;
}
...
k_timer_init(&count_work, count_timeout, NULL);
k_timer_start(&count_work, K_SECONDS(25), K_SECONDS(50)); // 25s后第一次执行 之后50s为周期执行
这里存在一个如何同步计数的问题。人点击APP端发送的开始和停止时需要反应时间的,需要回避开始和结束。
首先是计数速率的时候,只能取不包含开始和结束的时间段内的计数来计算。
而可靠性保证的时候,并不需要在一次计数完成的时候刚好结束,往后再计数一个周期,将全部的计数结果加起来,能与APP端相符即可。
采取的方案是启动协议栈,并在 APP 端连接后,开始连续发送测试数据包。计数的打印为 25s 后第一次执行,之后 50s 为周期执行。四次打印后结束发送,等待最后一次打印。将 5 次打印的计数求和,与APP端的发送数对比。然后取中间三次 50s 打印的字节数计算传输速率。
经过实际测试,APP 端 2 ms 发送间隔下,在长时间的连续发送下会产生丢包,需要将发送间隔上调至 3 ms 才能保证压测之下没有丢包。
20字节 间隔 2ms 传输持续 200s
协议栈端计数接收到 1494160 字节数据,但 APP 端发出 75046 个数据包,1500920 字节数据。
存在丢包情况。此时速率为 1494160 / 200 = 7470.8 byte/s
单个数据包大小为 20 字节,APP 端 3ms 发送间隔,测试打印:
[16:49:11.997]收←◆Connected
[16:49:26.163]收←◆count_timeout(): 17180
[16:50:16.110]收←◆count_timeout(): 213960
[16:51:06.061]收←◆count_timeout(): 211220
[16:51:56.016]收←◆count_timeout(): 212000
[16:52:45.978]收←◆count_timeout(): 57080
接收到的数据包为 17180+213960+211220+212000+57080 = 711440 字节,与APP端相符。
当前条件下的可靠传输速率为 (213960+211220+212000) / (50 * 3) = 4247.87 byte/s
测试双工的收发速率
数据吞吐例程内部逻辑是将接收到的数据转发回中心设备。在APP端保证发出和收到的字节数相同就能基本保证可靠性,然后再计数固定时间内传输的字节数即可得到传输速率。
同时收发的条件下,需要将发送间隔设置到 25ms 才能保证传输不丢包。
[00:11:22.697]收←◆Connected
[00:11:37.647]收←◆count_timeout(): 4280
[00:12:27.610]收←◆count_timeout(): 36400
[00:13:17.572]收←◆count_timeout(): 36400
[00:14:07.530]收←◆count_timeout(): 36320
[00:14:57.484]收←◆count_timeout(): 36360
[00:15:47.440]收←◆count_timeout(): 1900
APP端收发数相符,没有丢包。打印的计数和为151600,与APP端相符。
速率为 (36400+36400+36320+36360)/200 = 726.95 byte/s
双工传输的速率并不理想,查看传输时的时序图,发现传输所占用的时间比例很少,协议栈有很大的优化空间。
问题
首先是从时序图可以看到 SPI 通信口的利用率不高,有优化空间。
此外 APP 端给芯片发送数据的时候是通过 write GATT 服务进行的,写入的时候会检查接收缓冲区大小,如果满了,应当等待有空闲才会发送(实际去查看APP端的日志,即使将间隔设定为 1 ms,发送的间隔也不会是 1 ms,而是会根据实际情况浮动)。这种机制下,丢包是不应该的。
这两个问题有待之后去改进。
全部0条评论
快来发表一下你的评论吧 !