Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/dsyx/docs.silabs.com_zh/llms.txt

Use this file to discover all available pages before exploring further.

本应用笔记提供系统架构和 RTOS(Real-Time Operating System,实时操作系统)与 Bluetooth 应用之间基于事件通信的背景信息,讨论用户定义的任务并描述如何自定义应用程序。从 Silicon Labs Bluetooth SDK v3.1.0 起,适配层同时支持 Micrium OSFreeRTOS,两者均使用 CMSIS-RTOS2 API
本指南以 Simplicity Studio 5 中的 SoC-Empty 示例为基础进行说明,需要安装 Bluetooth SDK v3.1.0 或更高版本。

前提条件

硬件要求

带有 EFR32BG 或 EFR32MG 无线板的 Wireless Starter Kit

软件要求

Simplicity Studio 5,可选 IAR-EWARM(仅使用 SDK 兼容版本)

RTOS 基础知识

了解任务(Task)、信号量(Semaphore)、互斥量(Mutex)等 RTOS 概念

BLE 基础知识

具备 BLE 通信应用知识,可参阅 BLE 基础

安装 RTOS 组件

1

打开 Project Configurator

在 Simplicity Studio Project Explorer 中双击 soc_empty.slcp 文件,点击 SOFTWARE COMPONENTS 选项卡。
2

搜索并安装 Micrium OS Kernel

在搜索栏输入 micrium,在左窗格选择 Micrium OS Kernel,点击 Install
3

确认自动添加的组件

安装后自动添加以下组件:
  • Platform - CMSIS - CMSIS-RTOS2(及 Headers)
  • Platform - Common - Common APIs for CMSIS-Compliant Kernels
  • RTOS - Micrium OS - Kernel(及依赖的 CPU、Common、RTOS Description 模块)
如果应用中使用了 Simple timer service 组件,请替换为针对 Micrium OS 的版本:Simple timer service for Micrium RTOS

系统架构

支持 RTOS 的 Bluetooth 应用需要以下四个任务并发运行:
┌─────────────────────────────────────────────────────────┐
│  最高优先级                                              │
│  ┌────────────────────┐                                  │
│  │   Link Layer Task  │ ← Radio 中断驱动                 │
│  └────────────────────┘                                  │
│  ┌────────────────────┐                                  │
│  │ Bluetooth Host Task│ ← 更新 Stack、发出事件、处理命令  │
│  └────────────────────┘                                  │
│  ┌────────────────────┐                                  │
│  │ Event Handler Task │ ← 处理 Stack 事件                │
│  └────────────────────┘                                  │
│  ┌────────────────────┐                                  │
│  │    Idle Task       │ ← 无任务时进入 EM2 睡眠           │
│  └────────────────────┘                                  │
│  最低优先级                                              │
└─────────────────────────────────────────────────────────┘

任务间通信标志

任务通过以下标志(位于 sl_bt_rtos_adaptation 层内部)相互同步:
标志发送方接收方用途
SL_BT_RTOS_EVENT_FLAG_LLRadio 中断Link Layer Task链路层需要更新,调用 sl_bt_priority_handle()
SL_BT_RTOS_EVENT_FLAG_STACKLink Layer TaskBluetooth Host TaskStack 需要更新,调用 sl_bt_pop_event()
SL_BT_RTOS_EVENT_FLAG_CMD_WAITINGEvent Handler/Application TasksBluetooth Host Task命令就绪于共享内存,调用命令处理程序
SL_BT_RTOS_EVENT_FLAG_RSP_WAITINGBluetooth Host TaskEvent Handler/Application Tasks响应就绪于共享内存
SL_BT_RTOS_EVENT_FLAG_EVT_WAITINGBluetooth Host TaskEvent Handler Task事件就绪于共享内存
SL_BT_RTOS_EVENT_FLAG_EVT_HANDLEDEvent Handler TaskBluetooth Host Task事件已处理,共享内存可用于下一事件
此外,BGAPI 命令处理程序使用互斥量(BluetoothMutex)确保线程安全,允许从多个 RTOS 任务并发调用 BGAPI 命令。 等待 SL_BT_RTOS_EVENT_FLAG_LL 标志,通过调用 sl_bt_priority_handle() 更新上层链路层。该标志由 sli_bt_rtos_ll_callback() 在内核感知中断处理程序中设置。此任务具有最高优先级。

Bluetooth Host Task

负责更新 Stack、发出事件和处理命令,优先级高于 Event Handler Task,低于 Link Layer Task。初始化时调用 sl_bt_init() 并创建 Link Layer Task 和 Event Handler Task。

Event Handler Task

等待 SL_BT_RTOS_EVENT_FLAG_EVT_WAITING 标志,调用 sl_bt_process_event() 处理事件,并将事件分派到 sl_bt_on_event() 函数。此任务优先级低于 Bluetooth Host Task 和 Link Layer Task。

Idle Task

当没有任务准备运行时,OS 调用 Idle Task,默认将 MCU 置于最低可用睡眠模式(EM2)。

Bluetooth 事件处理

