Skip to content

Concepts First

  • Peripheral (slave): the device that gets connected to. It advertises periodically; phones (centrals) scan and connect to it.
  • GATT service: connected data is organized as services/characteristics. The example implements a test service (UUID 07af27a5-...) with read, write, notify and indicate characteristics.
  • Advertising: the peripheral advertises to be discovered; the example advertises with the device name and manufacturer data at fast advertising intervals.
  • Notify / Indicate: ways for the peripheral to push data — Notify needs no acknowledgement; Indicate does.

Example Overview

This page covers the peripheral example in the official Bouffalo SDK (examples/btble/peripheral):

  • initializes the BLE controller and host stack (btble_controller_init + hci_driver_init + bt_enable);
  • bt_enable_cb prints the local address, registers connection callbacks and initializes the test service ble_tp_init();
  • on connect/disconnect, callbacks ble_connected / ble_disconnected run; advertising restarts after disconnect;
  • advertising uses BT_LE_ADV_OPT_CONNECTABLE + device name with manufacturer data BL616;
  • the test service has read/write/notify/indicate characteristics (ble_tp_svc.c), interoperable with the BLE Master example or phone apps;
  • optional OAD (BLE OTA): with CONFIG_BT_OAD_SERVER, oad_service_enable is enabled; firmware packages are generated with GenerateOAD.py.

Operation Steps

1
Enter the Example Directory

Open a terminal and enter the SDK BLE peripheral (slave) example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):

cd examples/btble/peripheral
2
Build the Project

Both Ai-M61 and Ai-M62 use bl616:

make CHIP=bl616 BOARD=bl616dk
3
Flash the Firmware

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

make flash CHIP=bl616 COMX=/dev/ttyUSB0
4
Run and Verify

Serial tool at 2000000 baud; the log prints BD_ADDR:(MSB)...(LSB). Open nRF Connect / LightBlue on the phone, scan, connect to the device, and you can see the test service 07af27a5-9c22-11ea-9afe-02fcdc4e7412 with its read/write/notify characteristics.

Code Execution Flow

The complete peripheral flow from boot to connection:

APIs Used by the Example

btble_controller_init(configMAX_PRIORITIES - 1)

Initializes the BLE controller (radio and link layer).

Parameters:

  • priority: controller task priority

Return: none

bt_enable(bt_enable_cb)

Starts the BLE host stack; calls back bt_enable_cb when done.

Parameters:

  • cb: enable-complete callback

Return: none

bt_le_adv_start(&param, adv_data, adv_len, adv_rsp, rsp_len)

Starts advertising. The example uses connectable advertising (BT_LE_ADV_OPT_CONNECTABLE) with the device name.

Parameters:

  • param: struct bt_le_adv_param
  • adv_data / adv_rsp: advertising data and scan-response data

Return: 0 on success; negative error code

ble_tp_init()

(example-specific, ble_tp_svc.c) registers the test service: read characteristic 07af27a6-..., write 07af27a7-..., indicate 07af27a8-..., notify, etc.

Parameters: none

Return: none

bt_conn_cb_register(&ble_conn_callbacks)

Registers connect/disconnect callbacks (connected / disconnected).

Parameters:

  • callbacks: struct bt_conn_cb

Return: none

Complete Code

The full main.c source, identical to the official example (examples/btble/peripheral; test service implementation in ble_tp_svc.c in the same directory). Collapsed by default; click to expand:

📜 Click to expand peripheral/main.c full code
c
#include "shell.h"
#include <FreeRTOS.h>
#include "task.h"
#include "board.h"

#include "bluetooth.h"
#include "conn.h"
#include "conn_internal.h"
#if defined(BL702) || defined(BL602)
#include "ble_lib_api.h"
#elif defined(BL616)
#include "btble_lib_api.h"
#include "bl616_glb.h"
#include "rfparam_adapter.h"
#elif defined(BL618DG)
#include "btble_lib_api.h"
#include "bl618dg_glb.h"
#include "rfparam_adapter.h"
#elif defined(BL616CL)
#include "btble_lib_api.h"
#include "bl616cl_glb.h"
#include "rfparam_adapter.h"
#endif

#include "ble_tp_svc.h"
#include "hci_driver.h"
#include "hci_core.h"

#include "bflb_mtd.h"
#include "easyflash.h"

