杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

实时操作系统与 POSIX 层

本页介绍 AC79NN SDK 的运行时基础:底层 FreeRTOS 内核、杰理自研的 os_api 抽象接口层,以及 Amazon FreeRTOS-Plus-POSIX 兼容层(pthread / mqueue / semaphore 等),说明它们的分层关系、核心 API、配置开关与典型用法。

Purpose and Scope

本页覆盖 SDK 中与"实时操作系统(RTOS)与 POSIX 层"相关的全部基础设施:

  • 底层 RTOS 内核(FreeRTOS)的定位与接入方式;
  • 杰理 os_api 抽象层(任务、信号量、互斥量、消息队列、消息邮箱等)的设计意图与核心接口;
  • FreeRTOS-Plus-POSIX 兼容层(FreeRTOS_POSIX.h、pthread、mqueue)如何让标准 POSIX 程序直接运行;
  • 系统初始化与调度启动流程(os_init / os_init_tick / os_start);
  • 相关配置开关(os_cfg.h)与测试示例(os_api / pthreads_api 用例)。

以下内容属于其他页面,不在本页展开:设备驱动与中断(见驱动相关页面)、内存管理/堆分配策略、具体的电源管理流程。本页聚焦于"任务/同步/通信原语"这一运行时的核心机制。

Overview

AC79NN SDK 是一个典型的嵌入式 AIoT 单芯片 SDK,片上同时运行音频、蓝牙、网络协议栈与应用逻辑,因此需要抢占式多任务实时操作系统来保证时延与确定性。整个运行时自底向上分为三层:

  1. 内核层:FreeRTOS 提供抢占式调度、tick 时钟、任务状态机与内核对象(信号量、队列、事件组)。SDK 中通过 FreeRTOS/FreeRTOS.h、event_groups.h、semphr.h 等头文件接入。
  2. 抽象层:杰理自研的 os_api.h 将内核能力包装成一套稳定、精简、与具体内核解耦的 C 接口(os_task_create、os_sem_*、os_mutex_*、os_q_*、os_taskq_* 等)。SDK 内绝大多数业务模块(音频、蓝牙、网络)都通过这一层使用操作系统,而不是直接调用 FreeRTOS,从而保持可移植性。
  3. 兼容层:include_lib/system/os/POSIX/FreeRTOS-Plus-POSIX/ 下的 Amazon FreeRTOS POSIX V1.1.0 移植,提供 pthread_*、mq_*、POSIX semaphore、timer 等标准接口,使第三方/标准 POSIX 代码(如 lwIP、mDNS、benchmark)无需修改即可编译运行。

这种"内核 + 私有抽象 + POSIX 兼容"的三层结构是设计意图的核心:私有 os_api 保证杰理 SDK 内部代码的长期稳定与最小化开销;POSIX 层保证开源第三方代码的可移植性;两者共享同一个 FreeRTOS 内核调度器,互不冲突。

Architecture

flowchart TD
    subgraph sg_App["应用层 Application"]
        App["音频/蓝牙/网络/用户应用"]
        Example["os_api 示例<br/>pthreads_api 示例"]
    end

    subgraph sg_API["系统调用层 API Layer"]
        OSAPI["杰理 os_api 抽象层<br/>os_api.h / os_cfg.h"]
        POSIX["FreeRTOS-Plus-POSIX<br/>FreeRTOS_POSIX.h"]
        PThread["pthread / mqueue / sem / timer"]
    end

    subgraph sg_Kernel["内核层 FreeRTOS Kernel"]
        Sched["任务调度器 Task Scheduler"]
        Sync["信号量 semphr.h"]
        Queue["队列 queue.h"]
        Event["事件组 event_groups.h"]
        Tick["Tick 时钟"]
    end

    subgraph sg_HW["硬件层 Hardware"]
        CPU["AC79NN CPU 核"]
        Timer["硬件定时器"]
    end

    App --> OSAPI
    Example --> OSAPI
    Example --> POSIX
    POSIX --> PThread
    App --> PThread
    PThread --> Sched
    OSAPI --> Sched
    OSAPI --> Sync
    OSAPI --> Queue
    OSAPI --> Event
    Sched --> Tick
    Sync --> Tick
    Queue --> Tick
    Tick --> Timer
    Sched --> CPU

