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_cbprints the local address, registers connection callbacks and initializes the test serviceble_tp_init();- on connect/disconnect, callbacks
ble_connected/ble_disconnectedrun; advertising restarts after disconnect; - advertising uses
BT_LE_ADV_OPT_CONNECTABLE+ device name with manufacturer dataBL616; - 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_enableis enabled; firmware packages are generated withGenerateOAD.py.
Operation Steps
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/peripheralBoth Ai-M61 and Ai-M62 use bl616:
make CHIP=bl616 BOARD=bl616dkHold BOOT, briefly press EN/RST to enter download mode, then flash:
make flash CHIP=bl616 COMX=/dev/ttyUSB0Serial 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(¶m, 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_paramadv_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
#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(¶m, 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(¶m, 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

