概念先知道
- 共存(Coexistence):BL616/BL618 是单天线双模芯片,WiFi 和 BLE 共用射频,由底层按时间片调度,两者可以同时工作。
- PS(Power Save,省电模式):WiFi 的空闲省电机制。开启后 WiFi 周期性休眠,射频时间让给 BLE,是“共存场景”的推荐配置。
- Duty cycle(占空比):WiFi 醒着发送/接收的时间比例,例程用
wifi_sta_ps_set 50设为 50%。 - iperf:例程编译了 WiFi iperf 功能(
CONFIG_WIFI_IPERF =y),用于做共存场景的吞吐测试。
例程功能简介
- 本页对应博流官方 SDK 的 wifi_ble 例程(
examples/wifi/coex/wifi_ble),演示 WiFi STA 与 BLE 同时运行的共存场景:WiFi 保持连接的同时,BLE 仍可广播、扫描、连接。 - 例程 = WiFi 管理(连接/事件)+
btble_cli的 BLE 命令(btble_test_port.c提供移植层,本页未展开)。 - 支持芯片:BL602 / BL616 / BL616CL / BL618DG。
- SDK 还为 BL616CL 附带了一组 Python 测试工具(
BL616cl_test/下的ble_test.py、wifi_test.py、coex_test.py),可做自动化共存测试。
操作步骤
在终端进入 SDK 的 wifi_ble 例程目录(前提:环境已按快速开始(Linux)或Windows搭好):
cd examples/wifi/coex/wifi_bleAi-M61 与 Ai-M62 统一填写 bl616,例程默认同时开启 WiFi 与 BLE:
make CHIP=bl616 BOARD=bl616dk按住 BOOT 键不放、短按 EN/RST 进入下载模式后烧录:
make flash CHIP=bl616 COMX=/dev/ttyUSB0串口助手波特率 2000000,复位后等待 WiFi 初始化完成,再输入(把 SSID 和密码换成自己的):
wifi_sta_connect <ssid> <passwd>打开 WiFi 省电并把 WiFi 占空比(duty cycle)设为 50%,给 BLE 留出射频时间:
wifi_sta_ps_on
wifi_sta_ps_set 50在同一个命令行里开启 BLE 可连接广播,用手机 nRF Connect 即可在 WiFi 连接状态下扫到并连接:
ble_start_adv 0 0 0x80 0x80代码执行流程
例程调用的 API 介绍
btble_cli_start()
以任务方式启动 BLE CLI(由 btble_test_port.c 提供移植实现),内部完成 btble_controller_init → hci_driver_init → bt_enable 并注册 ble_* 命令。
参数:无
返回值:无
async_register_event_filter(EV_WIFI, wifi_event_handler, NULL)
注册 WiFi 事件过滤器,收到 CODE_WIFI_ON_* 系列事件后驱动状态机(初始化完成 → 连接成功 → 获取 IP 等)。
参数:
ev:事件类型EV_WIFIcb:事件回调
返回值:无
完整代码
以下为 wifi_ble 例程 main.c 完整源码,与官方示例一致,默认折叠,点击展开(btble_test_port.c 为 BLE 移植层,未在此页展开):
📜 点击展开 wifi_ble/main.c 完整代码
#include "shell.h"
#include <FreeRTOS.h>
#include "task.h"
#include "board.h"
#include "rfparam_adapter.h"
#include "bflb_mtd.h"
#include "easyflash.h"
#include <lwip/tcpip.h>
#include "wifi_mgmr_ext.h"
#ifndef BL602
#include "fhost_api.h"
#include "wifi_mgmr.h"
#endif
#include "mm.h"
#define DBG_TAG "MAIN"
#include "log.h"
#include "async_event.h"
static struct bflb_device_s *uart0;
#define WIFI_STACK_SIZE (1536)
#define TASK_PRIORITY_FW (16)
extern void shell_init_with_task(struct bflb_device_s *shell);
extern void wifi_event_handler(async_input_event_t ev, void *priv);
#ifdef BL602
extern void wifi_task_create(void);
extern int wifi_mgmr_task_start(void);
#endif
#if defined(CONFIG_BLUETOOTH)
extern int btble_cli_start(void);
#endif
void wifi_start_firmware_task(void *param)
{
LOG_I("Starting wifi ...\r\n");
async_register_event_filter(EV_WIFI, wifi_event_handler, NULL);
wifi_task_create();
#ifndef BL602
LOG_I("Starting fhost ...\r\n");
fhost_init();
#endif
vTaskDelete(NULL);
}
void wifi_event_handler(async_input_event_t ev, void *priv)
{
uint32_t code = ev->code;
switch (code) {
case CODE_WIFI_ON_INIT_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE\r\n", __func__);
wifi_mgmr_task_start();
} break;
case CODE_WIFI_ON_MGMR_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE\r\n", __func__);
} break;
case CODE_WIFI_ON_SCAN_DONE: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE\r\n", __func__);
wifi_mgmr_sta_scanlist();
} break;
case CODE_WIFI_ON_CONNECTED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED\r\n", __func__);
void mm_sec_keydump();
mm_sec_keydump();
} break;
#ifdef CODE_WIFI_ON_GOT_IP_ABORT
case CODE_WIFI_ON_GOT_IP_ABORT: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP_ABORT\r\n", __func__);
} break;
#endif
#ifdef CODE_WIFI_ON_GOT_IP_TIMEOUT
case CODE_WIFI_ON_GOT_IP_TIMEOUT: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP_TIMEOUT\r\n", __func__);
} break;
#endif
case CODE_WIFI_ON_GOT_IP: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP\r\n", __func__);
LOG_I("[SYS] Memory left is %d Bytes\r\n", kfree_size(0));
} break;
case CODE_WIFI_ON_DISCONNECT: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STARTED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STOPPED: {
LOG_I("[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED\r\n", __func__);
} break;
case CODE_WIFI_ON_AP_STA_ADD: {
LOG_I("[APP] [EVT] [AP] [ADD] %lld\r\n", xTaskGetTickCount());
} break;
case CODE_WIFI_ON_AP_STA_DEL: {
LOG_I("[APP] [EVT] [AP] [DEL] %lld\r\n", xTaskGetTickCount());
} break;
default: {
LOG_I("[APP] [EVT] Unknown code %u \r\n", code);
}
}
}
int main(void)
{
board_init();
configASSERT((configMAX_PRIORITIES > 4));
uart0 = bflb_device_get_by_name("uart0");
shell_init_with_task(uart0);
bflb_mtd_init();
/* ble stack need easyflash kv */
easyflash_init();
/* Init rf */
if (0 != rfparam_init(0, NULL, 0)) {
printf("PHY RF init failed!\r\n");
return 0;
}
tcpip_init(NULL, NULL);
xTaskCreate(wifi_start_firmware_task, "wifi init", 1024, NULL, 10, NULL);
#if defined(CONFIG_BLUETOOTH)
btble_cli_start();
#endif
vTaskStartScheduler();
while (1) {
}
}FAQ
WiFi 和 BLE 同时开,BLE 连不上或吞吐明显下降
先开启 WiFi 省电并把占空比设为 50%:wifi_sta_ps_on + wifi_sta_ps_set 50;单天线共存时两者必然互相挤占射频时间,实测吞吐会低于纯 WiFi 场景,属正常现象。
怎么测共存时的 WiFi 吞吐
例程编译了 iperf(CONFIG_WIFI_IPERF =y),连接 WiFi 后可用 iperf 命令测 TCP/UDP 吞吐,同时让 BLE 保持广播或连接,观察共存影响。
只想单独测 BLE,不连 WiFi 行吗
可以。不执行 wifi_sta_connect 即可,BLE 命令(ble_start_adv、ble_start_scan 等)不受影响。
BL616CL 的 Python 测试工具怎么用
examples/wifi/coex/wifi_ble/BL616cl_test/ 下的 ble_test.py、wifi_test.py、coex_test.py 配合测试板使用,README 描述了各自的测试流程;BLE 测试用例仅支持 BLE-only 芯片 BL616CL。
遇到问题?
如有其他问题,请到统一的提问与讨论区:Ai-Thinker Discussions