分层职责说明:

  • 应用层通过两种入口访问操作系统:SDK 业务代码走 os_api(如 os_task_create),第三方/标准代码走 POSIX(如 pthread_create)。两者在示例工程中并存,例如 apps/common/example/system/os/pthreads_api/main.c 同时调用 pthread_* 与 os_time_dly。
  • os_api 层是杰理 SDK 事实上的"系统调用"边界,接口签名稳定、不随 FreeRTOS 版本变化,且大多可直接映射到内核对象(任务→TCB、信号量→semphr、队列→queue)。
  • POSIX 层(Amazon FreeRTOS POSIX V1.1.0)以 FreeRTOS_POSIX.h 为统一入口头文件,必须先于其他 POSIX 头文件包含(见 FreeRTOS_POSIX.h),它依次引入 portable 配置、FreeRTOS 内核头文件与内部数据结构。
  • 内核层提供真正的调度与同步原语,所有上层接口最终都落到 FreeRTOS 的 task、semphr、queue、event_groups 上。

核心机制:os_api 抽象层

设计意图

os_api.h 位于 include_lib/system/os/,是杰理 SDK 对操作系统能力的统一封装边界。它只依赖三个基础头文件:generic/typedef.h(基本类型)、os/os_cpu.h(CPU/临界区)、os/os_error.h(错误码)、os/os_type.h(类型定义),并通过 extern "C" 保证 C/C++ 混编安全:

#include "generic/typedef.h"
#include "os/os_cpu.h"
#include "os/os_error.h"
#include "os/os_type.h"

来源:os_api.h

这种"只依赖自包含类型头、不暴露内核头文件"的设计,使得上层模块在编译期与 FreeRTOS 完全解耦——更换内核(例如替换为其他 RTOS)时,只需重写 os_api 的实现,业务代码零改动。

任务消息类型:消息队列的分类体系

os_api 将投递到任务消息队列的消息按语义划分为四类,高位作为类型标志:

#define Q_MSG           0x100000	/*!< 普通消息 */
#define Q_EVENT         0x200000	/*!< 事件消息 */
#define Q_CALLBACK      0x300000	/*!< 回调消息 */
#define Q_USER          0x400000	/*!< 用户消息 */

来源:os_api.h

设计意图:不同语义的消息用同一个队列承载,接收端可以按类型位(与 Q_MSG 等掩码相与)快速分流处理。Q_CALLBACK 常被用于把"函数指针 + 参数"打包投递到指定任务上下文执行,避免跨任务直接调用带来的竞态。

任务创建:动态与静态两种栈

os_api 提供两种任务创建接口,签名一致,区别在于任务控制块(TCB)+ 任务栈 + 消息队列内存的来源:

int os_task_create(void (*func)(void *parm),
                   void *parm,
                   u8 prio,
                   u32 stk_size,
                   int q_size,
                   const char *name);

int os_task_create_static(void (*func)(void *parm),
                          void *parm,
                          u8 prio,
                          u32 stk_size,
                          int q_size,
                          const char *name,
                          u8 *tcb_stk_q);

来源:os_api.h

要点解读:

  • prio 为优先级,stk_size 与 q_size 均以 4 字节(一个字)为单位——这是嵌入式场景常见的约定,需要换算成字节时必须乘 4。
  • os_task_create 由内核从堆中动态分配三块内存;os_task_create_static 由调用者传入一块 tcb_stk_q 静态内存块(包含 TCB 空间 + 栈空间 + 队列空间),用于系统启动早期堆尚未就绪、或对确定性要求极高的关键任务。
  • 每个任务自带一个消息队列(q_size),配合 os_taskq_post / __os_taskq_post 使用——这是杰理 SDK 任务间通信的主要范式(见下文"核心流程")。

