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 OS 和 FreeRTOS ,两者均使用 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 概念
安装 RTOS 组件
打开 Project Configurator
在 Simplicity Studio Project Explorer 中双击 soc_empty.slcp 文件,点击 SOFTWARE COMPONENTS 选项卡。
搜索并安装 Micrium OS Kernel
在搜索栏输入 micrium ,在左窗格选择 Micrium OS Kernel ,点击 Install 。
确认自动添加的组件
安装后自动添加以下组件:
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 。
打开 Project Configurator
在 Simplicity Studio Project Explorer 中双击 soc_empty.slcp 文件,点击 SOFTWARE COMPONENTS 选项卡。
搜索并安装 FreeRTOS Heap 3
在搜索栏输入 freertos ,在左窗格选择 FreeRTOS Heap 3 ,点击 Install 。 安装 FreeRTOS Heap 3 会自动添加以下组件:
Platform - CMSIS - CMSIS-RTOS2(及 Headers)
Platform - Common - Common APIs for CMSIS-Compliant Kernels
RTOS - FreeRTOS(及 FreeRTOS Heap 3)
如使用 Simple timer service 组件,请替换为 Simple timer service for FreeRTOS 或 Simple timer service for FreeRTOS with static memory allocation 。如只安装 FreeRTOS 而非 FreeRTOS Heap 3 ,将默认使用 FreeRTOS Heap 4 。
系统架构
支持 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 Task Bluetooth Host Task Stack 需要更新,调用 sl_bt_pop_event() SL_BT_RTOS_EVENT_FLAG_CMD_WAITINGEvent Handler/Application Tasks Bluetooth Host Task 命令就绪于共享内存,调用命令处理程序 SL_BT_RTOS_EVENT_FLAG_RSP_WAITINGBluetooth Host Task Event Handler/Application Tasks 响应就绪于共享内存 SL_BT_RTOS_EVENT_FLAG_EVT_WAITINGBluetooth Host Task Event Handler Task 事件就绪于共享内存 SL_BT_RTOS_EVENT_FLAG_EVT_HANDLEDEvent Handler Task Bluetooth Host Task 事件已处理,共享内存可用于下一事件
此外,BGAPI 命令处理程序使用互斥量(BluetoothMutex)确保线程安全,允许从多个 RTOS 任务并发调用 BGAPI 命令。
Link Layer Task
等待 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 组件配置。
Micrium OS 时间驱动任务
FreeRTOS 时间驱动任务
在 app.c 中添加以下代码: #include "os.h"
// 任务参数定义
#define SL_BT_RTOS_APPLICATION_PRIORITY 10 u
#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,
0 u ,
SL_BT_RTOS_APPLICATION_PRIORITY,
& ApplicationTaskStk [ 0 u ],
APPLICATION_STACK_SIZE / 10 u ,
APPLICATION_STACK_SIZE,
0 u , 0 u , 0 u ,
(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);
}
}
在 app.c 中添加以下代码: #include "FreeRTOS.h"
#include "task.h"
// 任务参数定义(FreeRTOS 中数字越大优先级越高)
#define SL_BT_RTOS_APPLICATION_PRIORITY 10 u
static void vTaskApplication ( void * pvParameters );
_ALIGNED ( 8 ) static StackType_t
thread_application_stk [ 250 & 0x FFFFFFF8 u ];
_ALIGNED ( 4 ) static StaticTask_t thread_application_cb;
在 app_init() 中创建任务: xTaskCreateStatic (
( TaskFunction_t ) vTaskApplication ,
"Application Task" ,
sizeof (thread_application_stk) / sizeof ( StackType_t ),
NULL ,
( UBaseType_t ) SL_BT_RTOS_APPLICATION_PRIORITY ,
thread_application_stk,
& thread_application_cb );
时间驱动任务实现(每秒切换 LED1): static void vTaskApplication ( void * pvParameters )
{
( void )pvParameters;
while ( 1 ) {
vTaskDelay ( 1000 );
sl_led_toggle ( & sl_led_led1);
}
}
时间与事件驱动任务
任务可以是时间驱动 (定时器到期)、事件驱动 (外部事件触发)或两者兼有 。
Micrium OS 事件驱动示例
FreeRTOS 事件驱动示例
使用 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);
}
}
使用 Event Groups 实现按钮驱动的 LED 闪烁频率变化: #include "sl_simple_button_instances.h"
#include "event_groups.h"
// 全局 Event Group
EventGroupHandle_t xEventGroupApplicationHandle;
StaticEventGroup_t xEventGroupApplicationData;
#define APPL_EVENT_GROUP_BIT_BTN_ON (( EventBits_t ) 1 )
#define APPL_EVENT_GROUP_BIT_BTN_OFF (( EventBits_t ) 2 )
在 app_init() 中创建 Event Group: xEventGroupApplicationHandle =
xEventGroupCreateStatic ( & xEventGroupApplicationData );
时间+事件驱动任务实现: static void vTaskApplication ( void * pvParameters )
{
( void )pvParameters;
EventBits_t uxBits;
TickType_t xTicksToWait = 1000 / portTICK_PERIOD_MS;
while ( 1 ) {
uxBits = xEventGroupWaitBits (
xEventGroupApplicationHandle,
APPL_EVENT_GROUP_BIT_BTN_ON | APPL_EVENT_GROUP_BIT_BTN_OFF,
pdTRUE, // 返回前清除位
pdFALSE, // 任意位满足即可
xTicksToWait);
if (uxBits & APPL_EVENT_GROUP_BIT_BTN_ON) {
xTicksToWait = 200 / portTICK_PERIOD_MS; // 按下:200 ms
sl_led_toggle ( & sl_led_led1);
} else if (uxBits & APPL_EVENT_GROUP_BIT_BTN_OFF) {
xTicksToWait = 1000 / portTICK_PERIOD_MS; // 释放:1 秒
sl_led_toggle ( & sl_led_led1);
} else {
// 超时:按当前间隔切换 LED
sl_led_toggle ( & sl_led_led1);
}
}
}
按钮回调中设置 Event Group 位: void sl_button_on_change ( const sl_button_t * handle )
{
if ( sl_button_get_state (handle) == SL_SIMPLE_BUTTON_PRESSED) {
xEventGroupSetBits (xEventGroupApplicationHandle,
APPL_EVENT_GROUP_BIT_BTN_ON);
} else if ( sl_button_get_state (handle) == SL_SIMPLE_BUTTON_RELEASED) {
xEventGroupSetBits (xEventGroupApplicationHandle,
APPL_EVENT_GROUP_BIT_BTN_OFF);
}
}
以上示例演示效果:
LED1 每秒闪烁一次(初始状态)
按下按钮并保持时,LED1 每 200 ms 闪烁一次
释放按钮后,LED1 恢复每秒闪烁一次
Bluetooth On-Demand Start(按需启动)
如果 Bluetooth Stack 不需要全时间运行,可使用按需启动特性:
安装组件
在 Project Configurator 的 Software Components 中搜索并安装 Bluetooth on-demand start 组件。
手动启动/停止 Stack
安装后,Bluetooth Stack 不会自动启动,需要由应用程序负责启动和停止: sl_bt_system_start_bluetooth (); // 启动 Bluetooth Stack
sl_bt_system_stop_bluetooth (); // 优雅停止(断开连接、停止广告/扫描,释放资源)
在 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 的可移植性需求。