sl_bt_on_event() 是 Event Handler Task 的一部分,用于处理 Bluetooth Stack 发出的事件:
void sl_bt_on_event(sl_bt_msg_t *evt)
{
    switch (SL_BT_MSG_ID(evt->header)) {
        // 协议栈初始化完成,可以开始广告
        case sl_bt_evt_system_boot_id:
            sl_bt_advertiser_start(/* ... */);
            break;

        // 连接关闭,重新开始广告
        case sl_bt_evt_connection_closed_id:
            sl_bt_advertiser_start(/* ... */);
            break;

        // 处理用户写入请求
        case sl_bt_evt_gatt_server_user_write_request_id:
            if (evt->data.evt_gatt_server_user_write_request.characteristic
                == gattdb_LED0) {
                if (evt->data.evt_gatt_server_user_write_request.value.data[0]) {
                    sl_led_turn_on(&sl_led_led0);
                } else {
                    sl_led_turn_off(&sl_led_led0);
                }
                sl_bt_gatt_server_send_user_write_response(
                    evt->data.evt_gatt_server_user_write_request.connection,
                    evt->data.evt_gatt_server_user_write_request.characteristic,
                    0);
            }
            break;

        // 处理用户读取请求
        case sl_bt_evt_gatt_server_user_read_request_id:
            if (evt->data.evt_gatt_server_user_read_request.characteristic
                == gattdb_LED0) {
                uint8_t led0_state = sl_led_get_state(&sl_led_led0);
                uint16_t sent_len = 0;
                sl_bt_gatt_server_send_user_read_response(
                    evt->data.evt_gatt_server_user_read_request.connection,
                    evt->data.evt_gatt_server_user_read_request.characteristic,
                    0, 1, &led0_state, &sent_len);
            }
            break;

        default:
            break;
    }
}
sl_bt_on_event() 中实现的事件处理程序应快速完成工作。如需执行耗时或异步操作,应创建独立的 Application Task 来处理,并通过 RTOS 标志/信号量与事件处理程序通信。

添加 Application Task

应用程序任务的优先级必须低于 Link Layer Task、Bluetooth Host Task 和 Event Handler Task。Bluetooth Stack 任务优先级在 sl_bt_rtos_config.h 中定义,可通过 Bluetooth Core 组件配置。
app.c 中添加以下代码:
#include "os.h"

// 任务参数定义
#define SL_BT_RTOS_APPLICATION_PRIORITY   10u
#ifndef APPLICATION_STACK_SIZE
#define APPLICATION_STACK_SIZE (1000 / sizeof(CPU_STK))
#endif

static void    ApplicationTask(void *p_arg);
static OS_TCB  ApplicationTaskTCB;
static CPU_STK ApplicationTaskStk[APPLICATION_STACK_SIZE];
app_init() 中创建任务:
RTOS_ERR os_err;
OSTaskCreate(&ApplicationTaskTCB,
             "Application Task",
             ApplicationTask,
             0u,
             SL_BT_RTOS_APPLICATION_PRIORITY,
             &ApplicationTaskStk[0u],
             APPLICATION_STACK_SIZE / 10u,
             APPLICATION_STACK_SIZE,
             0u, 0u, 0u,
             (OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
             &os_err);
时间驱动任务实现(每秒切换 LED1):
static void ApplicationTask(void *p_arg)
{
    RTOS_ERR os_err;
    (void)p_arg;

    while (DEF_TRUE) {
        // 每秒执行一次
        OSTimeDlyHMSM(0, 0, 1, 0,
                      OS_OPT_TIME_DLY | OS_OPT_TIME_HMSM_NON_STRICT,
                      &os_err);
        sl_led_toggle(&sl_led_led1);
    }
}

时间与事件驱动任务

任务可以是时间驱动(定时器到期)、事件驱动(外部事件触发)或两者兼有
使用 Event Flag Management 实现按钮驱动的 LED 闪烁频率变化:
#include "sl_simple_button_instances.h"

// 全局事件标志组
OS_FLAG_GRP application_event_flags;
#define APPLICATION_EVENT_FLAG_BTN_ON  ((OS_FLAGS)1)
#define APPLICATION_EVENT_FLAG_BTN_OFF ((OS_FLAGS)2)
app_init() 中初始化事件标志组:
RTOS_ERR os_err;
OSFlagCreate(&application_event_flags,
             "Application Flags",
             (OS_FLAGS)0,
             &os_err);
时间+事件驱动任务实现:
static void ApplicationTask(void *p_arg)
{
    RTOS_ERR os_err;
    (void)p_arg;
    uint32_t interval_ms;
    OS_RATE_HZ tick_rate;
    OS_FLAGS flags;

    tick_rate = OSTimeTickRateHzGet(&os_err);
    interval_ms = 1 * tick_rate;  // 初始间隔 1 秒

    while (DEF_TRUE) {
        flags = OSFlagPend(
            &application_event_flags,
            (OS_FLAGS)(APPLICATION_EVENT_FLAG_BTN_ON
                       + APPLICATION_EVENT_FLAG_BTN_OFF),
            interval_ms,
            OS_OPT_PEND_BLOCKING + OS_OPT_PEND_FLAG_SET_ANY
            + OS_OPT_PEND_FLAG_CONSUME,
            NULL, &os_err);

        if (flags & APPLICATION_EVENT_FLAG_BTN_ON) {
            interval_ms = tick_rate / 5;  // 按下时:200 ms
        }
        if (flags & APPLICATION_EVENT_FLAG_BTN_OFF) {
            interval_ms = 1 * tick_rate;  // 释放时:1 秒
        }
        sl_led_toggle(&sl_led_led1);
    }
}
按钮回调中设置标志:
void sl_button_on_change(const sl_button_t *handle)
{
    RTOS_ERR os_err;
    if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_PRESSED) {
        OSFlagPost(&application_event_flags,
                   (OS_FLAGS)APPLICATION_EVENT_FLAG_BTN_ON,
                   OS_OPT_POST_FLAG_SET, &os_err);
    } else if (sl_button_get_state(handle) == SL_SIMPLE_BUTTON_RELEASED) {
        OSFlagPost(&application_event_flags,
                   (OS_FLAGS)APPLICATION_EVENT_FLAG_BTN_OFF,
                   OS_OPT_POST_FLAG_SET, &os_err);
    }
}

