Skip to content

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) example applications/bluetooth/ble_ibeacon; the code can be found directly in the local SDK.

🎯Page GoalMake the board advertise custom iBeacon data (UUID / Major / Minor / transmit power), searchable and recognizable by a phone app — mastering the complete BLE advertising flow.
🧰Prerequisites① An Ai-WB2 development board ② Development environment set up per [SDK Installation](../../sdk/sdk_intro) ③ A BLE-capable phone (with a Bluetooth debugging app such as nRF Connect installed).
🔗RelatedBLE concepts: [BLE Introduction](./ble_intro); the "shouter/listener" relationship of advertising: see the scanning part of [BLE Master](./ble_master).

Enter the Example Project

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: cd is the “change directory” command — entering the iBeacon example project directory; all subsequent make build and make flash flash 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
Understand and Modify the Broadcast Content (Optional)

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 macro IBEACON_NAME (default "MY_IBEACON") — change it to change the name shown in the broadcast.

Write the Code

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(&param, 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 the Project

Build in the project directory:

make -j8

Note: make is the “build” command, turning code into firmware (the program flashed into the board) the board can run; -j8 builds 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 — run cd toolchain/riscv/Linux && . chmod755.sh first, then rebuild.

Flash the Firmware

Keep the board connected via USB, confirm the serial device, and flash:

make flash p=/dev/ttyUSB0 b=921600

Note: make flash is the “flash” command, writing the compiled firmware into the board’s chip. After p= comes the serial device (change it to your computer’s actual one — check with ls /dev/ttyUSB*), b=921600 is 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.

Run and Verify

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 uses 0
  • tx_pin: transmit pin; this example 16
  • rx_pin: receive pin; this example 7
  • cts_pin: flow-control pin; pass 255 if unused
  • rts_pin: flow-control pin; pass 255 if unused
  • baudrate: baud rate (the "speech rate" of serial transfer — both ends must agree); this example 115200

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 passes configMAX_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), shaped void cb(int err); pass NULL if 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 example ibeacon_data (contains the iBeacon data)
  • ad_len: number of advertising data entries; this example ARRAY_SIZE(ibeacon_data) (2 entries)
  • sd: scan response data array; pass NULL if not needed
  • sd_len: number of scan response entries; pass 0

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 example 10 (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, shaped void task(void *arg), required
  • name: task name string (for debugging); this example "ibeacon"
  • stack: task stack size (in words); this example 1024
  • param: parameter pointer passed to the entry function; pass NULL if none
  • prio: task priority, values: 0 (lowest) ~ 19 (highest, per SDK config); this example 15
  • handle: task handle output pointer; pass NULL if 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
c
/*
 * 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(&param,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 IBEACONble_controller_inithci_driver_initbt_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.

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