議棧全解析)
在調(diào)試 NUCLEO-WB55 USBDongle 時(shí)上電不廣播這個(gè)問(wèn)題我前前后后碰到過(guò)三次。每次原因都不一樣一次是出廠固件里壓根沒(méi)燒 BLE 程序一次是 SWD 引腳被代碼占用了導(dǎo)致燒錄失敗還有一次是 USB 供電電流不夠Dongle 插上去之后射頻部分根本沒(méi)起來(lái)。這篇文章就把這三類問(wèn)題、排查過(guò)程和最終解決辦法一次性講清楚給正在被這個(gè)不廣播搞得頭疼的朋友一條完整的排障路線。NUCLEO-WB55 USBDongle 是 ST 推出的基于 STM32WB55RG 的 USB 樣式開(kāi)發(fā)板官方定位是配合 BLE 調(diào)試工具做演示和抓包但在實(shí)際項(xiàng)目中很多人拿它做自定義 Beacon、透?jìng)骶W(wǎng)關(guān)、甚至 OTA 測(cè)試工具。它的核心是雙核 MCUCortex-M4 負(fù)責(zé)應(yīng)用Cortex-M0 只跑藍(lán)牙協(xié)議棧相當(dāng)于一個(gè)獨(dú)立協(xié)處理器所以 BLE 協(xié)議棧運(yùn)行和應(yīng)用邏輯是隔離的。這既是它的優(yōu)勢(shì)也是很多人調(diào)試時(shí)懵圈的地方——你在 M4 上寫的代碼未必能把廣播跑起來(lái)因?yàn)閺V播服務(wù)的真正調(diào)度在 M0 那邊。提示標(biāo)題里的advertizing是 advertising 的常見(jiàn)拼寫錯(cuò)誤搜索引擎里這個(gè)拼法搜出來(lái)的討論反而不少。不過(guò)不影響下面所有內(nèi)容圍繞BLE 廣播不工作來(lái)展開(kāi)。1. 先搞清楚硬件和固件的匹配關(guān)系1.1 NUCLEO-WB55 USBDongle 到底是個(gè)什么板子STM32WB55RG 是一個(gè)雙核無(wú)線 MCU主核 Cortex-M4 跑應(yīng)用代碼協(xié)同核 Cortex-M0 運(yùn)行 ST 預(yù)編譯好的藍(lán)牙協(xié)議棧二進(jìn)制文件稱為 FUS / BLE Stack 固件。NUCLEO-WB55 USBDongle 只是把這塊芯片做成 USB Stick 形態(tài)板上引出了 USB-C 接口、RGB LED、兩個(gè)按鍵、SWD 調(diào)試接口和天線。它和常見(jiàn)的 NUCLEO-WB55RG 開(kāi)發(fā)板最大的區(qū)別是Dongle 版本沒(méi)有板載 ST-LINK不能直接插 USB 線就調(diào)試必須外接一個(gè) ST-LINK 或者借助另一塊 NUCLEO-WB55RG 板載的 ST-LINK 通過(guò) SWD 來(lái)燒錄調(diào)試。很多朋友拿到 Dongle 的第一反應(yīng)是拿 USB 線插電腦然后打開(kāi)手機(jī)藍(lán)牙搜設(shè)備結(jié)果什么都搜不到。這是正常的因?yàn)槌鰪S固件默認(rèn)燒的是ST HID或者BLE Sensor相關(guān)的演示程序而且這取決于你買到的批次和出廠燒錄內(nèi)容。它不是一塊插上就能廣播 Beacon的板子。USB 枚舉成功只代表芯片的 USB 外設(shè)在跑不代表 BLE 射頻在上電后就啟動(dòng)廣播了。USB Dongle 的板載天線是 PCB 天線走的是 2.4G 頻段官方標(biāo)稱輸出功率可以調(diào)到 6 dBm 左右。板子沒(méi)有電池供電電路必須靠 USB 口取電這也是后面供電問(wèn)題的根源。調(diào)試時(shí)建議先看板子上的 LED默認(rèn)程序里 LED 會(huì)閃爍或常亮如果 LED 完全沒(méi)反應(yīng)先懷疑供電和枚舉問(wèn)題如果 LED 正常但無(wú)廣播再往固件方向排查。1.2 默認(rèn)出廠固件不是 Beacon別指望上電就廣播為了確認(rèn)出廠固件內(nèi)容最直接的辦法是用 STM32CubeProgrammer 讀一下芯片的 Flash。連接好 ST-LINK 后打開(kāi) STM32CubeProgrammer選擇 ST-LINK 接口點(diǎn)擊 Connect。如果連接正常在 Memory 視圖里看一眼地址 0x08000000 開(kāi)始的區(qū)域或者直接讀取 Option Bytes。值得注意的是Dongle 版本的 ST-LINK 連接方式不是板載虛擬串口而是 SWD 四線SWDIO、SWCLK、GND、3.3V。我建議第一次拿到 Dongle 的朋友不要急著寫自己的應(yīng)用先 STM32CubeProgrammer 全片擦除然后燒錄官方 BLE_Beacon 例程驗(yàn)證射頻通路是否正常。這一步能隔離硬件壞了還是固件不對(duì)兩個(gè)問(wèn)題。官方例程在 STM32CubeWB 固件包里Projects/P-NUCLEO-WB55.USBDongle/Applications/BLE/BLE_Beacon。需要注意的是BLE 協(xié)議棧固件stm32wb5x_BLE_Stack_full_fw.bin和用戶應(yīng)用固件是分開(kāi)燒錄的FUSFirmware Upgrade Service固件也要提前燒好。出廠時(shí)芯片內(nèi)部一般已經(jīng)燒好了 FUS 和 BLE Stack但如果你執(zhí)行過(guò)全片擦除或者拿到了不帶協(xié)議棧的芯片就必須按順序重新燒錄先燒 FUS再燒 BLE Stack最后燒應(yīng)用。順序錯(cuò)了M0 就起不了協(xié)議棧廣播自然跑不起來(lái)。具體的地址分配在 STM32CubeWB 包里的Projects/P-NUCLEO-WB55.USBDongle/Applications/BLE/BLE_Beacon/README.md寫得非常清楚。1.3 硬件供電和 USB 枚舉的坑USB Dongle 對(duì)供電品質(zhì)很敏感。它的射頻部分在廣播瞬間會(huì)有比較大的電流尖峰如果插在劣質(zhì) USB HUB 或老舊電腦的前置 USB 口上電壓跌落會(huì)導(dǎo)致 M0 協(xié)議棧異常復(fù)位表現(xiàn)就是偶爾廣播一下然后消失或者完全沒(méi)有廣播。我第三次遇到不廣播就是插在一個(gè)不帶外部供電的 USB 3.0 HUB 上。Dongle 的 LED 正常亮USB 枚舉也正常但手機(jī)始終搜不到。用萬(wàn)用表量 USB 的 5V空載時(shí) 5.05V插上 Dongle 后瞬間跌到 4.72V射頻一開(kāi)就掉到 4.5V 以下。換到電腦后置 USB 口或者帶供電的 HUB 后問(wèn)題直接消失。所以排查順序里把供電放在前三位是必要的。另外提醒一點(diǎn)Dongle 的 USB-C 口不是所有線都能用。我遇到過(guò)一根只支持充電不支持?jǐn)?shù)據(jù)傳輸?shù)?USB-C 線導(dǎo)致 STM32CubeProgrammer 無(wú)法識(shí)別設(shè)備但 BLE 廣播其實(shí)正常。這時(shí)候用手機(jī)能看到廣播卻以為板子掛了。遇到怎么都連不上的情況先換一根確認(rèn)能傳數(shù)據(jù)的線。2. 固件燒錄這關(guān)過(guò)不去廣播就是空中樓閣2.1 燒錄用的是哪個(gè)工具鏈NUCLEO-WB55 USBDongle 沒(méi)有板載調(diào)試器燒錄前需要準(zhǔn)備一個(gè) ST-LINK/V2 或者 ST-LINK/V3。我用的是 ST-LINK/V2 的克隆版某寶幾十塊那種配合 STM32CubeProgrammer 完全夠用。接線是標(biāo)準(zhǔn) SWD 四線SWDIO、SWCLK、GND、3.3V。板上 SWD 引腳是印在背面的注意看絲印別焊反。如果你手頭正好有一塊 NUCLEO-WB55RG 開(kāi)發(fā)板也可以把它板載的 ST-LINK 當(dāng)作調(diào)試器給 Dongle 燒錄只需要把 NUCLEO 板上的 CN2 跳線帽拔掉斷開(kāi)板載 ST-LINK 與目標(biāo) MCU 的 SWD 連接然后從 ST-LINK 輸出引腳飛線到 Dongle 的 SWD 引腳。這樣省一個(gè)調(diào)試器但操作麻煩一點(diǎn)我建議還是單獨(dú)買個(gè) ST-LINK幾十塊錢節(jié)省大量時(shí)間。連接好之后打開(kāi) STM32CubeProgrammer選擇 ST-LINK 模式把 Mode 設(shè)為 Under reset 或者 Hot Plug一般 Hot Plug 就夠用。點(diǎn)擊 Connect 后軟件會(huì)讀出芯片型號(hào) STM32WB55RG并在左下角顯示當(dāng)前保護(hù)級(jí)別Read Out Protection 應(yīng)該是 Level 0如果顯示 Level 1 會(huì)限制讀取和燒錄需要先解除保護(hù)。2.2 固件選擇官方示例 vs 自建工程官方固件包 STM32CubeWB 里針對(duì) USBDongle 的 BLE 應(yīng)用主要放在Projects/P-NUCLEO-WB55.USBDongle/Applications/BLE/目錄下包含 BLE_Beacon、BLE_HeartRate、BLE_Throughput 等。BLE_Beacon 是最小的工程邏輯最簡(jiǎn)單特別適合做驗(yàn)證射頻通路這件事。如果你用的是 STM32CubeMX 自建工程注意選擇正確的 BoardP-NUCLEO-WB55.USBDongle。在 CubeMX 里如果不選對(duì)板子引腳分配、射頻匹配、天線開(kāi)關(guān)控制這些配置就會(huì)對(duì)不上。STM32WB55 需要外部 32MHz 晶振HSE32作為射頻參考時(shí)鐘CubeMX 生成的時(shí)鐘樹(shù)如果配置錯(cuò)了BLE 協(xié)議棧初始化會(huì)直接卡在hci_init()或者干脆不廣播。官方案例工程不需要手動(dòng)配置時(shí)鐘因?yàn)楣こ涛募镆呀?jīng)寫好了。這也是我建議新手先用官方案例跑通再改自己工程的原因。如果你用的不是 STM32CubeWB 里的工程而是網(wǎng)上找的第三方模板一定要核對(duì)三個(gè)關(guān)鍵點(diǎn)協(xié)議棧地址、FUS 地址和應(yīng)用起始地址。這三個(gè)地址只要錯(cuò)一個(gè)下載后大概率是程序跑飛或協(xié)議棧起不來(lái)。ST 官方工程里這些地址是通過(guò)鏈接腳本預(yù)置好的不熟悉的朋友不要自己亂改。2.3 燒錄后復(fù)位和連接器的問(wèn)題燒錄完成不是終點(diǎn)Dongle 需要斷電重新上電或者按一下板上的復(fù)位按鈕如果有才能正常進(jìn)入廣播狀態(tài)。很多人燒完固件后不手動(dòng)復(fù)位以為程序會(huì)自動(dòng)運(yùn)行結(jié)果一直沒(méi)廣播。實(shí)際上 STM32CubeProgrammer 燒錄完成后默認(rèn)會(huì)復(fù)位并運(yùn)行但如果你用的是第三方燒錄工具不一定有這個(gè)行為手動(dòng)斷電重插一次最穩(wěn)。另外一個(gè)容易踩的坑是 SWD 引腳被復(fù)用了。有些 BLE 應(yīng)用會(huì)把 PB3、PB4、PA15 這些 SWD 相關(guān)引腳配置成 GPIO 或者射頻控制腳一旦代碼運(yùn)行調(diào)試接口就被切斷了。這會(huì)導(dǎo)致你燒錄完第一次程序后第二次再也連不上 ST-LINK。解決辦法是燒錄時(shí)把 BOOT0 拉高讓芯片從系統(tǒng)存儲(chǔ)器啟動(dòng)先中斷用戶程序然后用 STM32CubeProgrammer 重新連接并擦除 Flash。但我實(shí)際操作下來(lái)STM32WB55 的 BOOT0 引腳拉高有講究Dongle 板上沒(méi)有專門引出來(lái)得飛線。更省事的辦法是使用 STM32CubeProgrammer 的 Connect under reset 模式把復(fù)位引腳也接上在復(fù)位釋放的瞬間拉低 SWD 請(qǐng)求成功率更高。SWD 連接不上是一個(gè)高頻問(wèn)題。如果你確認(rèn)接線正確、驅(qū)動(dòng)正常但 STM32CubeProgrammer 始終報(bào) No ST-LINK detected 或 Target connection failed優(yōu)先檢查 Option Bytes 里的 RDP 級(jí)別。我之前買過(guò)一批二手 Dongle里面 RDP 被設(shè)置成了 Level 1直接導(dǎo)致無(wú)法連接必須先用 STM32CubeProgrammer 的 Remove protection 功能解除。注意解除保護(hù)會(huì)全片擦除之后需要重新燒錄 FUS 和 BLE Stack。3. 從 Beacon 示例開(kāi)始一步一步讓 Dongle 廣播起來(lái)3.1 打開(kāi)官方 Beacon 例程改參數(shù)前先理解參數(shù)STM32CubeWB 的 BLE_Beacon 例程位置我上面已經(jīng)給了用 IAR、Keil 或者 STM32CubeIDE 打開(kāi)都可以。我自己主要用 STM32CubeIDE開(kāi)箱即用不需要額外配置工程鏈。打開(kāi)之后先不要編譯先在app_conf.h和hci_tl.h里確認(rèn)協(xié)議棧相關(guān)配置再看app_ble.c。BLE_Beacon 例程的核心就是adv_data[]這個(gè)數(shù)組它定義了廣播數(shù)據(jù)的內(nèi)容。例程默認(rèn)發(fā)的是一個(gè)簡(jiǎn)單的自定義 Beacon廣播間隔默認(rèn)參數(shù)通常是ADV_INTERVAL_MIN_MS和ADV_INTERVAL_MAX_MS單位換算成 BLE 的時(shí)間單位是 0.625ms。官方默認(rèn)值看兩個(gè)宏但最終的值會(huì)被aci_gap_set_discoverable()這個(gè) HCI 命令的Advertising_Interval_Min、Advertising_Interval_Max參數(shù)覆蓋。有一點(diǎn)很多新手會(huì)搞錯(cuò)BLE 廣播間隔不是一個(gè)固定數(shù)值而是一個(gè)區(qū)間實(shí)際廣播間隔由協(xié)議棧在這個(gè)區(qū)間內(nèi)隨機(jī)選取這是藍(lán)牙規(guī)范用來(lái)減少同頻干擾的機(jī)制。所以如果你配置的 min100ms、max100ms實(shí)際廣播串間隔也不會(huì)完全是 100.000ms而是在 100ms 附近抖動(dòng)。用手機(jī) App 觀察時(shí)別因?yàn)槊看螐V播間隔有幾毫秒偏差就覺(jué)得有問(wèn)題。廣播數(shù)據(jù)里除了用戶自定義的 Manufacturer Specific Data還有必要的 Flags 字段表示這個(gè)設(shè)備支持LE General Discoverable Mode。如果 Flags 缺失很多手機(jī) App 會(huì)直接過(guò)濾掉這個(gè)廣播包表現(xiàn)為設(shè)備可見(jiàn)但不顯示。所以自建廣播數(shù)據(jù)時(shí)Flags0x02 0x01 0x06這 3 個(gè)字節(jié)一定不要省。3.2 編譯燒錄和串口日志驗(yàn)證BLE_Beacon 例程默認(rèn)不開(kāi)串口日志但 NUCLEO-WB55 USBDongle 的虛擬串口是通過(guò) ST-LINK 的 CDC 實(shí)現(xiàn)的Dongle 本身并沒(méi)有獨(dú)立的 USB-UART 橋接芯片。所以如果你用的是外接 ST-LINK它是沒(méi)有虛擬串口的你只能在 STM32CubeProgrammer 的 Serial Wire ViewerSWV里看 printf 輸出或者直接忽略日志靠 LED 狀態(tài)判斷。這個(gè)板子有一個(gè) RGB LED在 BLE_Beacon 例程里如果廣播正常LED 會(huì)進(jìn)入一個(gè)周期閃爍狀態(tài)。具體顏色和頻率在app_ble.c里可以通過(guò)BUTTON_LED相關(guān) API 調(diào)整。我的判斷方法是如果上電后 RGB LED 有周期性閃爍說(shuō)明 M4 應(yīng)用已經(jīng)跑起來(lái)了再配合手機(jī)端看到廣播包基本可以確認(rèn)整個(gè)鏈路沒(méi)問(wèn)題。編譯燒錄這步要注意先用 STM32CubeProgrammer 確認(rèn) Flash 里已經(jīng)燒好了 BLE Stack。檢查方法是在 Memory 視圖里讀協(xié)議棧地址比如 0x08008000 或 0x08080000取決于工程配置如果全是 0xFF 說(shuō)明協(xié)議棧沒(méi)燒進(jìn)去。BLE_Beacon 例程的鏈接腳本里定義了BLE_STACK_ADDRESS不同版本偏移不同所以直接用 .bin 燒的時(shí)候一定要按 README 里的偏移地址來(lái)。我犯過(guò)的錯(cuò)誤是把 BLE_Stack 固件用默認(rèn) 0x08000000 地址燒進(jìn)去直接把應(yīng)用固件覆蓋了然后整板變磚重新燒了三次才搞對(duì)。3.3 用手機(jī)和抓包器確認(rèn)廣播包廣播跑沒(méi)跑起來(lái)最直觀的手段是手機(jī)。iOS 上推薦用 LightBlue 或 nRF ConnectAndroid 上我用的是 nRF Connect 和BLE 調(diào)試助手這類 App。打開(kāi) App 掃描如果看到廣播名比如ST Beacons或你自定義的設(shè)備名說(shuō)明廣播已經(jīng)發(fā)出去了。但這只是第一步廣播包的內(nèi)容是否合法、功率是否達(dá)標(biāo)單靠手機(jī)看不詳細(xì)。深入排查時(shí)必須上抓包器。低成本方案是再拿一塊 NUCLEO-WB55 開(kāi)發(fā)板刷成 BLE Sniffer配合 Wireshark 抓包。ST 官方提供了STM32WB BLE Sniffer工具用起來(lái)比 nRF Sniffer 稍微麻煩一點(diǎn)但配置無(wú)誤的話抓包結(jié)果很干凈。抓包主要看三點(diǎn)廣播事件是否周期性出現(xiàn)、廣播通道37/38/39是否都能抓到、RSSI 是否符合預(yù)期。如果只有單個(gè)通道出現(xiàn)廣播說(shuō)明射頻鏈路有問(wèn)題如果三個(gè)通道都有但 RSSI 極低優(yōu)先懷疑天線匹配或供電。手機(jī)能搜到廣播但 RSSI 顯示特別弱比如 -80 dBm 以下而且人靠近板子也只有 -60 左右這種一般不是軟件問(wèn)題而是射頻硬件或天線問(wèn)題。NUCLEO-WB55 USBDongle 的 PCB 天線區(qū)域務(wù)必保持干凈不要用手大面積握住天線部分也不要用 USB 延長(zhǎng)線把 Dongle 懸在金屬桌面附近。金屬物體對(duì) 2.4G 天線的吸收效應(yīng)非常明顯實(shí)測(cè)同一塊板子放在金屬底座上和放在塑料支架上RSSI 能差 15 到 20 個(gè) dB。注意BLE 的廣播通道固定在 2402MHz、2426MHz、2480MHz這三個(gè)頻點(diǎn)旁邊往往有 Wi-Fi 的 2.4G 信號(hào)。如果現(xiàn)場(chǎng) Wi-Fi 信道恰好落在這些頻點(diǎn)附近廣播包碰撞概率會(huì)增大但不是廣播消失的根因。只要廣播間隔正常協(xié)議棧會(huì)在后續(xù)間隔里重試不會(huì)出現(xiàn)永久看不到的現(xiàn)象。4. 常見(jiàn)問(wèn)題與排查技巧實(shí)錄4.1 上電后完全沒(méi)有廣播手機(jī)和抓包器都找不到這是最典型的情況優(yōu)先級(jí)最高的是確認(rèn)協(xié)議棧是否起來(lái)了。可以在app_ble.c的APP_BLE_Init()里臨時(shí)加一個(gè) GPIO 翻轉(zhuǎn)用示波器或者邏輯分析儀看 M0 初始化完成后有沒(méi)有執(zhí)行到。實(shí)際上更快的辦法是檢查hci_init()的返回值STM32WB55 的 HCI 層和 M0 通信是通過(guò)內(nèi)部 IPC 完成的如果返回錯(cuò)誤說(shuō)明 M0 沒(méi)有正常運(yùn)行協(xié)議棧。常見(jiàn)的錯(cuò)誤返回是HCI_UNSUPPORTED_FEATURE或者HCI_COMMAND_DISALLOWED這兩種情況通常不是應(yīng)用代碼問(wèn)題而是 FUS 和 BLE Stack 版本不匹配。去 ST 官網(wǎng)下載最新版 STM32CubeWB里面固件和 FUS 是配套的不建議混搭不同版本。版本不匹配的典型現(xiàn)象就是編譯燒錄都成功、LED 正常、就是不廣播排查成本極高所以我開(kāi)頭就說(shuō)先確認(rèn)協(xié)議棧版本匹配。還有一個(gè)隱蔽問(wèn)題FUS 的啟動(dòng)狀態(tài)影響整個(gè)協(xié)議棧加載。在 STM32CubeProgrammer 的 FUS 頁(yè)面操作時(shí)如果看到 FUS is not running說(shuō)明 FUS 沒(méi)有啟動(dòng)需要先發(fā)送 Start Wirestack 命令或者重新燒錄 FUS。這個(gè)狀態(tài)在出廠芯片里一般沒(méi)問(wèn)題但如果你對(duì) Flash 做過(guò)擦除就得重新走一遍 FUS 啟動(dòng)流程。4.2 廣播時(shí)有時(shí)無(wú)間隔一大就消失廣播時(shí)有時(shí)無(wú)通常不是節(jié)點(diǎn)本身的問(wèn)題而是環(huán)境干擾或供電跌落。我遇到過(guò)一種情況板子放在電腦旁邊靠近 USB3.0 HUB 時(shí)廣播正常但放到金屬機(jī)箱上后廣播消失拿起來(lái)懸空廣播又回來(lái)了。這個(gè)屬于天線阻抗受周圍環(huán)境變化導(dǎo)致發(fā)射效率下降協(xié)議棧本身沒(méi)有報(bào)錯(cuò)。解決辦法很粗暴把 Dongle 放到干凈的位置再測(cè)試。另一種可能是ENTER_LOW_POWER_MODE沒(méi)有關(guān)閉導(dǎo)致 MCU 進(jìn)入低功耗狀態(tài)后射頻子系統(tǒng)的時(shí)鐘或供電被間歇性關(guān)斷廣播間隔被拉長(zhǎng)到幾秒甚至十幾秒一次。在官方例程里CFG_LOW_POWER_MODE這個(gè)宏默認(rèn)是啟用的它在電池設(shè)備上很有用但在 USB 供電的 Dongle 上沒(méi)意義。如果你發(fā)現(xiàn)廣播間隔比配置值大很多看看這個(gè)宏是否被定義成了 1改成 0 后問(wèn)題通常馬上消失。低功耗設(shè)計(jì)本身沒(méi)有錯(cuò)但在 USB Dongle 這種持續(xù)供電設(shè)備上省電邏輯只會(huì)引入不必要的復(fù)雜度。還有一次我的現(xiàn)象是手機(jī)掃到廣播后不斷重連連上就斷開(kāi)用抓包器看廣播正常但連接請(qǐng)求CONNECT_REQ階段設(shè)備沒(méi)有回應(yīng)。檢查后發(fā)現(xiàn)是代碼里沒(méi)有正確處理連接事件回調(diào)M4 沒(méi)有及時(shí)調(diào)用aci_gap_connection_complete_event之后的程序相當(dāng)于只廣播但不參與連接。這個(gè)屬于應(yīng)用層邏輯問(wèn)題不是射頻問(wèn)題排查方向要分開(kāi)。4.3 手機(jī)看不到但抓包器能正常抓到廣播這種場(chǎng)景很有迷惑性抓包器確認(rèn)廣播在發(fā)手機(jī)卻掃不到很多人會(huì)懷疑手機(jī)壞了。其實(shí)大概率是廣播數(shù)據(jù)格式或廣播參數(shù)不滿足手機(jī)端過(guò)濾條件。如果廣播包設(shè)置了ADV_TYPE為不可連接廣播Non-connectable undirected advertising很多手機(jī)在掃碼界面會(huì)直接忽略因?yàn)檫@種廣播不可連接掃了也沒(méi)用。Beacon 類應(yīng)用常用這個(gè)類型但如果是想做連接類應(yīng)用要選擇可連接廣播。另一種情況是廣播周期太長(zhǎng)。如果把廣播間隔調(diào)到 1000ms 以上手機(jī)端掃描窗口通常是 10.24 秒為一個(gè)周期其中約 3.84 秒在掃描就有概率漏掉你表現(xiàn)為時(shí)有時(shí)無(wú)。藍(lán)牙規(guī)范里若廣播間隔小于等于 100ms掃描器幾乎必能發(fā)現(xiàn)間隔大于 1s 時(shí)就要碰運(yùn)氣了。排查時(shí)把廣播間隔臨時(shí)調(diào)小到 50~100ms如果手機(jī)馬上能看到問(wèn)題就在廣播參數(shù)上。手機(jī)上裝了某些過(guò)濾類 App比如防廣告攔截類的可能會(huì)屏蔽未知 BLE 設(shè)備。我自己的 Android 手機(jī)上裝了個(gè)網(wǎng)絡(luò)管控工具它會(huì)把廠商 ID 是 0xFFFF 的廣播包當(dāng)成可疑設(shè)備自動(dòng)過(guò)濾掉。換個(gè)手機(jī)或者換 App 試試能避免被這種軟件玄學(xué)帶偏方向。4.4 RSSI 和天線布局為什么廣播功率調(diào)了沒(méi)效果官方例程里通常有aci_hal_set_tx_power_level()這個(gè) API可以設(shè)置發(fā)射功率比如 0 dBm、3 dBm、6 dBm。很多人調(diào)大功率后發(fā)現(xiàn)手機(jī) RSSI 沒(méi)有明顯提升就以為 API 沒(méi)生效。實(shí)際上 STM32WB55 的發(fā)射功率有多個(gè)等級(jí)最大 6 dBm 時(shí)電流消耗明顯增加但 RSSI 的提升不是線性的——從 0 dBm 調(diào)到 6 dBm理論上只增加 6 dB反映在手機(jī)上通常只有幾個(gè) dB 的改善而環(huán)境的反射、路徑損耗、天線方向帶來(lái)的影響遠(yuǎn)不止 6 dB。天線布局對(duì) RSSI 的影響更大。NUCLEO-WB55 USBDongle 的天線區(qū)域在 PCB 一端距離 USB 接口較遠(yuǎn)。使用時(shí)要保證天線周圍 1cm 以內(nèi)沒(méi)有金屬遮擋。如果 Dongle 是插在電腦后面板或者顯示器集線器上天線部分可能被金屬殼包圍信號(hào)衰減會(huì)非常明顯。最好用一根 USB 延長(zhǎng)線把 Dongle 拖出來(lái)讓天線區(qū)域懸空實(shí)測(cè) RSSI 能從 -70 dBm 提到 -55 dBm。RSSI 調(diào)試時(shí)還要注意測(cè)量環(huán)境的一致性。我會(huì)固定一個(gè)測(cè)試位置板子放在塑料泡沫支架上手機(jī)固定在 1 米外的同一地點(diǎn)然后把所有變量廣播間隔、信道、發(fā)射功率、天線方向逐個(gè)調(diào)整每次只改一個(gè)變量。如果不控制變量連續(xù)測(cè)得 RSSI 波動(dòng)能有 ±10 dB根本無(wú)法判斷改動(dòng)效果。5. 幾個(gè)值得收藏的排查習(xí)慣和工具搭配5.1 遇到問(wèn)題先做減法而不是做加法不廣播這個(gè)問(wèn)題的排查思路我建議遵循從底層往上的減法原則先確認(rèn)供電和硬件再確認(rèn)調(diào)試連接再確認(rèn)協(xié)議棧是否運(yùn)行最后才是應(yīng)用代碼邏輯。很多朋友一上來(lái)就懷疑自己寫的廣播數(shù)據(jù)有問(wèn)題改了半天發(fā)現(xiàn)是 ST-LINK 線接觸不良浪費(fèi)時(shí)間。我的排障順序是固定的萬(wàn)用表量 USB 5V 電壓插上 Dongle 后看壓降是否超過(guò) 0.3V確認(rèn) STM32CubeProgrammer 能正常連接并讀出 Flash 內(nèi)容確認(rèn) Flash 里存在的固件類型和地址是否符合預(yù)期燒官方 BLE_Beacon 例程驗(yàn)證射頻通路手機(jī) nRF Connect 掃描看 RSSI 和廣播名如果還不行用抓包器看協(xié)議棧行為這套順序能覆蓋我遇到過(guò)的所有不廣播場(chǎng)景。不需要每次都走完但遇到玄學(xué)問(wèn)題時(shí)從頭走一遍往往能發(fā)現(xiàn)前面遺漏的細(xì)節(jié)。5.2 工具搭配建議調(diào)試器ST-LINK/V2 或 V3建議用原版或者質(zhì)量好的兼容版劣質(zhì)克隆版在 SWD 高速模式下容易不穩(wěn)定。燒錄工具STM32CubeProgrammer版本盡量新注意它和 STM32CubeWB 固件包版本的配套關(guān)系。抓包工具另一塊 NUCLEO-WB55 開(kāi)發(fā)板 STM32WB BLE Sniffer 固件 Wireshark成本低效果好。手機(jī) AppnRF ConnectAndroid/iOS 都有、LightBlue各裝一個(gè)交叉驗(yàn)證掃描結(jié)果。萬(wàn)用表普通的 3 位半萬(wàn)用表就夠主要量電壓。邏輯分析儀排查低功耗模式問(wèn)題時(shí)有用看 GPIO 翻轉(zhuǎn)狀態(tài)和時(shí)序。這套工具加起來(lái)成本不高但能把軟件能看到和射頻實(shí)際發(fā)出去這兩件事同時(shí)覆蓋排障時(shí)不用來(lái)回猜。5.3 現(xiàn)場(chǎng)環(huán)境對(duì) BLE 廣播的影響比想象中大最后提醒一點(diǎn)BLE 廣播的現(xiàn)場(chǎng)環(huán)境因素非常容易被忽略。我曾在辦公室里調(diào)試一塊 Dongle手機(jī)就在旁邊但始終搜不到廣播抓包器一抓發(fā)現(xiàn)廣播事件一直在發(fā)。反復(fù)排查后發(fā)現(xiàn)辦公桌旁邊有一個(gè) USB 3.0 高速硬盤盒它的金屬外殼和內(nèi)部高速信號(hào)正好在 2.4G 頻段產(chǎn)生強(qiáng)干擾。把硬盤盒挪遠(yuǎn)半米之后手機(jī)立即就搜到了。如果你在辦公室或者測(cè)試臺(tái)調(diào)試先把周圍的大塊金屬物體、USB 3.0 設(shè)備、無(wú)線鼠標(biāo)接收器都移開(kāi)能排除一大批環(huán)境干擾。無(wú)線鼠標(biāo)接收器這個(gè)很多人都沒(méi)注意。2.4G 無(wú)線鼠標(biāo)用的頻段和 BLE 部分重疊而且無(wú)線鼠標(biāo)是持續(xù)占信道發(fā)射的對(duì) BLE 廣播的干擾比 Wi-Fi 還明顯。我實(shí)測(cè)過(guò)無(wú)線鼠標(biāo)接收器離 Dongle 10cm 以內(nèi)廣播包丟包率能從 1% 漲到接近 10%手機(jī)掃描成功率明顯下降。調(diào)試時(shí)把這些設(shè)備拿遠(yuǎn)一點(diǎn)能省很多排查時(shí)間。6. 結(jié)合實(shí)際項(xiàng)目如果 Dongle 做自定義 Beacon建議怎么改6.1 廣播數(shù)據(jù)的組織和注意事項(xiàng)如果確認(rèn)板子能正常廣播接下來(lái)就是把它改成自己想要的 Beacon。廣播數(shù)據(jù)最大是 31 字節(jié)包括頭字節(jié)、長(zhǎng)度字節(jié)和數(shù)據(jù)內(nèi)容。BLE_Beacon 例程里的adv_data[]是按 TLV 格式組織的第一個(gè)字節(jié)是長(zhǎng)度Length第二個(gè)字節(jié)是類型Type后面是數(shù)據(jù)Value。例如0x02, 0x01, 0x06表示長(zhǎng)度為 2、類型為 Flags、數(shù)據(jù)為 0x06。自建 Beacon 時(shí)Manufacturer Specific Data 是常用的自定義載體。它由公司 IDCompany ID2 字節(jié)和自定義數(shù)據(jù)組成。普通開(kāi)發(fā)者沒(méi)有購(gòu)買 SIG 的公司 ID可以用 0xFFFF 作為測(cè)試用 ID。要注意的是廣播數(shù)據(jù)總長(zhǎng)不能超過(guò) 31 字節(jié)如果超了協(xié)議棧會(huì)直接返回錯(cuò)誤廣播可能不啟動(dòng)。我把一個(gè) 28 字節(jié)的 UID 放進(jìn)去之后忘了算長(zhǎng)度結(jié)果廣播完全沒(méi)發(fā)出來(lái)排查了半天才發(fā)現(xiàn)是數(shù)組越界。廣播名Device Name也占用廣播數(shù)據(jù)的空間如果名字設(shè)得很長(zhǎng)剩下的空間就少了。我的建議是廣播數(shù)據(jù)里只放必要的信息名字盡量短比如 5 個(gè)字符以內(nèi)把空間留給自己的數(shù)據(jù)。如果確實(shí)需要完整設(shè)備名可以把名字放到 Scan Response Data 里手機(jī)掃描時(shí)也能看到但廣播包本身會(huì)更精簡(jiǎn)。6.2 廣播事件類型和連接配置的選擇Beacon 類應(yīng)用一般用不可連接廣播non-connectable這樣可以減少功耗和協(xié)議開(kāi)銷但缺點(diǎn)是手機(jī)不能連上來(lái)做數(shù)據(jù)交互。如果 Dongle 后面要做數(shù)據(jù)透?jìng)骰蛘?OTA就要改回可連接廣播。STM32WB55 的 HCI 命令里aci_gap_set_discoverable()的 advertising type 參數(shù)不同對(duì)應(yīng)行為也不同。調(diào)試時(shí)先用可連接廣播跑通了再根據(jù)需求調(diào)整減少變量。連接間隔Connection Interval和從機(jī)延遲Slave Latency在連接場(chǎng)景下同樣重要。這兩個(gè)參數(shù)由主機(jī)在連接請(qǐng)求里指定但從機(jī)可以在aci_gap_set_peripheral_configuration()里設(shè)置可接受范圍。如果從機(jī)設(shè)置的范圍和主機(jī)請(qǐng)求的差異太大連接會(huì)失敗或頻繁斷開(kāi)。我遇到過(guò)一個(gè)問(wèn)題Dongle 廣播正常但手機(jī)連接后 3 秒就斷實(shí)時(shí)排查發(fā)現(xiàn)是連接間隔沖突。把從機(jī)可接受范圍放寬后連接就穩(wěn)定了。這類問(wèn)題在 Beacon 階段不會(huì)暴露但后續(xù)要轉(zhuǎn)成連接模式時(shí)一定會(huì)碰到。7. 最后分享一點(diǎn)個(gè)人體會(huì)NUCLEO-WB55 USBDongle 不廣播這個(gè)問(wèn)題說(shuō)大不大說(shuō)小不小但每一次排查下來(lái)我對(duì) STM32WB55 的協(xié)議棧結(jié)構(gòu)、FUS 機(jī)制、低功耗模式都有更深的理解。其實(shí)絕大多數(shù)不廣播問(wèn)題都不是板子壞了而是供電、協(xié)議棧版本、燒錄地址、廣播參數(shù)這幾個(gè)環(huán)節(jié)里某個(gè)細(xì)節(jié)沒(méi)對(duì)上。把這些環(huán)節(jié)逐個(gè)驗(yàn)證一遍花的時(shí)間不會(huì)太長(zhǎng)。我個(gè)人在實(shí)際操作中的體會(huì)是調(diào)試這類雙核無(wú)線芯片最好先建立M4 應(yīng)用日志、BLE 協(xié)議棧狀態(tài)、射頻抓包三個(gè)視角同時(shí)看問(wèn)題的習(xí)慣。M4 的日志能告訴你應(yīng)用代碼跑到哪一步協(xié)議棧狀態(tài)能告訴你 M0 是否正常抓包能告訴你射頻數(shù)據(jù)是否真的發(fā)到空中。三個(gè)視角對(duì)齊后問(wèn)題定位基本就是時(shí)間問(wèn)題。另外一個(gè)不算技巧的技巧每次燒錄前先把要用的固件版本記下來(lái)包括 FUS、BLE Stack、App 三個(gè)版本。很多難啃的問(wèn)題最后發(fā)現(xiàn)只是某個(gè)組件被更新后引入了不兼容。調(diào)試記錄寫清楚能省下大量的重復(fù)排查時(shí)間。希望這篇基于實(shí)際踩坑經(jīng)驗(yàn)整理的內(nèi)容能幫你少走彎路。如果你也遇到類似的廣播問(wèn)題不妨按照上面的順序排查一遍大概率能在半小時(shí)內(nèi)定位到根因。