任务归属与删除标志

#define OS_TASK_DEL_REQ 0x01u   /*!< 删除请求 */
#define OS_TASK_DEL_RES 0x02u   /*!< 删除响应 */
#define OS_TASK_DEL_OK  0x03u   /*!< 删除完成 */

#define OS_TASK_SELF    (const char *)0x1
#define OS_TASK_FATHER  (const char *)0x2

来源:os_api.h

设计意图:嵌入式 RTOS 中"任务主动删除自己"或"父任务删除子任务"都存在资源释放时序问题(栈可能正在被使用)。OS_TASK_DEL_REQ/RES/OK 三态握手机制让删除变成请求-应答式协作流程:请求方发删除请求,目标任务在安全的调度点响应,确认 OS_TASK_DEL_OK 后才真正回收资源。OS_TASK_SELF / OS_TASK_FATHER 用于指定删除目标为"当前任务"或"父任务"。

初始化与启动流程

os_api 暴露三个启动阶段接口:

void os_init(void);       // 初始化操作系统
void os_init_tick(int);   // 初始化时钟节拍
void os_start(void);      // 开始调度

来源:os_api.h

典型启动序列为:os_init() 建立内核对象 → os_init_tick(tick_rate) 配置 tick 周期 → 创建首个应用任务(通常用 os_task_create 静态/动态创建)→ os_start() 交出控制权,由 FreeRTOS 调度器接管,此后系统完全由 tick 驱动。

sequenceDiagram
    participant B as Boot/启动代码
    participant A as os_api 层
    participant K as FreeRTOS 内核
    participant T as 应用任务

    B->>A: os_init()
    A->>K: 初始化内核数据结构
    B->>A: os_init_tick(rate)
    A->>K: 配置 SysTick/硬件定时器
    B->>A: os_task_create(func, parm, prio, stk, q, name)
    A->>K: 分配 TCB+栈+队列,挂入就绪链表
    B->>A: os_start()
    A->>K: 启动调度器 (vTaskStartScheduler)
    K-->>T: 首次上下文切换,进入 func(parm)
    T->>T: 运行业务逻辑

POSIX 兼容层:FreeRTOS-Plus-POSIX

统一入口头文件

POSIX 层的总入口是 FreeRTOS_POSIX.h(Amazon FreeRTOS POSIX V1.1.0 移植)。它按固定顺序引入平台配置、FreeRTOS 内核头与内部类型,因此所有 POSIX 源文件必须最先包含它:

#include "FreeRTOS_POSIX_portable.h"
#include "FreeRTOS_POSIX_portable_default.h"

#include "FreeRTOS/FreeRTOS.h"
#include "FreeRTOS/event_groups.h"
#include "FreeRTOS/semphr.h"

#include "FreeRTOS_POSIX/sys/types.h"
#include "FreeRTOS_POSIX_internal.h"

来源:FreeRTOS_POSIX.h

该层位于 include_lib/system/os/POSIX/FreeRTOS-Plus-POSIX/include/,配套 portable/ 下的 FreeRTOS_POSIX_portable.h / FreeRTOS_POSIX_portable_default.h 负责平台相关配置(如 pthread_t 与 FreeRTOS TaskHandle_t 的映射、超时转换宏),这是把标准 POSIX 语义(阻塞、超时、优先级)翻译到 FreeRTOS 原语的关键适配点。

提供的 POSIX 能力

  • pthread:pthread_create / pthread_mutex_* / pthread_exit / pthread_join 等线程与互斥量接口,线程由 FreeRTOS 任务承载,pthread_t 内部映射到 TaskHandle_t。
  • POSIX 消息队列:mqd_t、mq_open / mq_send / mq_receive,底层映射到 FreeRTOS 队列。
  • POSIX 信号量与定时器:semaphore 与 timer 接口。