#if defined(CONFIG_BT_OAD_SERVER)
#include "oad_main.h"
#include "oad_service.h"
#endif

static struct bflb_device_s *uart0;

extern void shell_init_with_task(struct bflb_device_s *shell);

static void ble_connected(struct bt_conn *conn, u8_t err)
{
    if(err || conn->type != BT_CONN_TYPE_LE)
    {
        return;
    }
    printf("%s",__func__);
}

static void ble_disconnected(struct bt_conn *conn, u8_t reason)
{ 
    int ret;

    if(conn->type != BT_CONN_TYPE_LE)
    {
        return;
    }

    printf("%s",__func__);

    // enable adv
    ret = set_adv_enable(true);
    if(ret) {
        printf("Restart adv fail. \r\n");
    }
}

static struct bt_conn_cb ble_conn_callbacks = {
	.connected	=   ble_connected,
	.disconnected	=   ble_disconnected,
};

static void ble_start_adv(void)
{
    struct bt_le_adv_param param;
    int err = -1;
    struct bt_data adv_data[1] = {
        BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR | BT_LE_AD_GENERAL)
    };
    struct bt_data adv_rsp[1] = {
        BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA, "BL616")
    };

    memset(&param, 0, sizeof(param));
    // Set advertise interval
    param.interval_min = BT_GAP_ADV_FAST_INT_MIN_2;
    param.interval_max = BT_GAP_ADV_FAST_INT_MAX_2;
    /*Get adv type, 0:adv_ind,  1:adv_scan_ind, 2:adv_nonconn_ind 3: adv_direct_ind*/
    param.options = (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME); 

    err = bt_le_adv_start(&param, adv_data, ARRAY_SIZE(adv_data), adv_rsp, ARRAY_SIZE(adv_rsp));
    if(err){
        printf("Failed to start advertising (err %d) \r\n", err);
    }
    printf("Start advertising success.\r\n");
}
bool ble_check_oad(u32_t cur_file_ver, u32_t new_file_ver)
{
    return true;
}
void bt_enable_cb(int err)
{
    if (!err) {
        bt_addr_le_t bt_addr;
        bt_get_local_public_address(&bt_addr);
        printf("BD_ADDR:(MSB)%02x:%02x:%02x:%02x:%02x:%02x(LSB) \r\n",
            bt_addr.a.val[5], bt_addr.a.val[4], bt_addr.a.val[3], bt_addr.a.val[2], bt_addr.a.val[1], bt_addr.a.val[0]);

        bt_conn_cb_register(&ble_conn_callbacks);
        ble_tp_init();
#if defined(CONFIG_BT_OAD_SERVER)
        oad_service_enable(ble_check_oad);
        // start advertising
        ble_start_adv();
#endif
    }
}

static TaskHandle_t app_start_handle;

static void app_start_task(void *pvParameters)
{
    // Initialize BLE controller
    #if defined(BL702) || defined(BL602)
    ble_controller_init(configMAX_PRIORITIES - 1);
    #else
    btble_controller_init(configMAX_PRIORITIES - 1);
    #endif
    // Initialize BLE Host stack
    hci_driver_init();
    bt_enable(bt_enable_cb);

    vTaskDelete(NULL);
}

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;
    }

    #if defined(BL618DG)
    #if defined(CONFIG_BTBLE_USE_STANDALONE_PATH)
    printf("cmd_set_btble_standalone\r\n");
    extern void cmd_set_btble_standalone(int argc, char **argv);
    cmd_set_btble_standalone(0, 0);
    #else
    printf("cmd_set_btble_combo\r\n");
    extern void cmd_set_btble_combo(int argc, char **argv);
    cmd_set_btble_combo(0, 0);
    #endif
    #endif

    xTaskCreate(app_start_task, (char *)"app_start", 1024, NULL, configMAX_PRIORITIES - 2, &app_start_handle);

    vTaskStartScheduler();

    while (1) {
    }
}

FAQ

The phone connects then disconnects

Confirm the two devices are close enough (BLE range is usually a few to a dozen meters); check that you are not connecting multiple peripherals at once; some phone OSes limit concurrent BLE connections — close other BLE connections first.

Advertising does not start in bt_enable_cb

The example calls ble_start_adv() only when built with CONFIG_BT_OAD_SERVER; without it, advertising is controlled by the service logic in ble_tp_svc.c, or you can call ble_start_adv() yourself in bt_enable_cb.

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