Bluetooth On-Demand Start(按需启动)

如果 Bluetooth Stack 不需要全时间运行,可使用按需启动特性:
1

安装组件

在 Project Configurator 的 Software Components 中搜索并安装 Bluetooth on-demand start 组件。
2

手动启动/停止 Stack

安装后,Bluetooth Stack 不会自动启动,需要由应用程序负责启动和停止:
sl_bt_system_start_bluetooth();   // 启动 Bluetooth Stack
sl_bt_system_stop_bluetooth();    // 优雅停止(断开连接、停止广告/扫描,释放资源)
3

在 Application Task 中控制

示例:通过按钮切换 Bluetooth Stack 的启停状态:
static void ApplicationTask(void *p_arg)
{
    RTOS_ERR os_err;
    (void)p_arg;
    OS_FLAGS flags;
    static bool stack_is_running = false;

    while (DEF_TRUE) {
        flags = OSFlagPend(
            &application_event_flags,
            (OS_FLAGS)(APPLICATION_EVENT_FLAG_BTN_ON
                       + APPLICATION_EVENT_FLAG_BTN_OFF),
            0,
            OS_OPT_PEND_BLOCKING + OS_OPT_PEND_FLAG_SET_ANY
            + OS_OPT_PEND_FLAG_CONSUME,
            NULL, &os_err);

        if (flags & APPLICATION_EVENT_FLAG_BTN_ON) {
            if (!stack_is_running) {
                sl_bt_system_start_bluetooth();
            } else {
                sl_bt_system_stop_bluetooth();
            }
            stack_is_running = !stack_is_running;
        }
    }
}

任务优先级配置

Bluetooth Stack 任务优先级在 sl_bt_rtos_config.h 中定义,可通过 Bluetooth Core 组件(Bluetooth – RTOS 分类下)配置:
任务推荐优先级(Micrium OS)推荐优先级(FreeRTOS)说明
Link Layer Task最高(如 52)最高(如 52)实时性最严格
Bluetooth Host Task次高(如 51)次高(如 51)需高于 Event Handler
Event Handler Task中(如 50)中(如 50)处理应用事件
Application Task低(≥ 10,推荐)低(≥ 10,推荐)用户自定义任务
Application Task 的优先级必须低于所有 Bluetooth Stack 任务。对于 Micrium OS,数字越小优先级越高;对于 FreeRTOS,数字越大优先级越高。Silicon Labs 建议将 Application Task 的优先级数字设置为 ≥ 10

SDK 示例应用

SDK 中提供了以下 RTOS 集成示例,可在 Simplicity Studio 的 Example Projects & Demos 中找到:

Bluetooth – SoC Thermometer FreeRTOS

演示 FreeRTOS 与 Bluetooth 应用的集成,在 SoC Thermometer 示例基础上添加 FreeRTOS 支持。

Bluetooth – SoC Thermometer Micrium OS

演示 Micrium RTOS 与 Bluetooth 应用的集成,在 SoC Thermometer 示例基础上添加 Micrium OS 支持。

Bluetooth – SoC Empty RAIL DMP FreeRTOS

Bluetooth + 专有协议动态多协议(DMP)应用起始项目,运行在 FreeRTOS 之上。

Bluetooth – SoC Empty RAIL DMP Micrium OS

Bluetooth + 专有协议动态多协议(DMP)应用起始项目,运行在 Micrium OS 之上。
尽管 Bluetooth RTOS 适配层使用 CMSIS-RTOS2 API,强烈建议用户应用程序代码使用原生的 Micrium OS 或 FreeRTOS API,以充分利用系统特性。CMSIS-RTOS2 API 实现不支持所有 RTOS 特性,更适合用于 Bluetooth Stack 的可移植性需求。

Build docs developers (and LLMs) love