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

电子说

1.3w人已加入

描述

项目的代码测试完成之后,准备收尾时,出现了问题。清除掉开发过程中用来调试的print打印之后,zephyr_polling 的 HCI 突然不能正常工作了,之前测试可用的 zephyr_polling 中的各个例程都不再能运行。

这个时候是去掉了 print 打印的,不能从日志找问题。经过一个一个尝试之后定位到了 SPI 接收操作完成之后的一个 print。将其去掉之后,芯片运行会宕机,但若是替换为一个 2 ticks (即2ms)的时延,例程都能正常运行。

但是显然不能这样处理这个问题,这样一是治标不治本 (只是在这个环境下避免了时序问题的发生,当条件改变,问题还可能出现),二是影响性能。

于是使用这个(不太好用的)逻辑分析仪开始寻找问题。

1.是否接收header发送的太频繁

先考虑问题是否出在轮询接收,发送 header 过于频繁,导致芯片down。

根据逻辑时序图,很多地方都是发起接收之后直接读取芯片的待发数据大小。而此时芯片并不一定准备好了做接收,读到的数据大小很大,导致重复多次地读取无用 byte。

MCU控制

官方例程里没有这个问题是因为接收时中断调用的,芯片那边主动要求接收数据,一定准备好发送了。轮询的话则应该等待芯片做好准备,拉高irq线再发送recv_header

处理:

在接收操作发送 header 前加入 !IsDataAvailable() 校验,确认芯片准备好了再发 header 确定要接收的数据量。

加入判断机制后大大减少了启动用时,提高了效率。

但是去掉print芯片还是down了。

2.是否是拉高cs_pin后irq_pin响应太慢

考虑是否是拉高cs后irq_pin响应太慢

观察时序图发现,MCU 拉高 cs 希望发送数据之后,过了较长一段等待时间后 irq 才拉高进行 header 传输。

MCU控制

测试这种情况:cs 拉高再拉低,等待较长一段时间才 irq 拉高,此时传输数据,芯片并没有 down:

MCU控制

3.是否不能在发送header之后同时收发

在接收处加入校验后的代码,去掉 print 芯片还是 down 了。观察其最后的时序,发现其发送了发送 header 之后,同时进行了收发,然后 down 了。

没有delay 发送接收碰撞 后续芯片 down 了, spi 通信失败:

MCU控制

并且,反复测试之后,芯片都是在这一次传输之后宕机。这里发送的命令010cfc032c0101是关闭芯片自带 host。同时传输的是 04ff03:01:000106 厂商事件包,应该是一个 6 字节的心跳包。

最后的那一个 06 是因为 host 要传输的命令是 7 个字节,最后有个随机的电平。协议栈不会对芯片的特殊厂商事件包进行处理,即使被塞入接收队列,最后协议栈处理的时候也会将其丢弃。

考虑是否不能同时收发。对比观察正常的收发的时序。

带 2 ticks delay 的接收

MCU控制

对比发现,正常的工作的传输并不会出现收发同时的情况。

抛开这个宕机问题不谈,在发送的事务流程中,对于传输数据过程中芯片发过来的数据是直接丢弃的,而这将导致丢包。虽然这里丢失的是厂商事件包,本来就不会对其处理,但是处于普适性应该将其纠正。

解决同时收发的问题

观察时序图发现,发送 header 之后不进行数据传输时被芯片允许的。尝试在实际发送之前检查 send_header 响应中接收缓冲区数据量,如果不为 0,结束当此发送流程,先做一次完整接收,并将接收到的数据塞到接收队列里,再重新发送 send_header (使用while循环,直到待接收数据为0),继续当前数据的发送。

直接在 send_header 传输完成之后加入判断,进行一次接收:

/* Read header */
rt_spi_transfer(ble_spi, &header_master, &header_slave, HEADER_SIZE);
rx_bytes = (((uint16_t)header_slave[2])< < 8) | ((uint16_t)header_slave[1]);
uint16_t byte_count = (header_slave[4] < < 8)| header_slave[3];
if (byte_count > 0) 
{
    hci_driver_init_loop();
    result = -2;
}
else
{
  if(rx_bytes >= size)
  {
    /* Buffer is big enough */
    rt_spi_transfer(ble_spi, buffer, &read_char_buf, size);
  }
  else
  {
    /* Buffer is too small */
    result = -2;
  }
  /* Release CS line */
  rt_pin_write(hci_config.cs_pin_num, PIN_HIGH);
}

测试发现并不行,这时想起我没拉高 CS 结束这一次发送传输事务就直接启动了一次接收,肯定会出错。加入这一句:rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_HIGH);。

但加入后仍然不能正常使用。发送超时了,也就是在发起接收的时候, cs 拉低之后,irq 一直没有拉高

| /

RT - Thread Operating System
/ | 5.0.1 build Sep 9 2023 21:50:28
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 >SPI Send timeout 101
E: (bt_hci_core)hci_send_cmd():2928: Unable to send to driver (err -1)

查看时序图:

MCU控制

发现后续irq_pin直到超时了都没动一下,怀疑是前一次的发送流程没有被芯片认定结束。

经过一系列尝试和测试之后,发现要想结束当次发送流程,需要将 cs 拉高一定的时间,才能让 chipset 觉得这次发送完了:

if (byte_count > 0) {
    /* Release CS line */
    rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_HIGH);
    /* to end the send, we need a delay */
    rt_thread_delay(1);
    hci_driver_init_loop();
    result = -2;
}

虽然这里引入了时延,但是收发撞到一起的情况属于特殊情况,对于整体的性能影响不大。

修改后芯片down掉的问题得到解决:

| /

RT - Thread Operating System
/ | 5.0.1 build Sep 9 2023 21:50:28
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
Advertising successfully started
Connected
HRS notifications enabled
HRS notifications disabled
Disconnected (reason 0x13)

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

全部0条评论

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

×
20
完善资料,
赚取积分