項目的代碼測試完成之后,準(zhǔn)備收尾時,出現(xiàn)了問題。清除掉開發(fā)過程中用來調(diào)試的print打印之后,zephyr_polling 的 HCI 突然不能正常工作了,之前測試可用的 zephyr_polling 中的各個例程都不再能運行。
這個時候是去掉了 print 打印的,不能從日志找問題。經(jīng)過一個一個嘗試之后定位到了 SPI 接收操作完成之后的一個 print。將其去掉之后,芯片運行會宕機,但若是替換為一個 2 ticks (即2ms)的時延,例程都能正常運行。
但是顯然不能這樣處理這個問題,這樣一是治標(biāo)不治本 (只是在這個環(huán)境下避免了時序問題的發(fā)生,當(dāng)條件改變,問題還可能出現(xiàn)),二是影響性能。
于是使用這個(不太好用的)邏輯分析儀開始尋找問題。
1.是否接收header發(fā)送的太頻繁
先考慮問題是否出在輪詢接收,發(fā)送 header 過于頻繁,導(dǎo)致芯片down。
根據(jù)邏輯時序圖,很多地方都是發(fā)起接收之后直接讀取芯片的待發(fā)數(shù)據(jù)大小。而此時芯片并不一定準(zhǔn)備好了做接收,讀到的數(shù)據(jù)大小很大,導(dǎo)致重復(fù)多次地讀取無用 byte。
官方例程里沒有這個問題是因為接收時中斷調(diào)用的,芯片那邊主動要求接收數(shù)據(jù),一定準(zhǔn)備好發(fā)送了。輪詢的話則應(yīng)該等待芯片做好準(zhǔn)備,拉高irq線再發(fā)送recv_header
處理:
在接收操作發(fā)送 header 前加入 !IsDataAvailable() 校驗,確認芯片準(zhǔn)備好了再發(fā) header 確定要接收的數(shù)據(jù)量。
加入判斷機制后大大減少了啟動用時,提高了效率。
但是去掉print芯片還是down了。
2.是否是拉高cs_pin后irq_pin響應(yīng)太慢
考慮是否是拉高cs后irq_pin響應(yīng)太慢
觀察時序圖發(fā)現(xiàn),MCU 拉高 cs 希望發(fā)送數(shù)據(jù)之后,過了較長一段等待時間后 irq 才拉高進行 header 傳輸。
測試這種情況:cs 拉高再拉低,等待較長一段時間才 irq 拉高,此時傳輸數(shù)據(jù),芯片并沒有 down:
3.是否不能在發(fā)送header之后同時收發(fā)
在接收處加入校驗后的代碼,去掉 print 芯片還是 down 了。觀察其最后的時序,發(fā)現(xiàn)其發(fā)送了發(fā)送 header 之后,同時進行了收發(fā),然后 down 了。
沒有delay 發(fā)送接收碰撞 后續(xù)芯片 down 了, spi 通信失敗:
并且,反復(fù)測試之后,芯片都是在這一次傳輸之后宕機。這里發(fā)送的命令010cfc032c0101是關(guān)閉芯片自帶 host。同時傳輸?shù)氖?04ff03:01:000106 廠商事件包,應(yīng)該是一個 6 字節(jié)的心跳包。
最后的那一個 06 是因為 host 要傳輸?shù)拿钍?7 個字節(jié),最后有個隨機的電平。協(xié)議棧不會對芯片的特殊廠商事件包進行處理,即使被塞入接收隊列,最后協(xié)議棧處理的時候也會將其丟棄。
考慮是否不能同時收發(fā)。對比觀察正常的收發(fā)的時序。
帶 2 ticks delay 的接收
對比發(fā)現(xiàn),正常的工作的傳輸并不會出現(xiàn)收發(fā)同時的情況。
拋開這個宕機問題不談,在發(fā)送的事務(wù)流程中,對于傳輸數(shù)據(jù)過程中芯片發(fā)過來的數(shù)據(jù)是直接丟棄的,而這將導(dǎo)致丟包。雖然這里丟失的是廠商事件包,本來就不會對其處理,但是處于普適性應(yīng)該將其糾正。
解決同時收發(fā)的問題
觀察時序圖發(fā)現(xiàn),發(fā)送 header 之后不進行數(shù)據(jù)傳輸時被芯片允許的。嘗試在實際發(fā)送之前檢查 send_header 響應(yīng)中接收緩沖區(qū)數(shù)據(jù)量,如果不為 0,結(jié)束當(dāng)此發(fā)送流程,先做一次完整接收,并將接收到的數(shù)據(jù)塞到接收隊列里,再重新發(fā)送 send_header (使用while循環(huán),直到待接收數(shù)據(jù)為0),繼續(xù)當(dāng)前數(shù)據(jù)的發(fā)送。
直接在 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);
}
測試發(fā)現(xiàn)并不行,這時想起我沒拉高 CS 結(jié)束這一次發(fā)送傳輸事務(wù)就直接啟動了一次接收,肯定會出錯。加入這一句:rt_pin_write(HCI_TL_SPI_CS_PIN, PIN_HIGH);。
但加入后仍然不能正常使用。發(fā)送超時了,也就是在發(fā)起接收的時候, 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)
查看時序圖:
發(fā)現(xiàn)后續(xù)irq_pin直到超時了都沒動一下,懷疑是前一次的發(fā)送流程沒有被芯片認定結(jié)束。
經(jīng)過一系列嘗試和測試之后,發(fā)現(xiàn)要想結(jié)束當(dāng)次發(fā)送流程,需要將 cs 拉高一定的時間,才能讓 chipset 覺得這次發(fā)送完了:
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;
}
雖然這里引入了時延,但是收發(fā)撞到一起的情況屬于特殊情況,對于整體的性能影響不大。
修改后芯片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)
-
收發(fā)器
+關(guān)注
關(guān)注
10文章
3438瀏覽量
106068 -
緩沖器
+關(guān)注
關(guān)注
6文章
1923瀏覽量
45533 -
邏輯分析儀
+關(guān)注
關(guān)注
3文章
214瀏覽量
23202 -
MCU控制
+關(guān)注
關(guān)注
0文章
48瀏覽量
6760 -
RTThread
+關(guān)注
關(guān)注
8文章
132瀏覽量
40907
發(fā)布評論請先 登錄
相關(guān)推薦
評論