Skip to content

Concepts First

  • Coexistence: BL616/BL618 are single-antenna combo chips — Wi-Fi and BLE share the radio and are scheduled by the firmware, so both can work at the same time.
  • PS (Power Save): the Wi-Fi idle power-saving mechanism. Once enabled, Wi-Fi sleeps periodically and leaves radio time for BLE — the recommended setup for coexistence scenarios.
  • Duty cycle: the percentage of time Wi-Fi stays awake to send/receive; the example sets it to 50% with wifi_sta_ps_set 50.
  • iperf: the example builds in Wi-Fi iperf (CONFIG_WIFI_IPERF =y) for throughput tests in coexistence scenarios.

Example Overview

  • This page covers the official wifi_ble example (examples/wifi/coex/wifi_ble), demonstrating Wi-Fi STA and BLE running simultaneously: while Wi-Fi keeps its connection, BLE can still advertise, scan and connect.
  • The example = Wi-Fi management (connect/events) + the btble_cli BLE commands (the port layer lives in btble_test_port.c, not expanded on this page).
  • Supported chips: BL602 / BL616 / BL616CL / BL618DG.
  • The SDK also ships a set of Python test tools for BL616CL (BL616cl_test/: ble_test.py, wifi_test.py, coex_test.py) for automated coexistence testing.

Operation Steps

1
Enter the example directory

Enter the SDK’s wifi_ble example directory (prerequisite: set up the environment with Quick Start (Linux) or Windows):

cd examples/wifi/coex/wifi_ble
2
Build the project

Ai-M61 and Ai-M62 both use bl616; the example enables Wi-Fi and BLE together by default:

make CHIP=bl616 BOARD=bl616dk
3
Flash the firmware

Hold BOOT, tap EN/RST to enter download mode, then flash:

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
Connect to Wi-Fi

Open the serial terminal at 2000000 baud, wait for the Wi-Fi stack to initialize, then type (replace SSID and password with your own):

wifi_sta_connect <ssid> <passwd>
5
Enable coexistence power save

Turn on Wi-Fi power save and set the Wi-Fi duty cycle to 50% to leave radio time for BLE:

wifi_sta_ps_on
wifi_sta_ps_set 50
6
Run and verify: start BLE advertising

Start connectable BLE advertising in the same shell — a phone with nRF Connect can scan and connect while Wi-Fi stays connected:

ble_start_adv 0 0 0x80 0x80

Code Execution Flow

APIs Used by the Example

tcpip_init(cb, arg)

Initialize the lwIP TCP/IP stack so the module can obtain an IP once Wi-Fi connects.

Parameters:

  • cb: init-done callback
  • arg: callback argument

Return value: none

wifi_task_create()

Create the Wi-Fi firmware task and load the Wi-Fi stack.

Parameters: none

Return value: none

fhost_init()

Initialize fhost (the Wi-Fi management framework); afterwards the network can be connected through the wifi_mgmr_* APIs.

Parameters: none

Return value: none

btble_cli_start()

Start BLE CLI as a task (port implementation in btble_test_port.c); internally runs btble_controller_inithci_driver_initbt_enable and registers the ble_* commands.

Parameters: none

Return value: none

async_register_event_filter(EV_WIFI, wifi_event_handler, NULL)

Register a Wi-Fi event filter; CODE_WIFI_ON_* events drive the state machine (init done → connected → got IP, etc.).

Parameters:

  • ev: event type EV_WIFI
  • cb: event callback

Return value: none

Complete Code

The full main.c of the wifi_ble example, identical to the official SDK, collapsed by default — click to expand (btble_test_port.c, the BLE port layer, is not expanded on this page):

📜 Click to expand wifi_ble/main.c full code
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

BLE cannot connect or throughput drops when Wi-Fi and BLE are both on

First enable Wi-Fi power save and set the duty cycle to 50%: wifi_sta_ps_on + wifi_sta_ps_set 50. With a single antenna the two radios necessarily share RF time, so throughput below the Wi-Fi-only scenario is expected.

How to measure Wi-Fi throughput during coexistence

The example builds in iperf (CONFIG_WIFI_IPERF =y); after connecting, use the iperf commands to test TCP/UDP throughput while BLE keeps advertising or stays connected to observe the coexistence impact.

Can I test BLE alone without connecting Wi-Fi

Yes. Simply skip wifi_sta_connect; the BLE commands (ble_start_adv, ble_start_scan, etc.) still work.

How to use the BL616CL Python test tools

ble_test.py, wifi_test.py and coex_test.py under examples/wifi/coex/wifi_ble/BL616cl_test/ work with the test board; each README describes its test flow. The BLE test cases only support the BLE-only BL616CL chip.

Have questions?

For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

Released under the MIT License. Build Time 2026-09-11 14:52:23