尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

BlueNRG-LP扩展广播扫描不到?PHY配置与排查指南

BlueNRG-LP扩展广播扫描不到?PHY配置与排查指南 1. 问题现象与整体排查思路1.1 先还原一下现场前阵子我在一个用BlueNRG-LP SoC做低功耗长距离信标项目的过程中遇到了一个很典型的怪问题广播端已经按照BLE 5.0的扩展广播模式把数据发出去了通道、功率、广播间隔看起来都正常但拿着手机、或者用另一块BlueNRG-LP板子做扫描端却怎么都扫描不到这个扩展广播包。手机上的扫描工具偶尔能看到设备名但广播数据要么为空要么完全不在设备列表里出现。更诡异的是如果我把广播模式改回传统的ADV_IND手机立刻就能扫到设备列表、广播数据、RSSI全都正常。这个问题在研究BLE扩展广播的团队里一点都不少见尤其是从传统广播切到扩展广播的第一版调试阶段。LAT1214这篇应用笔记记录的就是这个场景的完整排查过程从原理层到寄存器配置再到实际日志我把所有可能踩坑的点都过了一遍。如果你也在用BlueNRG-LP、BlueNRG-LPS这些ST的BLE SoC做扩展广播并且遇到了“自己发的广播自己扫不到”的怪事那这篇笔记应该能帮你省下不少时间。先说一下这套方案的基本构成广播端用的是基于BlueNRG-LP SoC的定制板SDK基于ST官方BlueNRG-LP开发包BLE协议栈跑在SoC内部没有外部MCU属于典型的单芯片方案。扫描端一开始用的是同一款开发板后面为了快速排除问题又加了手机App和射频抓包工具做交叉验证。正是在这个交叉验证的过程中我发现问题并不是出在RF链路或者天线匹配上而是出在“扩展广播的链路层行为”和“扫描端配置”之间的匹配上。1.2 扩展广播不是“更大号的传统广播”很多人第一次接触BLE 5.0扩展广播时会觉得它就是把原来31字节的广播包扩展成更大的数据包而已这是一个容易误导人的理解。扩展广播在协议栈里的处理方式跟传统广播完全不是一回事。传统广播由广播端在37/38/39三个主广播信道上反复发送ADV_IND、ADV_NONCONN_IND等PDU扫描器只需要在这三个固定信道上被动监听就能拿到广播数据。整个过程不会跳到数据信道主信道广播包里的载荷就是最终数据。扩展广播则分成了两段广播端先在主信道上发一个ADV_EXT_IND这个主信道包只携带一个指针告诉扫描器“真正的广播载荷在某个数据信道上PHY是什么通道编号是多少偏移量是多少”。扫描器收到这个指示包以后必须主动跳到对应的数据信道去接收AUX_ADV_IND再从这个辅助包里解析出真正的广播数据。如果广播数据很长后面甚至还会跟着AUX_CHAIN_IND这样的链式包扫描器必须一包一包跟下去。这个机制带来的直接结果就是一个只实现了BLE 4.x传统扫描逻辑的扫描器即使它能在主信道上收到ADV_EXT_IND也会因为不理解这个PDU的含义而把它当作未知广播类型直接忽略更谈不上跳信道去跟随辅助包了。BlueNRG-LP本身是支持BLE 5.2的SoC硬件上完全具备处理扩展广播的能力但如果协议栈配置、扫描参数、事件回调这些环节有一个没打开表现出来就是你看到的“扫描不到扩展广播包”。1.3 问题定位要先切两半遇到这种问题最忌讳一上来就去调天线、换晶体、改匹配网络。射频问题当然存在但扩展广播扫不到绝大多数情况是协议栈配置层面的问题。我的习惯是把整个链路先切成两段广播端一段扫描端一段然后用第三方工具做裁判。具体做法很简单先拿一台支持BLE 5.0扩展广播的手机用nRF Connect或者ST BLE Toolbox去扫广播端。如果手机能看到设备并且设备类型、广播数据都能正常解析出来说明广播端发送扩展广播这条链路是通的问题大概率在你自己写的扫描端或者扫描端的协议栈配置上。反过来如果手机也扫不到但传统广播模式能扫到那问题更可能出在广播端的扩展广播参数配置上比如辅助PHY、广播信道选择、SID或者发送端地址类型有问题。这个“切两半”的步骤看起来简单但在实际项目里非常管用。我这次就是因为先用手机确认了广播端没问题才把排查重心完全放到了扫描端的BlueNRG-LP SoC配置上节省了大量时间。下一章我会把扩展广播收发过程中最容易出问题的几个核心细节一一拆开。2. 为什么BlueNRG-LP收不到扩展广播核心细节拆解2.1 PHY不匹配是头号嫌疑扩展广播引入了一个关键参数就是辅助包的物理层PHY。传统广播只能在1M PHY上发送扫描器不用操心PHY匹配的问题。但扩展广播允许广播端把真正的广播载荷放在2M PHY或者Coded PHY上发送尤其是长距离场景下绝大多数人会选择Coded PHY因为Coded PHY采用125kbps或500kbps的编码速率接收灵敏度可以提升很多传得更远。问题恰恰就出在这里。扫描端在配置扩展扫描时需要显式告诉协议栈自己要监听哪些PHY上的辅助包。如果你的广播端把辅助包放在了Coded PHY上但扫描端的扩展扫描配置里只启用了1M PHY那扫描器即使正确收到了主信道上的ADV_EXT_IND也会因为“对端广播使用的辅助PHY不在本机扫描PHY列表里”而直接放弃跟随扫描结果自然为空。我在BlueNRG-LP上遇到过好几次这种情况原因是SDK初始化扫描参数时默认值是只监听1M PHY。这个默认值对传统广播完全够用所以很多人根本不会留意到还有PHY选择这个参数。但切换到扩展广播后这个“隐身”的默认参数就会变成第一个拦路虎。排查建议很简单先确认广播端实际用的辅助PHY是什么再把扫描端的PHY设置成相同的模式。如果想兼容所有情况可以直接把扫描PHY配成“1M和Coded都监听”代价只是扫描功耗高一点对大部分应用完全可接受。2.2 扫描窗口和间隔决定你能不能“接住”广播事件第二个容易被忽视的细节是扫描窗口与扫描间隔的配合。传统广播在主信道上发送扫描端只需要在主信道监听并不需要跳信道所以即使扫描窗口短一些也相对容易抓到广播包。扩展广播则不一样扫描端收到主信道上的指示包之后要马上跳到数据信道去接收辅助包这个跃迁过程需要时间。如果扫描端配置的扫描窗口太小或者扫描间隔太短比如扫描间隔是100ms扫描窗口只有10ms那扫描器只有10%的时间在监听。扩展广播的主信道指示包出现频率本来就不像传统广播那么高再加上数据信道辅助包的发送窗口更短就会出现广播端明明在正常发送扫描端却总也扫不到的情况。尤其是你开了Coded PHY之后辅助包的发送时间更长但数据信道上的发送机会还是受跳频图样和广播间隔共同影响侦听窗口不足依然会漏。我在实际调试时一开始用的是SDK默认的扫描参数扫描间隔大约20ms扫描窗口10ms本地测试时偶尔能扫到非常不稳定。后来把扫描窗口加大到接近扫描间隔比如间隔50ms、窗口40ms再配合试一下效果就稳定了很多。当然实际参数要结合产品的功耗指标来权衡但如果你只是想确认扩展广播链路通不通不妨先把扫描窗口拉大排除这个变量。2.3 过滤策略和白名单把广播包悄悄丢掉了另一个隐藏很深的坑是过滤策略。BLE扫描器在配置扫描时通常有一个地址过滤选项可以选择是否过滤重复设备也可以选择是否只接收白名单里的广播端。传统广播模式下这些过滤策略的效果比较直观因为主信道广播包本身会携带完整的广播数据和地址信息。但在扩展广播模式下主信道指示包里通常只有地址的最小信息完整的设备地址和广播数据要到辅助包里才能解析出来。如果你的扫描端配置了比较激进的过滤重复地址策略或者启用了白名单但广播端使用的是随机可解析地址并且地址类型没有和扫描端匹配好那扫描器可能收到ADV_EXT_IND之后在地址过滤这一关就把这个广播源丢弃了根本不会跳到辅助信道去取数据。这类问题的典型特征是如果广播端改用传统广播扫描端就能扫到一旦切回扩展广播设备就从列表里消失了。因为传统广播在协议栈里的过滤路径和扩展广播不同两种模式下地址处理逻辑并不完全一致。排查时可以先临时把过滤策略调到最宽松比如不过滤重复设备、不使用白名单再重新扫描看看。如果这次能扫到扩展广播那说明过滤策略就是元凶接下来再去精调地址类型和过滤规则。2.4 传统扫描API和扩展扫描API是两个世界这一点可能是BlueNRG-LP使用中最容易踩的坑。很多从ST旧型号BlueNRG-1、BlueNRG-2迁移到BlueNRG-LP的工程师习惯了用老的扫描初始化流程直接调用传统的扫描配置接口去启动扫描。传统扫描API在协议栈内部只会去处理传统广播PDU对ADV_EXT_IND这类扩展广播PDU基本不产生扫描报告或者说不会走扩展扫描报告事件上报给应用层。BlueNRG-LP的SDK里扩展扫描需要单独走带ext前缀的配置接口比如aci_gap_set_ext_scan_configuration这类命令使能扩展扫描后应用层收到的扫描报告事件也不再是传统的GAP_EVT_ADV_REPORT而是扩展扫描报告事件事件里会额外携带PHY、辅助包类型、SID这些扩展广播特有的字段。如果你的应用层只注册了传统广播报告事件没有去注册扩展扫描报告事件即使底层扫描器已经收到了扩展广播包应用层也不会知道。这一点在调试时特别有迷惑性因为从日志看扫描端一直显示“没有收到任何设备”可实际上底层早就收到了数据。我当时就是在应用层回调里只处理了旧的事件类型结果白白浪费了半天时间。后来把扩展扫描报告事件也注册上日志立刻滚滚而来。2.5 地址类型与重复过滤的连带影响最后再补充一个容易连带出错的小点广播端的“Own Address Type”。扩展广播允许广播端使用公共地址、随机静态地址、随机可解析地址等多种地址类型。扫描端在收到主信道指示包后会根据指示包里的地址信息去做重复设备过滤和设备识别。如果你的广播端配置的地址类型和扫描端预期的不一致比如广播端发送时用的是随机可解析地址而扫描端的过滤策略假设所有设备都用公共地址那在某些协议栈实现里扫描器可能无法正确聚合同一台设备的多次广播事件导致扫描报告一直产生不了。这个问题在传统广播下也可能出现但扩展广播的多包机制会把它的影响放大因为主信道指示包和辅助包里的地址字段可能不是同一个形式处理起来更复杂。解决思路是在调试初期把广播端地址固定为公共地址或随机静态地址等链路通了以后再换成可解析地址这样能最大程度降低变量数。3. 实操过程完整可复现的扩展广播扫描配置3.1 环境准备与硬件连接先说我在这次排障中使用的硬件和软件环境方便你对照复现。广播端和扫描端我都用的是ST的NUCLEO-BLUENRG-LP开发板板载BlueNRG-LP SoC。SDK采用的是ST官方BlueNRG-LP开发包版本更新到了支持BLE 5.2扩展广播的较新版本编程环境是STM32CubeIDE。调试工具方面我准备了一台支持BLE 5的Android手机安装了nRF Connect和ST BLE Toolbox另外还准备了一个支持Broadcast模式抓包的BLE Sniffer用来确认空中的PDU报文。这里特别提醒一下SDK版本真的会影响API名称和默认行为。我第一次按老版本的习惯去查接口发现很多参数对不上后来直接打开SDK的头文件去搜ext_advertising、ext_scan相关定义才找到正确的接口。所以下面的示例代码主要是演示关键的配置流程和参数意图具体函数签名请以你当前SDK版本的头文件为准。3.2 广播端把扩展广播参数配到“能发出去”的状态广播端配置的核心是把广播类型设置为扩展广播并指定辅助包的PHY。以我的项目为例我需要把广播数据放在Coded PHY上发送以获取更远的覆盖距离。在SDK的驱动层扩展广播通常是通过一个配置结构体或者一组带ext前缀的API来操作的。下面是一段示意性的伪代码重点在于让你看到关键参数的位置// 示意代码具体API名称和参数以当前SDK头文件为准 uint8_t adv_data[] { 0x02, 0x01, 0x06, // Flags: LE General Discoverable 0x05, 0x16, 0x00, 0x18, 0x00, 0x01, // Service UUID major/minor }; // 1. 设置扩展广播数据Handle 0 表示第0号广播集 aci_gap_set_ext_advertising_set_data( 0, // Advertising Handle ADV_DATA_OP_COMPLETE, // Operation: 完整替换数据 0, // Fragment preference sizeof(adv_data), adv_data ); // 2. 设置扩展广播参数 hci_le_set_extended_advertising_parameters( 0, // Advertising Handle 0x08, 0x00, // Primary interval: 5ms * 0.625ms ?? 按需调整 0x08, 0x00, // Secondary interval 0x00, // ADV Type: Non-Connectable Non-Scannable 0x01, // Own Address Type: Random Static 0x00, // Peer Address Type NULL, // Peer Address 0x07, // Channel Map: 37/38/39 0x01, // Filter Policy: 接受所有扫描请求 0x00, // TX Power: 默认 0x01, // Primary PHY: LE_1M 0x04, // Secondary PHY: LE_CODED 关键参数 0x00, // SID: 广播集ID 0x00, // Scan Request Notification 0x00 // 不跳过后续连接事件调度 ); // 3. 使能扩展广播 aci_gap_set_ext_advertising_enable( 0x01, // Enable 1, // Number of Advertising Sets 0, // Handle列表 NULL // 每个set的持续时间 );这里最容易忽略的是Secondary PHY这一项。如果你把辅助包放在了Coded PHY上但扫描端没有监听Coded PHY那就会出现“广播端好像一直在发扫描端始终扫不到”的现象。3.3 扫描端关键配置是PHY和扫描报告事件扫描端的配置是这次排障的重点也是大多数问题的根源。在BlueNRG-LP上扩展扫描需要单独配置并且要把PHY类型、扫描类型和扫描报告事件全部打开。示意代码如下// 示意代码具体API命名以SDK为准 tBleStatus ret; // 设置扩展扫描配置 ret aci_gap_set_ext_scan_configuration( SCAN_ENABLE, // 使能扫描 DUPLICATE_FILTER_DISABLE, // 先关闭重复过滤便于调试 NO_FILTER_POLICY, // 不过滤等通了再精调 PHY_1M_AND_CODED, // 关键参数同时监听1M和Coded PHY SCAN_PASSIVE // 先使用被动扫描减少变量 ); if (ret ! BLE_STATUS_SUCCESS) { // 打印错误码多半是参数越界或者状态机不对 } // 设置扫描间隔和扫描窗口范围以SDK宏定义为准 aci_gap_set_ext_scan_parameters( 0x00A0, // Scan Interval: 约100ms先保证能抓到包 0x0060, // Scan Window: 约60ms尽量拉长 ); // 使能扩展扫描 aci_gap_set_ext_scan_enable( 0x01, // Enable 0x00 // Period: 0表示持续扫描 );配置完扫描以后应用层要确保注册了扩展扫描报告事件。在我用的SDK版本中这个事件枚举通常是GAP_EVT_EXT_SCAN_REPORT或GAP_EVT_EXT_ADV_REPORT。在事件回调里可以用下面的思路打印最关键的信息case GAP_EVT_EXT_SCAN_REPORT: // 解析广播地址、RSSI、PHY、广播数据 // 注意检查 adv_type如果是AUX_ADV_IND说明收到了扩展广播 break;我在调试时会在事件回调里同时打印PHY和adv_type。如果事件能触发但PHY显示是1M而广播端实际在Coded PHY上发那说明扫描端的PHY配置可能没有生效如果事件完全不触发那就回去查扫描使能和事件注册。3.4 用手机和双板对测做交叉验证配置改完以后我的验证顺序是这样的先用手机nRF Connect扫描广播端确认空中确实有扩展广播报文再用ST BLE Toolbox重新扫一遍因为不同App对扩展广播的解析方式略有差异多一个工具多一重验证最后用第二块BlueNRG-LP开发板作为扫描端跑上面那套扩展扫描配置看串口日志是否有扩展扫描报告。这套验证顺序的好处是手机能扫到说明广播端没问题手机扫不到说明广播端本身就有问题这时候再回头检查广播参数。双板对测时如果手机能扫到但BlueNRG-LP扫不到几乎可以直接判定是扫描端配置的问题重点去查PHY、过滤策略、事件注册三件事。实测下来我最后就是靠“手机能扫到、BlueNRG-LP扫不到”这个结果锁定了问题扫描端PHY配置只开了1M广播端的辅助包却在Coded PHY上发送。把扫描PHY改成1M和Coded都监听之后扩展扫描报告事件立刻就出来了广播数据也能完整解析。4. 常见问题与排查技巧实录4.1 典型原因速查表我把这次排查过程中遇到的所有可能原因整理成了一张速查表后面再遇到类似问题可以直接对照着查。现象最可能原因快速验证方法手机能扫到自己的扫描端扫不到扫描端PHY未监听扩展广播辅助PHY把扫描PHY改为1M和Coded都监听自己扫描端偶尔能扫到持续丢包扫描窗口太小或扫描间隔太短拉大扫描窗口缩短扫描间隔传统广播能扫到扩展广播扫不到应用层没注册扩展扫描报告事件检查事件回调里的扩展扫描分支扫描日志显示完全无事件扫描端使用了传统扫描API没使能扩展扫描改用带ext前缀的扫描配置接口扫描报告事件有但设备信息不对地址过滤策略或白名单过滤先关闭重复过滤和白名单手机和自己都扫不到扩展广播广播端辅助PHY或广播参数本身配置错误用Sniffer抓包确认空中PDU切回传统广播就正常广播端和扫描端的扩展广播理解不一致检查SDK版本和API参数定义4.2 五步定位法如果你现在正在被类似问题困扰我建议直接照这个五步流程走一遍每一步都有明确的目的不会白费功夫。第一步确认广播端到底有没有把扩展广播发出去。这一步不要依赖自己的扫描代码直接用一台支持BLE 5的手机去扫。手机扫不到直接去查广播端配置。手机能扫到进入第二步。第二步确认扫描端的协议栈是否使能了扩展扫描。检查初始化代码里是不是用了带ext前缀的扫描配置接口有没有调用使能扩展扫描的命令。这步不过关后面全是白搭。第三步检查扫描PHY是否覆盖广播端辅助包所在的PHY。这是扩展广播和传统广播最大的区别点也是最容易漏掉的参数。干脆配置成同时监听1M和Coded一劳永逸。第四步检查应用层事件处理。确认扩展扫描报告事件已经被注册并且在回调里有对应的case分支。如果SDK版本升级过事件名可能变了顺手查一下头文件里的枚举定义。第五步把过滤策略降到最低。关掉重复过滤、关掉白名单、先不用可解析随机地址让扫描器以最宽松的模式工作。如果这时候能扫到了再逐步把过滤策略加回去找到具体的触发条件。4.3 几个值得记住的避坑细节这次调试里还有几个细节我觉得比那一步配置本身更值得写下来因为它们在常规文档里很少提到。第一个细节是SDK示例工程里的宏开关。很多人在官方例程的基础上改代码但例程里可能会有条件编译宏比如BLE_CFG_EXT_ADV、SUPPORT_CODED_PHY之类的开关默认可能没有打开。你光在应用层调API底层协议栈却没编进扩展广播支持表现出来就是接口返回成功但空中根本看不到扩展广播包。遇到这种问题先去看看SDK的ble_config或platform配置头文件把相关宏打开再试。第二个细节是NVM或Flash里残留的旧配置。BlueNRG-LP的协议栈支持把一些GAP配置存到非易失存储区如果你的板子之前跑过其他广播配置旧配置可能还残留在NVM里新代码启动时会和旧配置打架。我遇到过一种情况代码里明明设置了扩展广播但设备上电后还是按传统广播在跑就是因为NVM里保留了旧的非扩展广播参数。调试时可以用SDK工具把NVM彻底擦除让协议栈回到出厂状态再测。第三个细节是不要忽略射频前端。虽然大部分扫不到扩展广播的问题都在协议栈层但如果你把广播间隔缩得很短、TX Power开得很大同时板子的射频匹配网络又没调好那空中信号可能真的很差手机离得近一点能扫到离远一点就丢了。扩展广播的Coded PHY虽然灵敏度高但射频链路不干净的话信号还是会被噪声吃掉。如果协议栈配置都检查过了还没结果就找个信号好的环境、降低天线周围干扰再测一次。5. 调试工具与延伸建议5.1 抓包工具看到空中报文才算数只靠芯片日志和App扫描结果有时候还是不够直观。因为广播端发没发、发的是什么PHY、主信道指示包和辅助包是不是成对出现这些信息用软件日志很难完全还原。在这种情况下一个能解析BLE 5扩展广播的Sniffer会非常有帮助。我在这次排障中用的是基于nRF52840 Dongle的BLE Sniffer方案搭配Wireshark解析。抓包结果里能直接看到广播端在37/38/39信道上发送的ADV_EXT_IND以及扫描器跟着跳转到数据信道接收AUX_ADV_IND的过程。如果Sniffer只看到ADV_EXT_IND而没有后续的辅助包说明广播端可能在辅助包发送上出了问题如果Sniffer能看到广播端完整的扩展广播序列但你的扫描端没有上报任何事件那问题就锁定在扫描端协议栈配置上。还有一个免费的验证技巧是使用Android的HCI日志抓取功能在开发者选项里开启蓝牙HCI日志然后用手机去扫描扩展广播设备。抓下来的btsnoop日志能用Wireshark打开能清晰地看到手机扫描器的收发行为。如果你的手机能扫到但那块BlueNRG-LP扫不到对比一下两头对ADV_EXT_IND的处理差异往往能找准协议栈的问题点。5.2 BlueNRG-LP调试日志怎么看ST的BlueNRG-LP开发包在SDK里提供了比较完整的日志和事件跟踪能力开发板上板载的ST-Link会把UART日志透传到PC端配合ST的BlueNRG GUI工具可以直接看到协议栈上报的事件和错误码。我在调试时会在扫描端代码里打开GAP层的日志然后把扩展扫描报告事件里的关键字段都打印出来包括广播端地址、RSSI、主PHY、辅助PHY、广播类型。这个日志的价值在于一旦扩展扫描事件能正常触发你就知道协议栈已经收到扩展广播了剩下的只是解析和过滤的问题。如果事件一直不触发那就顺着协议栈往底层查看看是不是扫描使能之前有报错。错误码的排查也很重要SDK的头文件里有返回值定义大部分配置错误都能在调用API的返回值上发现比如参数越界、命令时序不对等等。5.3 从官方例程出发少走弯路最后给一个对新手比较友好的建议不要从零开始写扩展广播和扩展扫描的代码先跑通ST官方例程里与扩展广播或者长距离Demo相关的示例然后用增量法把业务逻辑加进去。ST的BlueNRG-LP开发包里一般会包含Beacon、长距离广播、方向定位等示例工程。这些例程已经把所有协议栈相关的参数配置好了广播和扫描都能互通。先在这个环境里跑通收发链路再对照自己的代码去改能把“协议栈配置问题”和“业务代码问题”彻底分开。我这次就是先拿官方长距离例程在开发板上跑了一遍确认硬件链路没问题才一步步对比出自己的配置里到底哪里和官方不一致。如果你的SDK版本目录里没有直接相关的例程也可以通过ST的Github仓库或者其他开发者论坛找找看很多社区贡献者会分享基于BlueNRG-LP的扩展广播收发示例。把别人的代码跑起来再对照自己的工程看差异是最快的排障方式。从我这次实测经验来看BlueNRG-LP SoC的扩展广播本身是稳定可靠的扫不到扩展广播包的原因几乎都集中在PHY设置、扫描API选择、事件注册和过滤策略这几个地方。调试这类问题最关键的一步就是先用手机或者抓包工具确认“空中确实有包”然后立刻把注意力放到扫描端配置上不要被其他无关因素干扰。最后再分享一个小技巧调试时把重复过滤关掉并且打印出每次扫描报告的PHY和广播类型你很快就能看出来广播包到底是在链路层被漏掉了还是在应用层被过滤掉了。
返回列表