SDK 中该层的主要消费者包括:apps/common/example/third_party/ 下的 coremark(core_portme_posix_overrides.h)、mDNS(lib/net/mdns/code/mDNSPosix.c)、lvgl 文件系统驱动(lv_fs_posix.c)等——它们以标准 POSIX 代码形式引入,通过兼容层直接运行在 FreeRTOS 之上。

核心流程:任务间消息通信

杰理 SDK 中任务间通信的典型范式是 os_taskq_post 消息投递:任意上下文(中断、其他任务、回调)向目标任务的消息队列投递消息,目标任务在自身的消息循环中取出并分发处理。__os_taskq_post 是底层实现入口,按任务名定位目标队列:

int __os_taskq_post(const char *name, int type, int argc, int *argv);

来源:os_api.h

flowchart TD
    Sender["发送方<br/>中断/任务/回调"] -->|"os_taskq_post(name, type, argc, argv)"| Q{"目标任务<br/>队列是否已满?"}
    Q -->|"否"| Enqueue["消息写入目标任务队列<br/>(Q_MSG/Q_EVENT/Q_CALLBACK/Q_USER)"]
    Q -->|"是"| Ret["返回错误/阻塞等待"]
    Enqueue --> Wake["唤醒目标任务 (调度器)"]
    Wake --> Loop["目标任务消息循环<br/>os_taskq_accept 取出消息"]
    Loop --> Type{"按 type 高位分流"}
    Type -->|"Q_MSG"| HandleMsg["处理普通消息"]
    Type -->|"Q_CALLBACK"| HandleCb["在任务上下文执行回调"]
    Type -->|"Q_EVENT"| HandleEvt["处理事件"]
    Type -->|"Q_USER"| HandleUser["处理用户自定义消息"]

设计意图:所有跨任务交互都收敛到"队列 + 消息循环",避免多任务直接共享变量带来的竞态;消息类型位让一个队列承载多种语义,接收端分流逻辑统一、扩展新消息类型只需新增一个类型位与分支。

核心流程:POSIX 线程互斥示例

SDK 自带 pthreads_api 示例工程(apps/common/example/system/os/pthreads_api/main.c),演示标准 POSIX 线程在 RTOS 上运行。其互斥锁测试的流程为:初始化 pthread_mutex_t → 创建两个线程 func1/func2 → 每个线程 pthread_mutex_lock 后逐字符打印字符串 → pthread_mutex_unlock 释放。两个线程竞争同一把锁,保证打印互不交错;线程创建后主流程即返回(pthread_join 被注释掉),体现嵌入式场景"创建后由调度器管理、不阻塞等待回收"的用法。

sequenceDiagram
    participant M as main (posix_mutex_test)
    participant P as POSIX 兼容层
    participant K as FreeRTOS 内核
    participant T1 as 线程 func1 (pthread_t p1)
    participant T2 as 线程 func2 (pthread_t p2)

    M->>P: pthread_mutex_init(&mutex, NULL)
    M->>P: pthread_create(&p1, NULL, func1, str1)
    P->>K: 创建任务,绑定函数指针
    M->>P: pthread_create(&p2, NULL, func2, str2)
    P->>K: 创建任务,绑定函数指针
    K-->>T1: 调度 func1 运行
    T1->>P: pthread_mutex_lock(&mutex)
    P->>K: 获取内核互斥量
    T1->>T1: 逐字符打印 (临界区)
    K-->>T2: 调度 func2,尝试 lock 被阻塞
    T1->>P: pthread_mutex_unlock(&mutex)
    P->>K: 释放互斥量,唤醒 T2
    K-->>T2: T2 获得锁,继续打印

Usage Examples

示例 1:创建动态任务(os_api 层)

从 os_api.h 的接口契约可直接看到任务的创建方式——指定入口函数、参数、优先级、栈大小(字为单位)、队列大小与任务名:

int os_task_create(void (*func)(void *parm),
                   void *parm,
                   u8 prio,
                   u32 stk_size,
                   int q_size,
                   const char *name);

来源:os_api.h

示例 2:POSIX 互斥锁测试(pthreads_api 示例)

static void posix_mutex_test(void)
{
    char *str1 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    char *str2 = "abcdefghijklmnopqrstuvwxyz";
    int err;

    pthread_mutex_init(&mutex, NULL);

    if ((err = pthread_create(&p1, NULL, func1, str1)) != 0) {
        printf("[0]pthread_create fail\n");
    }

    if ((err = pthread_create(&p2, NULL, func2, str2)) != 0) {
        printf("[1]pthread_create fail\n");
    }

    /* pthread_join(p1, NULL); */
    /* pthread_join(p2, NULL); */
}

来源:pthreads_api/main.c

该示例同时印证了两个事实:POSIX pthread_* 接口在此 SDK 中真实可用;os_time_dly 等杰理 os_api 接口可与 POSIX 接口混用(示例文件第 16 行声明 extern void os_time_dly(int tick);)。

示例 3:POSIX 消息队列发送线程(pthreads_api 示例)

static mqd_t mqID;

//发送线程
static void *thread_send(void *args)
{
    char msg[] = "This is a message for test!";
    mqd_t *sendID = (mqd_t *)args;

    while (1) {
        if (mq_send(*sendID, msg, sizeof(msg), 0) < 0) {
            printf("send msg err!\n");
            //终止当前线程
            pthread_exit(NULL);
        }

        os_time_dly(100);
    }

    return (void *)0;
}

来源:pthreads_api/main.c

要点:mq_send 失败(如队列满)时调用 pthread_exit(NULL) 终止自身线程,这是 POSIX 线程在出错路径上的标准退出方式;循环内用 os_time_dly(100) 节流,避免忙等耗尽 CPU——os_time_dly 的参数以 tick 为单位。

Configuration Options

RTOS 组件的裁剪配置集中在 include_lib/system/os/os_cfg.h。该头文件以宏开关控制各内核对象是否编译生成代码,关闭不需要的功能可减小 ROM/RAM 占用——这是嵌入式 SDK 典型的"按需裁剪"配置策略。

宏定义类型默认值说明
OS_TASKQ_ENint1使能/关闭任务消息队列(QUEUES)代码生成
OS_TASKQ_ACCEPT_ENint1包含 OSTaskQAccept()(非阻塞取消息)
OS_TASKQ_PEND_ENint1包含 OSTaskQPend()(阻塞取消息)
OS_TASKQ_FLUSH_ENint1包含 OSTaskQFlush()(清空队列)
OS_TASKQ_POST_ENint1包含 OSTaskQPost()(投递消息)
OS_TASKQ_POST_FRONT_ENint1包含 OSTaskQPostFront()(队首投递,高优先级消息)
OS_TASKQ_QUERY_ENint1包含 OSTaskQQuery()(查询队列状态)
OS_SEM_ENint1使能/关闭信号量(SEMAPHORES)代码生成
OS_SEM_ACCEPT_ENint1包含 OSSemAccept()(非阻塞获取信号量)
OS_SEM_DEL_ENint1包含 OSSemDel()(删除信号量)
OS_SEM_QUERY_ENint1包含 OSSemQuery()(查询信号量计数)
OS_SEM_SET_ENint1包含 OSSemSet()(重置信号量计数)

来源:os_cfg.h

裁剪原则:产品固件若未用到任务队列或信号量,可将对应 *_EN 置 0 减小代码体积;示例/调试固件保持全部使能。注意 OS_TASKQ_* 与 OS_SEM_* 是两组独立开关,且每个能力还有子开关(*_ACCEPT_EN、*_POST_EN 等),可做到细粒度裁剪。

API Reference

以下列出 os_api 层最核心的接口(完整列表见 os_api.h)。

