Concepts First
- iBeacon: Apple's Bluetooth advertising format — UUID (16 bytes) + Major (2) + Minor (2) + TX power packed into the manufacturer-specific data field (Company ID
0x004C). - UUID / Major / Minor: the UUID identifies a beacon family (e.g. a retail chain's stores), Major/Minor subdivide it (which store, which shelf).
- Advertising lifecycle: the example demonstrates
controller_init → adv_init → set_parameter → set_data → adv_start → adv_stop → adv_deinit → controller_deinitand checks heap for leaks. - Non-connectable advertising (ADV_NONCONN_IND): an iBeacon only "announces"; scanners receive the advertisement but cannot connect.
Example Overview
This page covers the adv example in the official Bouffalo SDK (examples/btble/adv, README marked Chip support: BL616CL only):
- uses the
CONFIG_BLE_BEACON_ONLYdirect controller API (bypasses HCI transport) with very low memory usage; build_ibeacon_data()assembles the iBeacon payload: Flags + manufacturer data (0x004C/0x0215/ UUID / Major / Minor / TX Power);- each cycle advertises 3 seconds (100–150ms interval), 3 cycles in total, printing heap usage per step to prove no cyclic leaks;
- parameters (UUID, Major, Minor, TX Power) are macros at the top of
main.c— edit them freely. - Related reference: connectable peripheral scenarios in BLE Slave; on regular BL616/BL618,
ble_start_adv()inexamples/btble/peripheralshows ordinary advertising.
Operation Steps
⚠️ The example on this page (examples/btble/adv) only supports BL616CL (BLE-only chip) and requires CONFIG_BLE_BEACON_ONLY=y; it does not run on the regular Ai-M61 (BL618) / Ai-M62 (BL616). This limitation is stated in the SDK README — operate on the matching board first.
Open a terminal and enter the SDK beacon example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/btble/advBuild with bl616cl:
make CHIP=bl616cl BOARD=bl616cldkHold BOOT, briefly press EN/RST to enter download mode, then flash:
make flash CHIP=bl616cl COMX=/dev/ttyUSB0Serial tool at 2000000 baud. The program automatically runs 3 “init→advertise→stop→deinit” lifecycles, advertising for 3 seconds each (iBeacon format, non-connectable). Scan with nRF Connect / LightBlue / Beacon Scope on a phone to see manufacturer data 0x004C (Apple) iBeacon advertisements.
Code Execution Flow
The complete single-cycle beacon flow:
APIs Used by the Example
btble_controller_init / btble_controller_deinit(priority) / ()
Initializes/deinitializes the BLE controller (in BEACON_ONLY mode heap usage is tiny — about 244 bytes to init, fully recovered on deinit).
Parameters:
priority: controller task priority (configMAX_PRIORITIES - 1)
Return: 0 on success; negative error code
btble_adv_init / btble_adv_deinit()
Initializes/deinitializes the advertising module (HCI Reset + event mask + queue allocation).
Parameters: none
Return: 0 on success; negative error code
btble_adv_set_parameter(¶ms)
Sets advertising parameters: interval (100–150ms), type (BTBLE_ADV_TYPE_NON_CONNECTABLE_UNDIRECTED), channels (all), etc.
Parameters:
params:struct btble_adv_params
Return: 0 on success; negative error code
btble_adv_set_data / btble_adv_start / btble_adv_stop(data, len) / () / ()
Sets the advertising data (the iBeacon packet), starts and stops advertising.
Parameters:
data/len: advertising data and length
Return: 0 on success; negative error code
Complete Code
The full main.c source, identical to the official example (examples/btble/adv). Collapsed by default; click to expand:
📜 Click to expand adv/main.c full code
/**
* @file main.c
* @brief BLE Beacon Demo - full lifecycle cycle test
*
* Runs 3 cycles of:
* btble_controller_init -> btble_adv_init -> btble_adv_set_parameter ->
* btble_adv_set_data -> btble_adv_start -> (wait) ->
* btble_adv_stop -> btble_adv_deinit -> btble_controller_deinit
*
* Requires CONFIG_BLE_BEACON_ONLY=y and BL616CL chip.
*/
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include "task.h"
#include "board.h"
#include "mm.h"
#include "btble_lib_api.h"
#include "bl616cl_glb.h"
#include "rfparam_adapter.h"
#include "bflb_mtd.h"
#include "easyflash.h"
/**************************************************************************************************
* Beacon Configuration
**************************************************************************************************/
#define BEACON_COMPANY_ID 0x004C /* Apple, Inc. */
#define BEACON_TYPE 0x0215 /* iBeacon type */
#define BEACON_MAJOR 0x0001
#define BEACON_MINOR 0x0002
#define BEACON_TX_POWER 0xC5 /* -59 dBm */
static const uint8_t beacon_uuid[16] = {
0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78,
0x89, 0x9A, 0xAB, 0xBC, 0xCD, 0xDE, 0xEF, 0xF0
};
/**************************************************************************************************
* Beacon Data Builder
**************************************************************************************************/
static int build_ibeacon_data(uint8_t *buf, size_t buf_size)
{
uint8_t *p = buf;
if (buf_size < 28) {
return -1;
}
/* Flags */
*p++ = 0x02;
*p++ = 0x01;
*p++ = 0x06;
/* Manufacturer Specific Data */
*p++ = 26;
*p++ = 0xFF;
*p++ = (BEACON_COMPANY_ID & 0xFF);
*p++ = ((BEACON_COMPANY_ID >> 8) & 0xFF);
*p++ = ((BEACON_TYPE >> 8) & 0xFF);
*p++ = (BEACON_TYPE & 0xFF);
*p++ = 0x15;
memcpy(p, beacon_uuid, 16);
p += 16;
*p++ = ((BEACON_MAJOR >> 8) & 0xFF);
*p++ = (BEACON_MAJOR & 0xFF);
*p++ = ((BEACON_MINOR >> 8) & 0xFF);
*p++ = (BEACON_MINOR & 0xFF);
*p++ = BEACON_TX_POWER;
return (int)(p - buf);
}
/**************************************************************************************************
* Heap Helper
**************************************************************************************************/
static size_t heap_free(void)
{
return kfree_size(0);
}
/**************************************************************************************************
* Beacon Cycle Test Task
**************************************************************************************************/
static void beacon_cycle_task(void *pvParameters)
{
const int NUM_CYCLES = 3;
const int ADV_DURATION_MS = 3000;
uint8_t adv_data[BTBLE_ADV_DATA_MAX_LEN];
int adv_data_len;
struct btble_adv_params params;
int err;
printf("\r\n========================================\r\n");
printf(" BLE Beacon Lifecycle Cycle Test\r\n");
printf(" Sequence: ctrl_init -> adv_init -> set_params\r\n");
printf(" -> set_data -> adv_start -> adv_stop\r\n");
printf(" -> adv_deinit -> ctrl_deinit\r\n");
printf(" Cycles: %d, ADV duration: %dms\r\n", NUM_CYCLES, ADV_DURATION_MS);
printf("========================================\r\n\r\n");
/* Build beacon data once (same for all cycles) */
adv_data_len = build_ibeacon_data(adv_data, sizeof(adv_data));
if (adv_data_len < 0) {
printf("[ERR] Failed to build beacon data\r\n");
vTaskDelete(NULL);
return;
}
memset(¶ms, 0, sizeof(params));
params.adv_interval_min = 0x00A0; /* 100 ms */
params.adv_interval_max = 0x00F0; /* 150 ms */
params.adv_type = BTBLE_ADV_TYPE_NON_CONNECTABLE_UNDIRECTED;
params.own_addr_type = BTBLE_ADDR_TYPE_PUBLIC;
params.adv_channel_map = BTBLE_ADV_CHANNEL_ALL;
params.adv_filter_policy = BTBLE_ADV_FILTER_ALLOW_ALL;
size_t heap_baseline = heap_free();
printf("[BASELINE] heap free: %u bytes\r\n\r\n", (unsigned)heap_baseline);
for (int cycle = 1; cycle <= NUM_CYCLES; cycle++) {
size_t h_prev, h_cur;
printf("--- Cycle %d/%d ---\r\n", cycle, NUM_CYCLES);
/* Step 1: controller init */
h_prev = heap_free();
btble_controller_init(configMAX_PRIORITIES - 1);
h_cur = heap_free();
printf(" [ctrl_init] heap used: %u free: %u\r\n",
(unsigned)(h_prev - h_cur), (unsigned)h_cur);
{
uint8_t *em_addr = NULL;
int em_size = 0;
btble_controller_remaining_mem(&em_addr, &em_size);
printf(" [EM] remaining: %d bytes\r\n", em_size);
}
/* Step 2: adv init (HCI_Reset + Set_Event_Mask + queue alloc) */
h_prev = h_cur;
err = btble_adv_init();
h_cur = heap_free();
printf(" [adv_init] err=%d heap used: %u free: %u\r\n",
err, (unsigned)(h_prev - h_cur), (unsigned)h_cur);
if (err != 0) {
printf(" [ERR] adv_init failed, skipping cycle\r\n");
btble_controller_deinit();
continue;
}
/* Step 3: set parameters */
err = btble_adv_set_parameter(¶ms);
printf(" [set_params] err=%d\r\n", err);
/* Step 4: set adv data */
err = btble_adv_set_data(adv_data, (uint8_t)adv_data_len);
printf(" [set_data] err=%d len=%d\r\n", err, adv_data_len);
/* Step 5: start advertising */
err = btble_adv_start();
printf(" [adv_start] err=%d -> %s\r\n",
err, err == 0 ? "OK" : "FAILED");
/* Advertise for ADV_DURATION_MS */
vTaskDelay(pdMS_TO_TICKS(ADV_DURATION_MS));
/* Step 6: stop advertising */
err = btble_adv_stop();
printf(" [adv_stop] err=%d\r\n", err);
/* Step 7: adv deinit (queue free + state reset) */
h_prev = h_cur;
btble_adv_deinit();
h_cur = heap_free();
printf(" [adv_deinit] heap recovered: %u free: %u\r\n",
(unsigned)(h_cur - h_prev), (unsigned)h_cur);
/* Step 8: controller deinit */
h_prev = h_cur;
btble_controller_deinit();
h_cur = heap_free();
printf(" [ctrl_deinit] heap recovered: %u free: %u\r\n",
(unsigned)(h_cur - h_prev), (unsigned)h_cur);
/* Check for leaks */
if (h_cur >= heap_baseline) {
printf(" [CHECK] heap fully recovered\r\n");
} else {
printf(" [CHECK] heap leak: %u bytes (baseline=%u, now=%u)\r\n",
(unsigned)(heap_baseline - h_cur),
(unsigned)heap_baseline, (unsigned)h_cur);
}
printf("\r\n");
vTaskDelay(pdMS_TO_TICKS(200));
}
printf("========================================\r\n");
printf(" Beacon lifecycle test DONE (%d cycles)\r\n", NUM_CYCLES);
printf(" Final heap free: %u bytes\r\n", (unsigned)heap_free());
printf("========================================\r\n");
vTaskDelete(NULL);
}
/**************************************************************************************************
* Main
**************************************************************************************************/
int main(void)
{
board_init();
bflb_mtd_init();
easyflash_init();
if (0 != rfparam_init(0, NULL, 0)) {
printf("PHY RF init failed!\r\n");
return 0;
}
xTaskCreate(beacon_cycle_task, "beacon_cycle", 1024, NULL,
configMAX_PRIORITIES - 2, NULL);
vTaskStartScheduler();
while (1) {}
}FAQ
Build fails with bl616 / cannot run
The example depends on CONFIG_BLE_BEACON_ONLY, which only supports BL616CL (BLE-only chip). Regular BL618/BL616 in Ai-M61/Ai-M62 do not support it — use another BLE example (e.g. BLE Slave).
Phone cannot find the iBeacon
Confirm you are scanning during the 3-second advertising window; iBeacon is non-connectable, and some apps hide non-connectable devices by default — enable "show all devices/beacons" (nRF Connect shows manufacturer data in scan results).
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

