摘要 :杰理 AC792N 作为梧桐三代双核 WiFi + 蓝牙 SoC,SDK 提供两套线程 API:
os_xxx标准系统 API、thread_xxx双核绑定增强 API。本文带你彻底搞懂两套 API 的用法、区别、任务调度、双核绑定、优先级堆栈配置,附带可直接移植的工程代码,解决 AC792N 线程开发常见坑。
一、前言
在杰理 AC792N 双核 SDK 开发中,你一定见过这两类线程 API:
os_xxx:标准 FreeRTOS 封装,通用任务创建 / 调度thread_xxx:杰理增强线程 API,支持CPU0/CPU1 双核绑定、自动初始化、统一管理
很多开发者混用、错用,导致:
- 任务跑不起来
- 双核绑定失效
- 栈溢出 / 死机
- 优先级混乱
本文一次性讲透:用法 + 区别 + 双核绑定 + 实战代码 + 避坑指南。
二、基础概念(必看)
AC792N 是AMP 双核架构:
-
CPU0:运行 FreeRTOS,负责系统、协议、业务
-
CPU1:裸机 / 轻量任务,负责音频、视频、算法运算
-
os_xxx:面向 CPU0 标准任务 -
thread_xxx:支持指定 CPU0/CPU1 运行,SDK 推荐官方用法
三、os_xxx 标准线程 API 详解(CPU0 专用)
3.1 核心 API 一览
c
运行
// 创建任务
os_task_t os_task_create(
void (*entry)(void *arg), // 入口函数
void *arg, // 入口参数
const char *name, // 任务名
u32 stack_size, // 栈大小(字节)
u8 priority // 优先级:0~15,越大越高
);
// 任务延时
void os_task_delay(u32 ms);
// 挂起/恢复
void os_task_suspend(os_task_t task);
void os_task_resume(os_task_t task);
// 删除任务
void os_task_delete(os_task_t task);
3.2 os_xxx 任务创建示例(可直接用)
c
运行
// 任务入口函数
void app_task(void *arg)
{
while (1) {
printf("app_task running...\n");
os_task_delay(1000); // 延时1秒
}
}
// 在初始化时调用创建
void app_init(void)
{
// 创建:入口、参数、名字、栈大小、优先级
os_task_create(app_task, NULL, "app_task", 512, 3);
}
3.3 os_xxx 特点
- 标准 FreeRTOS 封装
- 只能运行在 CPU0
- 简单、轻量
- 不支持 CPU1 绑定
- 适合普通业务、小任务
四、thread_xxx 增强线程 API(双核绑定神器)
thread_xxx 是杰理专为双核 AMP 架构 设计的高级任务管理 API,也是 SDK 最主流、最推荐的任务创建方式。
4.1 核心能力
- 支持指定任务跑在 CPU0 或 CPU1
- 支持静态配置表
task_info_table - 系统自动调度创建
- 自带消息队列
- 支持双核中断、共享内存配套使用
4.2 核心结构体(最重要)
c
运行
struct task_info {
const char *name; // 任务名
u8 priority; // 优先级 0~15
u8 cpu_id; // 0=CPU0 1=CPU1 2=自动
u16 stack_size; // 栈大小
u16 msg_size; // 消息队列深度
void (*entry)(void *arg);// 入口函数
};
4.3 thread_xxx 任务创建标准写法(AC792N 官方规范)
c
运行
// 任务入口函数
void test_task(void *arg)
{
while (1) {
printf("test task run... cpu:%d\n", sys_cpu_get_id());
os_task_delay(500);
}
}
// 任务配置表(系统自动识别创建)
const struct task_info task_info_table[] = {
// 名字 优先级 CPU 栈 消息队列 入口
{ "test_task", 3, 0, 512, 32, test_task }, // CPU0运行
{ "cpu1_task", 4, 1, 768, 32, cpu1_task }, // CPU1运行
{ NULL, 0, 0, 0, 0, NULL }, // 必须结尾
};
4.4 thread_xxx 常用 API
c
运行
// 获取当前任务句柄
thread_t thread_self(void);
// 延时(等价os_delay)
void thread_delay(u32 ms);
// 挂起/恢复
void thread_suspend(thread_t thread);
void thread_resume(thread_t thread);
// 发送消息到任务
int thread_msg_send(thread_t thread, u32 msg, u32 param);
五、os_xxx 与 thread_xxx 到底有什么区别?(面试常问)
表格
| 维度 | os_xxx | thread_xxx |
|---|---|---|
| 运行核心 | 仅 CPU0 | CPU0/CPU1 可指定 |
| 双核绑定 | 不支持 | 支持(cpu_id 字段) |
| 任务管理 | 手动创建 | 配置表自动创建 |
| 消息队列 | 需手动创建 | 自动分配 |
| 适用场景 | CPU0 简单任务 | 双核业务、音视频、框架任务 |
| SDK 推荐度 | 低 | 极高(官方标准) |
一句话总结:
- 简单小任务 →
os_xxx - 业务逻辑、双核、音频、视频 → thread_xxx
六、优先级与栈大小配置规则(避坑关键)
6.1 优先级规则(0~15)
- 0:最低
- 1~5:业务任务(推荐)
- 6~10:系统、协议、音频
- 11~15:最高优先级(中断级、驱动)
6.2 栈大小经验值
- 简单打印任务:384~512
- 协议 / UI:512~768
- 音频解码 / 视频:768~2048
- 算法 / FFT:2048+
栈太小 → 死机、重启、跑飞栈太大 → 浪费内存
七、实战:CPU0 + CPU1 双核任务同时运行
7.1 CPU0 任务
c
运行
void cpu0_task(void *arg)
{
while (1) {
printf("cpu0 task run...\n");
os_task_delay(1000);
}
}
7.2 CPU1 任务
c
运行
void cpu1_task(void *arg)
{
while (1) {
// CPU1专门做实时运算:音频、算法、视频
audio_decode_process();
os_task_delay(10);
}
}
7.3 任务表配置
c
运行
const struct task_info task_info_table[] = {
{ "cpu0_task", 3, 0, 512, 32, cpu0_task },
{ "cpu1_task", 4, 1, 768, 32, cpu1_task },
{ NULL, 0, 0, 0, 0, NULL },
};
AC792N 双核真正价值:CPU0 管系统,CPU1 管算力!
八、常见问题与避坑指南
8.1 任务创建了不运行?
- 优先级太低,被高优先级抢占
- 栈溢出,系统直接崩溃
- CPU1 任务未启动(需 CPU0 唤醒)
- 入口函数死等锁 / 消息
8.2 CPU1 任务不跑?
- 检查
cpu_id=1是否配置 - 检查 SDK 是否开启双核:
CPU_CORE_NUM=2 - CPU1 不能使用依赖 CPU0 系统深度依赖
8.3 延时不精准?
- 任务被抢占
- 关中断太久
- 高优先级任务死循环
九、总结
- os_xxx:CPU0 标准轻量任务,简单场景使用
- thread_xxx :杰理增强 API,支持双核绑定,工程必用
- AC792N 双核价值:
cpu_id=0/1实现系统与实时算力分离 - 优先级、栈大小、CPU 绑定是任务稳定三要素
开发规范建议:
- 框架 / 业务 / 双核任务 → thread_xxx
- 小工具 / 简易任务 → os_xxx