在对协议栈在 Bluenrg2 芯片上采用 SPI 作为 HCI 的数据传输进行测试的时候,发现存在丢包问题。当进行大吞吐连续传输时,可以发现协议栈收到的字节数少于测试APP发送的字节数。
首先需要找到丢包的位置,有多个可能:①在HCI层传输上报给协议栈上层的过程丢包;②在HCI层与芯片进行SPI通信时丢包;③在芯片接收和上报的过程丢包(按说可能性不大)。
使用在每一层计数接收到的数据的字节数,进行比较的方式确定产生丢包的位置。
1 在HCI层传输上报给协议栈上层的过程丢包
在 HCI 层的 SPI 初始化hci_driver_init()处也设置一个打印当前接收的字节数的定时任务:
HCI_SPI_ACL_recv_count = 0;
k_timer_init(&HCI_SPI_count_work, HCI_SPI_count_timeout, NULL);
k_timer_start(&HCI_SPI_count_work, K_SECONDS(30), K_SECONDS(30));
void HCI_SPI_count_timeout(struct k_timer *timer)
{
printf("HCI SPI ACL recv count timeout: %dn", HCI_SPI_ACL_recv_count);
}
在HCI层的接收函数hci_driver_init_loop()处,对ACL数据包进行判断和计数。
switch(data[0])
{
case HCI_EVENT_PKT:
buf = bt_buf_get_controller_tx_evt();
break;
case HCI_ACLDATA_PKT:
buf = bt_buf_get_controller_tx_acl();
HCI_SPI_ACL_recv_count += ret;
// printk("ACL: ");
// for (int i = 0; i < ret; ++i)
// {
// printk("%02x:",data[i]);
// }
// printk("n");
break;
default:
return;
}
测试
手机连接BLE模块,发送间隔设定为1ms,数据包大小20字节,测试得到打印结果。比较发现,协议栈上层的计数比HCI层接收处的数据计数更少,在HCI层传输上报给协议栈上层的过程有丢包。
检查HCI层接收数据和上报的代码,发现当数据传输量很大,MCU来不及处理时,协议栈上层的接收队列会堆积最后爆满,HCI 层申请 buffer 的时候可能失败,此时本次从芯片处接收到的数据就会被丢弃。
解决方案是在开始一次 SPI 接收之前,判断当前的缓冲区是否还有空间,有空间才接收。一般来说(事实上最后发现这个芯片好像并不是这样的),芯片收到的数据如果一直没有被HCI层接收,芯片端的缓冲区满了之后,芯片会暂停数据传输服务。这样可以使发送端的传输暂停,等待MCU完成处理后再继续传输,避免丢包。
if (bt_buf_reserve_size(BT_BUF_ACL_IN) == 0)
{
printk("HCI ACL BUFFER EMPTY rn");
return;
}
int ret = HCI_TL_SPI_Receive(data, len); //ret: bytes num Recv
再次测试发现,HCI层接收到的字节数和协议栈上层接收的字节数一致,但手机端发送的字节数和协议栈上层接收的字节数还是不一致,丢包还是存在。
2 在芯片接收和上报的过程丢包
在 SPI 的接收函数HCI_TL_SPI_Receive()处也加入一个计数HCI_SPI_ACL_recv_count,计数从芯片处接收到的全部数据,包括包头等;在HCI层将数据包塞入缓冲区之后,加入一个计数HCI_ACL_buf_recv_count,计数buffer缓冲区内的数据字节数(不包括包头)。
四个计数分别是:
HCI_SPI_recv_count_timeout: 从芯片处通过SPI接收到的全部数据包(包括包头)
HCI SPI ACL recv count timeout: HCI层接收到的ACL数据包的数据(仅数据,不包括包头等)
HCI_ACL_buf_recv_count_timeout: HCI层写入缓冲区后,缓冲区内的data字段里的数据(仅数据,不包括包头等)
app_count: 协议栈上层接收到的数据(仅数据,不包括包头等)
因为蓝牙启动的过程中也有一系列数据交互,为了确保计数的准确性,加入一个开始计数的HCISPIFlag,HCISPIFlag为true时才开始计数。当HCI层接收到手机端发送的99:99:99:99数据包(该数据包不会上报给协议栈上层)时,HCISPIFlag转为true。
ACL数据包的包头为12字节,例如测试数据包的内容:
02:01:281b00:17:00:04:00:520b00:00:01:02:03:04:05:06:07:08:09:00:01:02:03:04:05:06:07:08:09
开始计数的命令判断:
bool HCIcountCmdCheck(uint8_t *buf) {
uint8_t cmd[4] = {0x99, 0x99, 0x99, 0x99};
for (int i = 0; i < 4; ++i)
{
if (buf[i + 12] != cmd[i]) {
return false;
}
}
return true;
}
HCI层SPI接收处的计数:
if(byte_count > 0)
{
/* avoid to read more data than the size of the buffer /
if (byte_count > size)
{
byte_count = size;
}
for(len = 0; len < byte_count; len++)
{
rt_spi_transfer(ble_spi, &char_00, (uint8_t )&read_char, 1);
buffer[len] = read_char;
}
HCI_SPI_recv_count += len;
// ACL pack received count
if (HCISPIFlag)
{
if (buffer[0] == HCI_ACLDATA_PKT) {
HCI_SPI_ACL_recv_count += (len - 12);
}
}
}
测试
手机连接BLE模块,发送间隔设定为1ms,数据包大小20字节,测试得到打印结果:
[00:26:45.218]收←◆Connected
[00:27:05.152]收←◆HCI_SPI_recv_count_timeout: 660
HCI SPI ACL recv count timeout: 0
HCI_ACL_buf_recv_count_timeout: 0
[00:27:05.302]收←◆app count timeout: 0
[00:27:08.899]收←◆HCI count start
app count start
[00:27:35.134]收←◆HCI_SPI_recv_count_timeout: 302404
HCI SPI ACL recv count timeout: 188580
HCI_ACL_buf_recv_count_timeout: 188580
[00:27:35.284]收←◆app count timeout: 189840
[00:28:05.116]收←◆HCI_SPI_recv_count_timeout: 720932
HCI SPI ACL recv count timeout: 450160
HCI_ACL_buf_recv_count_timeout: 450160
[00:28:05.267]收←◆app count timeout: 451560
[00:28:35.096]收←◆HCI_SPI_recv_count_timeout: 1143556
HCI SPI ACL recv count timeout: 714300
HCI_ACL_buf_recv_count_timeout: 714300
[00:28:35.246]收←◆app count timeout: 715480
[00:29:05.081]收←◆HCI_SPI_recv_count_timeout: 1579780
HCI SPI ACL recv count timeout: 986940
HCI_ACL_buf_recv_count_timeout: 986940
[00:29:05.231]收←◆app count timeout: 988100
[00:29:35.066]收←◆HCI_SPI_recv_count_timeout: 1726692
HCI SPI ACL recv count timeout: 1078760
HCI_ACL_buf_recv_count_timeout: 1078760
[00:29:35.215]收←◆app count timeout: 1078760
手机APP端:
手机端发送 55276个包,共1105504字节,其中20字节的测试数据包 55275个,共1105500字节。
协议栈上层收到1078760字节数据,即53938个数据包; HCI层接收到的 ACL 数据包的数据字节数和 HCI 层写入缓冲区的data字段里的数据字节数,与协议栈上层的一致(最终一致,中间定时器打印的count数不一致是因为缓冲区的数据还未被取出)。从芯片处通过SPI接收到的全部数据包为1726692字节,其中660字节为启动阶段传输。
ACL 数据包的包头为12字节,发送的命令 ACL 包为16字节,测试ACL数据包为32字节。则实际接收到的测试ACL数据包为(1726692 - 660 - 16) / 32 = 53938个,与协议栈上层的一致。
对比发现,在芯片接收手机数据和上报的过程中发生了丢包。一般来说,芯片收到的数据如果一直没有被HCI层接收,芯片端的缓冲区满了之后,芯片会阻止发送端(手机)继续发送数据。
-
接收机
+关注
关注
8文章
1181浏览量
53469 -
SPI接口
+关注
关注
0文章
258浏览量
34381 -
BLE威廉希尔官方网站
+关注
关注
0文章
28浏览量
5852 -
MCU芯片
+关注
关注
3文章
252浏览量
11446 -
RTThread
+关注
关注
8文章
132浏览量
40873
发布评论请先 登录
相关推荐
评论