RTT平台zephyr_polling软件包SPI Bluenrg2丢包问题排查

电子说

1.2w人已加入

描述

在对协议栈在 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端:

BLE技术

手机端发送 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层接收,芯片端的缓冲区满了之后,芯片会阻止发送端(手机)继续发送数据。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分