0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

冬至子 来源:paradox 作者:paradox 2023-10-23 15:41 次阅读

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

1.jpg

手机端发送 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

    文章

    1180

    浏览量

    53458
  • SPI接口
    +关注

    关注

    0

    文章

    258

    浏览量

    34373
  • BLE技术
    +关注

    关注

    0

    文章

    28

    浏览量

    5849
  • MCU芯片
    +关注

    关注

    3

    文章

    250

    浏览量

    11439
  • RTThread
    +关注

    关注

    8

    文章

    132

    浏览量

    40861
收藏 人收藏

    评论

    相关推荐

    RTT_Zephyr_Polling BlueNRG2 SPI使用说明

    在RT-Thread平台下,利用 BlueNRG2 蓝牙芯片运行 RTT_Zephyr_Polling 协议栈。使用 SPI 作为 HCI 传输方式。
    的头像 发表于 09-21 14:54 1281次阅读
    <b class='flag-5'>RTT_Zephyr_Polling</b> <b class='flag-5'>BlueNRG2</b> <b class='flag-5'>SPI</b>使用说明

    RTT平台zephyr_polling软件包SPI Bluenrg2芯片宕机问题与修复

    项目的代码测试完成之后,准备收尾时,出现了问题。清除掉开发过程中用来调试的print打印之后,zephyr_polling 的 HCI 突然不能正常工作了,之前测试可用的 zephyr_polling 中的各个例程都不再能运行。
    的头像 发表于 09-25 17:08 1105次阅读
    <b class='flag-5'>RTT</b><b class='flag-5'>平台</b><b class='flag-5'>zephyr_polling</b><b class='flag-5'>软件包</b><b class='flag-5'>SPI</b> <b class='flag-5'>Bluenrg2</b>芯片宕机问题与修复

    RTT zephyr_polling软件包 Bluenrg2蓝牙芯片启动流程

    在用标准的 HCI 指令控制设备进行蓝牙操作之前,需要提前通过 VS Command 对设备进行配置,只有正确配置好的设备才能正常使用。
    的头像 发表于 09-27 11:19 1386次阅读
    <b class='flag-5'>RTT</b> <b class='flag-5'>zephyr_polling</b><b class='flag-5'>软件包</b> <b class='flag-5'>Bluenrg2</b>蓝牙芯片启动流程

    如何用Ubuntu qemu跑zephyr_polling的蓝牙?

    进入 RT-Thread online packages → IoT - internet of things 目录即可看到 zephyr_polling软件包,勾选软件包
    的头像 发表于 09-28 11:24 1909次阅读
    如何用Ubuntu qemu跑<b class='flag-5'>zephyr_polling</b>的蓝牙?

    如何使用RTT Studio配置at软件包来连接wifi模块?

    如何使用RTT Studio配置at软件包来连接wifi模块?
    发表于 02-16 07:47

    SPI驱动屏幕移植LVGL软件包具体流程

    _da, send_data, RT_NULL,2);}二、移植lvgl(一)、添加lvgl软件包首先打开rtthread setting,点击右侧的缩进,打开后,选择软件包,再将多媒体
    发表于 07-08 15:09

    rtt有支持多个文件压缩的软件包

    rtt有支持多个文件压缩的软件包么,比如tar指令,或者有那个大佬实现了多文件压缩的源码可以分享一下么?
    发表于 11-15 10:53

    I2C模块arduinoio Simulink软件包

    I2C模块arduinoio Simulink软件包
    发表于 01-22 14:06 0次下载

    RT-Thread 软件包介绍

    RT-Thread 软件包介绍软件包的目的软件包在高级语言中非常常见,很多高级语言都有对应的软件包平台,比如 Python 的 PyPi,R
    发表于 05-21 19:38 5556次阅读

    RT-Thread软件包定义和使用

    RT-Thread软件包是运行于RT-Thread物联网操作系统平台上,面向不同应用领域的通用软件组件 。RT-Thread 同时提供了开放的软件包
    的头像 发表于 05-21 11:29 1w次阅读
    RT-Thread<b class='flag-5'>软件包</b>定义和使用

    STM32F103C8 使用RT-Thread软件包系统读取MPU6050

    常见的元件自然有相应的软件包啦,在工程根目录打开ENV工具1.在这个目录下可以发现很多软件包,我们将MPU6xxx打开2.在打开RTT的iic支持
    发表于 12-06 14:36 12次下载
    STM32F103C8 使用RT-Thread<b class='flag-5'>软件包</b>系统读取MPU6050

    什么是Linux软件包,如何管理它们

    现代类 Unix 操作系统都提供了一个集中的软件包管理机制,以帮助用户搜索、安装和管理软件。而软件通常以的形式存储在仓库中,对软件包的使用
    的头像 发表于 02-06 14:59 1430次阅读

    RT-Thread在线软件包改为本地软件包的方法

    RT-Thread 的软件包,使用时需要手动通过 ENV 工具 更新到 本地的 packages 目录,并且 packages 目录默认不参与 Git 工程管理,软件包多了,偶尔需要更改软件包本身的一些代码,这就造成了
    的头像 发表于 08-11 15:02 1211次阅读
    RT-Thread在线<b class='flag-5'>软件包</b>改为本地<b class='flag-5'>软件包</b>的方法

    RTT zephyr_polling SPI Bluenrg2数据传输测试

    RTT 那边的 Kconfig 配置完成,项目的基本开发内容就完成了。然后再对协议栈在 Bluenrg2 芯片上采用 SPI 作为 HCI 的数据传输进行测试。
    的头像 发表于 09-25 16:25 897次阅读
    <b class='flag-5'>RTT</b> <b class='flag-5'>zephyr_polling</b> <b class='flag-5'>SPI</b> <b class='flag-5'>Bluenrg2</b>数据传输测试

    RT-Thread平台 zephyr_polling软件包 Bluenrg2 蓝牙芯片启动流程

    RTT zephyr_polling软件包 Bluenrg2 蓝牙芯片启动流程 “开源之夏”“蓝牙HOST协议栈zephyr_polling
    的头像 发表于 09-27 18:40 901次阅读
    RT-Thread<b class='flag-5'>平台</b> <b class='flag-5'>zephyr_polling</b><b class='flag-5'>软件包</b> <b class='flag-5'>Bluenrg2</b> 蓝牙芯片启动流程