Overview
iBeacon is Apple's beacon solution based on BLE advertising: the device only advertises (periodically sends a small packet of data, like shouting through a loudspeaker) and never establishes a connection; a phone passing by can recognize it and the information it carries (UUID, Major, Minor, etc.). It is commonly used for indoor positioning in malls, store push notifications and item-finding tags. This tutorial turns the Ai-WB2 into an iBeacon beacon and verifies the advertised content with a phone app.
In plain words: iBeacon is like a roadside billboard. The billboard doesn't talk to you or shake your hand — it just stands there showing its content ("who I am, where I am, how strong my signal is"), and you see it at a glance when you walk past. This tutorial turns the board into such a "Bluetooth billboard"; the phone app is the passing pedestrian — walk close and you can read the words on the sign (UUID and other data).
This tutorial is based on the official Ai-Thinker SDK (Ai-Thinker-Open/Ai-Thinker-WB2, version
release_bl_iot_sdk_1.6.40) exampleapplications/bluetooth/ble_ibeacon; the code can be found directly in the local SDK.
This tutorial uses the official SDK’s built-in ble_ibeacon example project directly; open a terminal and enter the project directory:
cd ~/Ai-Thinker-WB2/applications/bluetooth/ble_ibeacon
Note:
cdis the “change directory” command — entering the iBeacon example project directory; all subsequentmakebuild andmake flashflash commands must run in this directory.
Project structure:
| File | Purpose |
|---|---|
ble_ibeacon/main.c |
Main program source (the only source file in this project) — the main file this tutorial looks at |
ble_ibeacon/bouffalo.mk |
Project build config, usually no changes needed |
Open ble_ibeacon/main.c and find the iBeacon data array my_ibeacon[] — the advertised content lives here (each byte is a “word” on the billboard):
char my_ibeacon[]=
{
0x4C, 0x00, //公司的标志 (0x004C == Apple)
0x02, 0x15, //iBeacon advertisement indicator
0xB9, 0x40, ... 0x6D, // iBeacon proximity uuid(16 字节)
0x00, 0x01, // major(主编号)
0x00, 0x01, // minor(次编号)
0xc5 //power(发射功率,用于估算距离)
};
| Field | In plain words | Purpose |
|---|---|---|
Company ID 0x4C 0x00 |
Maker’s stamp | Declares the Apple iBeacon format |
| UUID (16 bytes) | ID card number | Identifies whose this beacon group is; customizable |
| major / minor | Group number / number | Subdivides under the same UUID (e.g. store number, shelf number) |
power 0xc5 |
Volume level | The transmit power; the phone estimates distance from it |
💡 The example UUID corresponds to
B9407F30-F5F8-466E-AFF9-25556B57FE6D(a common test UUID) — you can change these 16 bytes as you need; the device name is controlled by the macroIBEACON_NAME(default"MY_IBEACON") — change it to change the name shown in the broadcast.
The official example runs without modification; the complete main.c source has been moved to the end of this page:
📜 Full Code — in the “Full Code” section below, collapsed by default — click to expand, identical to the official example (
applications/bluetooth/ble_ibeacon/ble_ibeacon/main.c).
Code highlights:
| API | Purpose |
|---|---|
bl_sys_init() |
Initializes basic resources such as the system clock; must be called before using BLE — skipping it crashes immediately |
ble_controller_init(configMAX_PRIORITIES - 1) |
Initializes the BLE protocol stack (the brain of Bluetooth communication); without it all BLE functions below are no-ops |
hci_driver_init() |
Initializes the Bluetooth hardware driver, relaying between the CPU and the Bluetooth radio; skip it and nothing can advertise |
bt_enable(NULL) |
Turns on the Bluetooth protocol stack, like turning on a phone’s “Bluetooth switch”; without it nothing can advertise |
bt_le_adv_start(¶m, ibeacon_data, ...) |
Actually starts the “loudspeaker shout”; the content is ibeacon_data; without it the phone can’t find you |
bt_set_name(IBEACON_NAME) |
Names the device (MY_IBEACON) — what appears in the phone’s scan list |
Build in the project directory:
make -j8
Note:
makeis the “build” command, turning code into firmware (the program flashed into the board) the board can run;-j8builds with 8 parallel CPU cores, faster.
On success a firmware build_out/ble_ibeacon.bin is generated.
⚠️ If it reports
riscv64-unknown-elf-gcc: command not found, the toolchain permissions aren’t configured — runcd toolchain/riscv/Linux && . chmod755.shfirst, then rebuild.
Keep the board connected via USB, confirm the serial device, and flash:
make flash p=/dev/ttyUSB0 b=921600
Note:
make flashis the “flash” command, writing the compiled firmware into the board’s chip. Afterp=comes the serial device (change it to your computer’s actual one — check withls /dev/ttyUSB*),b=921600is the flash baud rate (serial transfer speed), keep the default.
⏳ During flashing, press and hold the EN button on the board when prompted to enter download mode (some boards enter automatically); wait for the progress bar to complete — that means the flash succeeded.
After flashing, the board automatically restarts and runs. First check the serial log — note! This example sets the serial baud rate to 115200 (bl_uart_init(0, 16, 7, 255, 255, 115200)), so the serial assistant must be set to 115200, not 921600:
AXK BLE IBEACON
ble_controller_init
hci_driver_init
bt_enable
Then open a Bluetooth debugging app on your phone (e.g. nRF Connect, available on both Android and iOS) and scan nearby devices — you should see a device named MY_IBEACON, or recognize an iBeacon beacon with UUID B9407F30-F5F8-466E-AFF9-25556B57FE6D.
The serial printing AXK BLE IBEACON and the phone app finding MY_IBEACON means success; if the serial has no output, first check that the baud rate is set to 115200; if the phone can’t find MY_IBEACON, see the FAQ at the end.
💡 Advanced verification: walk with your phone within 0.5~5 m of the board — some iBeacon apps show a distance estimate (that’s what the power field is for), confirming the advertised data is fully parsed.
API Summary for This Tutorial
bl_sys_init
Initializes basic resources such as the system clock and peripherals; must be called before using BLE (called in main() in this example).
Return: 0 on success; negative error code on failure
bl_uart_init(id, tx_pin, rx_pin, cts_pin, rts_pin, baudrate)
Initializes the serial port (UART — the channel that passes data bit by bit between the computer and the board); this example sets the log serial to 115200 baud (transfer speed).
Parameters:
id: serial number, values:0/1; this example uses0tx_pin: transmit pin; this example16rx_pin: receive pin; this example7cts_pin: flow-control pin; pass255if unusedrts_pin: flow-control pin; pass255if unusedbaudrate: baud rate (the "speech rate" of serial transfer — both ends must agree); this example115200
Return: 0 on success; negative error code on failure
ble_controller_init(task_priority)
Initializes the BLE protocol stack (the "brain" of Bluetooth communication) — the first step of all BLE features.
Parameters:
task_priority: protocol stack task priority (uint8_t); the official example passesconfigMAX_PRIORITIES - 1(system highest priority)
Return: none
hci_driver_init
Initializes the Bluetooth hardware driver, responsible for passing data between the CPU and the Bluetooth radio chip.
Return: 0 on success; negative error code on failure
bt_enable(cb)
Turns on the Bluetooth protocol stack — like turning on a phone's "Bluetooth switch"; without it nothing can advertise/connect.
Parameters:
cb: stack-ready callback (bt_ready_cb_t), shapedvoid cb(int err); passNULLif not needed
Return: 0 on success; negative error code on failure
bt_set_name(name)
Sets the Bluetooth device name — what appears in the phone's scan list.
Parameters:
name: the device name string, required (this example"MY_IBEACON")
Return: 0 on success; negative error code on failure
bt_le_adv_start(param, ad, ad_len, sd, sd_len)
Starts BLE advertising (the "loudspeaker shout"); the advertised data is specified by the ad array.
Parameters:
param: advertising parameter structure pointer, including the advertising interval (interval_min/interval_max), options (connectable/carry device name), etc.ad: advertising data array (bt_data_t); this exampleibeacon_data(contains the iBeacon data)ad_len: number of advertising data entries; this exampleARRAY_SIZE(ibeacon_data)(2 entries)sd: scan response data array; passNULLif not neededsd_len: number of scan response entries; pass0
Return: 0 on success; negative error code on failure
vTaskDelay(ms)
Suspends the current task for the given milliseconds, yielding the CPU to other tasks.
Parameters:
ms: delay in milliseconds; this example10(waiting for BLE hardware to be ready)
Return: none
xTaskCreate(task, name, stack, param, prio, handle)
Creates a task and adds it to the ready queue; the scheduler runs it by priority.
Parameters:
task: task entry function pointer, shapedvoid task(void *arg), requiredname: task name string (for debugging); this example"ibeacon"stack: task stack size (in words); this example1024param: parameter pointer passed to the entry function; passNULLif noneprio: task priority, values:0(lowest) ~19(highest, per SDK config); this example15handle: task handle output pointer; passNULLif not needed
Return: pdPASS on success; pdFAIL on failure (e.g. out of memory)
Full Code
Below is the complete ble_ibeacon/main.c source, identical to the official example (applications/bluetooth/ble_ibeacon/ble_ibeacon/main.c):
📜 Click to expand the full main.c code
/*
* Copyright (c) 2020 Bouffalolab.
*
* This file is part of
* *** Bouffalolab Software Dev Kit ***
* (see www.bouffalolab.com).
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Bouffalo Lab nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <string.h>
#include <FreeRTOS.h>
#include <task.h>
#include <blog.h>
#include <stdio.h>
#include <cli.h>
#include <blog.h>
#include <bl_uart.h>
#include <bl_sys.h>
#include "hci_driver.h"
#include "ble_lib_api.h"
#include "bluetooth.h"
#include "gatt.h"
#include "uuid.h"
#include <hosal_uart.h>
#define PRIORITIE_OFFSET 4
/*set ibeacon name*/
#define IBEACON_NAME "MY_IBEACON"
/*ibeacon data*/
char my_ibeacon[]=
{
0x4C, 0x00, //公司的标志 (0x004C == Apple)
0x02, 0x15, //iBeacon advertisement indicator
0xB9, 0x40, 0x7F, 0x30, 0xF5, 0xF8, 0x46, 0x6E, 0xAF, 0xF9, 0x25, 0x55, 0x6B, 0x57, 0xFE, 0x6D, // iBeacon proximity uuid
0x00, 0x01, // major
0x00, 0x01, // minor
0xc5 //power
};
static struct bt_data ibeacon_data[2] =
{
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA(BT_DATA_MANUFACTURER_DATA, my_ibeacon, sizeof(my_ibeacon)),//
};
/*start ble advertise*/
void ble_start_advertise(void)
{
struct bt_le_adv_param param;
param.id = BT_ID_DEFAULT;
param.interval_min = BT_GAP_ADV_FAST_INT_MIN_2;
param.interval_max = BT_GAP_ADV_FAST_INT_MAX_2;
//param.options = BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME;
param.options = BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_USE_NAME | BT_LE_ADV_OPT_ONE_TIME;
/*Get mode, 0:General discoverable, 1:non discoverable, 2:limit discoverable*/
bt_le_adv_start(¶m,ibeacon_data, ARRAY_SIZE(ibeacon_data),NULL,0);
bt_set_name(IBEACON_NAME);
}
/*BLE ibeacon init*/
void ble_ibeacon_init(void)
{
printf("ble_controller_init\r\n");
ble_controller_init(configMAX_PRIORITIES - 1); //ble协议栈初始化
printf("hci_driver_init\r\n");
hci_driver_init();//初始化驱动
printf("bt_enable\r\n");
bt_enable(NULL);
ble_start_advertise();//开启广播
}
static void app_init_thread(void *param)
{
vTaskDelay(10 / portTICK_RATE_MS);
ble_ibeacon_init();
vTaskDelete(NULL);
}
static void app_init_entry(void)
{
if(xTaskCreate(app_init_thread, ((const char*)"app_init"), 1024*6, NULL, tskIDLE_PRIORITY + 3 + PRIORITIE_OFFSET, NULL) != pdPASS)
printf("\n\r%s xTaskCreate(init_thread) failed", __FUNCTION__);
}
static void ble_loop_proc(void *pvParameters)
{
app_init_entry();
vTaskDelete(NULL);
}
void main(void)
{
bl_uart_init(0, 16, 7, 255, 255, 115200);//set uart baud 115200
printf("AXK BLE IBEACON\r\n");//log
bl_sys_init(); //if use ble,must init
xTaskCreate(ble_loop_proc, (char*)"ibeacon", 1024, NULL, 15, NULL);
}FAQ & Troubleshooting
⚠️ The phone can't find MY_IBEACON
Cause: advertising not started, distance too far, or the phone's Bluetooth/location permission is off
Fix: confirm the serial printed bt_enable and the program didn't hang after it; Android phones must enable the "location permission" to scan BLE devices; move the phone close to the board (0.5~5 m) and scan again; iBeacon-style apps cache results — kill and reopen the app
⚠️ No serial log output at all
Cause: wrong baud rate in the serial assistant — this example sets the serial to 115200, not the usual 921600
Fix: change the serial assistant baud rate to 115200 and reopen it; confirm the serial number is right (ls /dev/ttyUSB* to check)
⚠️ Changed the UUID/name, but the phone still shows the old one
Cause: not rebuilt and reflashed after the change, or the phone app cached the old data
Fix: after changing my_ibeacon[]/IBEACON_NAME, rerun make -j8 && make flash p=/dev/ttyUSB0 b=921600; on the phone, restart the app and toggle Bluetooth off/on
⚠️ Flashing keeps waiting, progress bar doesn't move
Cause: download mode wasn't entered, or the cable only charges and can't transfer data
Fix: press and hold EN during flashing to enter download mode as prompted; try a Type-C data-capable cable
⚠️ Serial device not found / can't open
Cause: USB-to-serial driver not installed, insufficient permission, or wrong device number
Fix: on Linux check with lsusb/dmesg; if permission denied run sudo usermod -aG dialout $USER and log back in; on Windows check the COM port in Device Manager
⚠️ make reports Makefile not found
Cause: the build command ran in the wrong directory
Fix: first run cd ~/Ai-Thinker-WB2/applications/bluetooth/ble_ibeacon to enter the project directory, then run make -j8
Self-Check
The serial prints AXK BLE IBEACON → ble_controller_init → hci_driver_init → bt_enable in order, and the phone's Bluetooth app finds a device named MY_IBEACON (iBeacon UUID B9407F30-F5F8-466E-AFF9-25556B57FE6D) — the advertising feature is verified.