void os_init(void)

初始化操作系统。必须在任何其他 OS 调用之前、os_start() 之前调用一次。

void os_init_tick(int tick_rate)

初始化 OS 时钟节拍(tick)。tick_rate 决定调度时基粒度;配置错误会导致 os_time_dly、超时等待的实际时长与预期不符。

void os_start(void)

启动调度器。调用后控制权移交 RTOS,此函数不返回;所有应用任务应在调用前创建完毕。

int os_task_create(void (*func)(void *parm), void *parm, u8 prio, u32 stk_size, int q_size, const char *name)

创建动态任务(TCB + 栈 + 消息队列从堆分配)。

参数:

  • func:任务入口函数指针
  • parm:传给入口函数的私有指针
  • prio:任务优先级(数值约定见内核文档)
  • stk_size:栈大小,以 4 字节为单位
  • q_size:消息队列大小,以 4 字节为单位
  • name:任务名字符串,用于调试与 os_current_task() / os_taskq_post 定位

返回: 0 成功;-1 失败(如内存不足)。

int os_task_create_static(void (*func)(void *parm), void *parm, u8 prio, u32 stk_size, int q_size, const char *name, u8 *tcb_stk_q)

创建静态任务。与 os_task_create 差异仅在最后一个参数:调用者必须提供一块足够容纳 TCB + 栈 + 队列的静态内存 tcb_stk_q。用于启动早期或确定性关键任务。

const char *os_current_task(void)

返回当前运行任务的名称。用于日志定位与断言,典型用法是打印"当前在哪个任务里"。

int __os_taskq_post(const char *name, int type, int argc, int *argv)

向名为 name 的任务消息队列投递一条消息。type 使用 Q_MSG/Q_EVENT/Q_CALLBACK/Q_USER 类型位(可叠加用户位),argc/argv 携带消息参数。上层通常封装为 os_taskq_post 宏/包装函数使用。

返回: 投递结果(0 成功;非 0 失败,如目标任务不存在或队列满)。

同步原语族(按 os_cfg.h 裁剪)

  • 信号量:os_sem_create / os_sem_post / os_sem_pend / os_sem_accept / os_sem_del / os_sem_set / os_sem_query(对应 OSSem*,由 OS_SEM_EN 系列开关控制);
  • 互斥量:os_mutex_create / os_mutex_pend / os_mutex_post 等;
  • 队列:os_q_create / os_q_send / os_q_post / os_q_pend 等;
  • 删除标志:OS_DEL_NO_PEND / OS_DEL_ALWAYS 控制删除时是否强制等待(见 os_api.h 第 31-32 行)。

说明:由于 os_api 为预编译库(include_lib),信号量/互斥量/队列的完整函数签名在头文件中的声明与上述任务接口同风格;具体实现在库中,本页以头文件声明的契约为准。

失败模式、边界情况与并发

任务删除的时序问题(thread_can_not_kill_test)

SDK 专门提供 apps/common/example/system/os/os_api/thread_can_not_kill_test.c 用例,验证"某些任务不可被杀"的场景。要点:任务正在持有锁、处于临界区或内核资源中时,强制删除会造成资源泄漏或死锁。os_api 的 OS_TASK_DEL_REQ/RES/OK 三态协议正是为了把删除变为协作式:任务必须在安全点确认响应,才能完成回收。业务代码应避免跨任务 free 对方栈/TCB 的行为,优先使用消息通知任务自行退出。

栈大小与队列大小不足

  • stk_size 过小 → 栈溢出(FreeRTOS 支持栈高水位检查,但过浅会先踩坏相邻内存)。调试期应通过任务名(os_current_task)定位溢出任务。
  • q_size 过小 → os_taskq_post / mq_send 返回失败。POSIX 示例中对 mq_send 失败调用 pthread_exit 退出线程(见上文示例 3),说明队列满在嵌入式场景是可预期的运行时错误,必须显式处理而非忽略。

优先级反转与互斥量

使用 pthread_mutex_* / os_mutex_* 时,若低优先级任务持有锁、高优先级任务等待,会出现优先级反转。FreeRTOS 的互斥量默认带优先级继承,但 POSIX 兼容层对 pthread_mutex 的映射行为取决于 FreeRTOS_POSIX_portable.h 的配置,需在移植配置中确认。高实时性路径建议直接使用 os_api 原语并遵循 SDK 既有优先级约定。

中断上下文约束

os_taskq_post 支持从中断上下文投递(队列机制天然支持),但所有阻塞型 pend 接口(os_sem_pend、os_q_pend、pthread_mutex_lock)禁止在中断上下文调用。os_api 提供 os_sem_accept / os_taskq_accept 等非阻塞变体(由 OS_SEM_ACCEPT_EN、OS_TASKQ_ACCEPT_EN 开关控制)供中断/高实时上下文使用。

并发一致性

  • 多任务共享变量必须通过互斥量/临界区保护;消息队列是推荐的跨任务通信方式。
  • 静态任务内存块(tcb_stk_q)由调用者管理生命周期,任务未退出前不得释放或复用该内存。

性能与运维考量

  • 裁剪开关:发布固件前按需关闭 os_cfg.h 中未用到的功能(如 OS_TASKQ_*、OS_SEM_* 子开关),直接减少代码体积。
  • 栈尺寸优化:stk_size/q_size 以 4 字节为单位,配置过大会浪费 SRAM;建议用内核栈水位统计校准到"峰值 + 安全余量"。
  • tick 粒度:os_init_tick 的节拍直接决定 os_time_dly 的精度与调度开销,功耗敏感场景可降低 tick 频率,实时性敏感场景则需提高。
  • 任务命名规范:name 参数贯穿调试(os_current_task)、消息投递(os_taskq_post)与日志,统一命名规范可显著降低多任务系统排障成本。

扩展点

  1. 更换/升级内核:业务代码只依赖 os_api.h,替换内核只需重新实现 os_api 库,接口契约(os_cfg.h 宏、任务/信号量/队列语义)保持即可。
  2. POSIX 平台适配:FreeRTOS_POSIX_portable.h / FreeRTOS_POSIX_portable_default.h 是 FreeRTOS-Plus-POSIX 的平台适配点,涉及类型映射与超时换算,接入新芯片/新工具链时改这里。
  3. 新增消息类型:Q_MSG/Q_EVENT/Q_CALLBACK/Q_USER 的高位类型体系可扩展用户自定义位,在消息循环中新增分支即可。
  4. 静态内存策略:对确定性要求高的任务(音频、协议栈关键路径)使用 os_task_create_static,避免运行时堆分配失败。

测试

SDK 提供两类现成测试入口:

  • apps/common/example/system/os/os_api/:main.c(总入口)、mutex_test.c、sem_test.c、queue_test.c、static_task_test.c、thread_can_not_kill_test.c,覆盖任务创建(动态/静态)、互斥量、信号量、队列与任务删除边界;
  • apps/common/example/system/os/pthreads_api/main.c:通过 USE_PTHREAD_API_TEST 宏使能,内含 POSIX_MUTEX_TEST / POSIX_SEM_TEST / POSIX_QUEUE_TEST 三种可切换用例,验证 POSIX 兼容层的互斥量、信号量与消息队列(mqd_t)。

这些用例同时充当"API 使用规范"的活文档:移植新平台后先跑通它们,可快速验证 RTOS 与 POSIX 层功能完整性。

Related Links

  • os_api.h(核心接口声明)
  • os_cfg.h(RTOS 裁剪配置)
  • FreeRTOS_POSIX.h(POSIX 层统一入口)
  • pthreads_api 示例
  • os_api 测试示例目录
  • 相关页面:系统初始化与启动流程、驱动与中断管理、内存管理(各页面按目录导航查看)
Next
C/C++ 运行时库