LOADING
1395 字
7 分钟
ChibiOS/RT 系统管理与调度器

调度器配置#

ChibiOS/RT 的调度器行为通过 chcfg.h 中的宏配置。这些配置在编译时确定,直接影响系统性能和资源占用。

优先级数量#

chcfg.h
#define CH_CFG_NUM_PRIORITIES 32
  • 默认值通常为 32,可按需调整
  • 增加优先级数量会增加内核 RAM 占用
  • 每增加 8 个优先级,约增加 256 字节 RAM

轮询时间片#

#define CH_CFG_TIME_QUANTUM 20
  • 同优先级线程的时间片长度(单位:tick)
  • 设为 0 表示禁用时间片轮转,仅使用时间片让出
  • 建议值:10-100 tick

线程额外栈空间#

#define CH_CFG_THREAD_EXTRA_STACK 128
  • 为每个线程额外分配的栈空间(字节)
  • 用于存放线程局部存储、调试信息等

内核堆大小#

#define CH_CFG_HEAP_SIZE (1024 * 2)
  • 动态内存分配使用的堆大小
  • chThdCreateFromHeap 从该堆分配内存

其他关键配置#

/* 虚拟定时器数量 */
#define CH_CFG_VIRTUAL_TIMERS 16
/* 消息队列大小 */
#define CH_CFG_MSG_CACHE_SIZE 2
/* 空闲钩子(用于低功耗) */
#define CH_CFG_IDLE_ENTER_HOOK() idle_enter_hook()
#define CH_CFG_IDLE_LEAVE_HOOK() idle_leave_hook()

系统管理接口#

系统锁与解锁#

系统锁用于保护临界区,防止调度器抢占:

void critical_section(void) {
chSysLock(); /* 锁定调度器,关闭中断 */
/* 临界区代码 */
volatile uint32_t count = 0;
for (int i = 0; i < 1000; i++) {
count++;
}
chSysUnlock(); /* 解锁调度器,恢复中断 */
}

chSysLock/chSysUnlock 的作用:

操作效果
chSysLock()禁用可屏蔽中断,阻止调度
chSysUnlock()恢复可屏蔽中断,允许调度
chSysLockFromISR()在 ISR 中锁定系统
chSysUnlockFromISR()在 ISR 中解锁系统

CPU 使用率测量#

/* 启用 CPU 使用率测量(需配置 CH_CFG.GetCurrentMethodHook) */
void sysinit(void) {
/* 通常在空闲线程中调用 */
}
/* 获取 CPU 使用率(百分比,0-100) */
void idle_hook(void) {
uint32_t usage = chSysGetCPUUsage();
/* usage 为 0-100 的整数百分比 */
if (usage > 80) {
/* CPU 负载过高警告 */
}
}

空闲钩子#

空闲钩子在空闲线程中周期性调用,可用于低功耗管理:

chcfg.h
#define CH_CFG_IDLE_ENTER_HOOK() do { \
__WFI(); /* 进入低功耗等待 */ \
} while(0)
#define CH_CFG_IDLE_LEAVE_HOOK() do { \
/* 从低功耗唤醒 */ \
} while(0)

功耗管理#

结合空闲钩子实现动态功耗管理:

static void idle_enter_hook(void) {
/* 关闭外设时钟 */
RCC->AHB1ENR &= ~RCC_AHB1ENR_GPIOAEN;
/* 进入 Sleep 模式 */
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__WFI();
}
static void idle_leave_hook(void) {
/* 恢复外设时钟 */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
}

运行时专家模式#

ChibiOS/RT 提供多种运行时诊断工具,帮助开发者调试和优化系统。

调试寄存器#

启用内核调试器可检测运行时错误:

chcfg.h
#define CH_CFG_USE_KERNEL_DEBUG TRUE

检测的错误包括:

  • 从非线程上下文调用线程 API
  • 在 ISR 中调用非 ISR 安全的 API
  • 无效的线程状态转换

栈溢出检查#

chcfg.h
#define CH_CFG_USE_STACKCHECK TRUE

启用后,每次上下文切换时检查线程栈是否溢出工作区边界。栈溢出是嵌入式系统中最常见的 bug 之一,建议开发阶段始终启用。

栈使用测量#

/* 获取线程栈使用量(已用字节) */
thread_t *tp = chThdGetSelfX();
size_t used = chThdGetStackUsed(tp);
/* 获取线程栈空间总量 */
size_t total = chThdGetStackSize(tp);
/* 计算使用百分比 */
uint32_t percent = (used * 100) / total;

也可以统计所有线程的栈使用情况:

void check_all_stacks(void) {
thread_descriptor_t *tdp;
/* 遍历所有已注册线程 */
for (tdp = chRegFirstThread();
tdp != NULL;
tdp = chRegNextThread(tdp)) {
size_t used = chThdGetStackUsed(tdp->get_stackp());
printf("Thread: %s, Stack used: %u bytes\n",
tdp->get_name(), used);
}
}

性能测量钩子#

chcfg.h
#define CH_CFG_USE_performance_hook TRUE
/* 上下文切换钩子 */
void ctxsw_hook(thread_t *ntp, thread_t *otp) {
/* ntp: 即将运行的线程 */
/* otp: 刚被换出的线程 */
/* 可用于记录切换频率、统计等 */
}

SMP 系统管理#

多核配置#

chcfg.h
#define CH_CFG_SMP_NESTED_ENABLE FALSE
#define CH_CFG_SMP_NUM_THREADS 4
#define CH_CFG_SMP_REQUIRED_CORES 2
  • CH_CFG_SMP_NUM_THREADS:SMP 系统中线程总数上限
  • CH_CFG_SMP_REQUIRED_CORES:必须在线的核心数

OS 实例#

每个核心需要独立的 OS 实例,包含自己的调度器和内核数据结构:

#include "ch.h"
/* 为每个核心定义 OS 实例 */
static OS_INSTANCE(os_core0);
static OS_INSTANCE(os_core1);
/* 核心 0 的主函数 */
void core0_main(void) {
os_instance_init(&os_core0);
os_instance_set_active(true);
/* 创建核心 0 的线程 */
chThdCreateStatic(waThread0,
sizeof(waThread0),
NORMALPRIO,
thread0_func,
NULL);
chThdExit();
}
/* 核心 1 的主函数 */
void core1_main(void) {
os_instance_init(&os_core1);
os_instance_set_active(true);
chThdCreateStatic(waThread1,
sizeof(waThread1),
NORMALPRIO,
thread1_func,
NULL);
chThdExit();
}

核心 ID#

/* 获取当前核心 ID */
syscoreid_t core_id = os_instance_get_core_id();
/* 根据核心 ID 执行不同逻辑 */
void per_core_init(void) {
syscoreid_t id = os_instance_get_core_id();
if (id == 0) {
/* 主核心初始化 */
} else {
/* 从核心初始化 */
}
}

Tick 处理#

频率配置#

chcfg.h
#define CH_CFG_ST_RESOLUTION 16
#define CH_CFG_ST_FREQUENCY 1000 /* 1 kHz tick */
  • CH_CFG_ST_FREQUENCY:系统 tick 频率(Hz)
  • 典型值:1000(1ms 分辨率)或 10000(100μs 分辨率)

虚拟定时器处理#

虚拟定时器基于系统 tick 实现,用于超时管理:

/* 定义虚拟定时器 */
static virtual_timer_t vt1;
/* 定时器回调函数 */
static void vt1_callback(void *arg) {
/* 超时处理 */
LED_Toggle();
}
/* 启动定时器:500ms 后触发 */
void start_timer(void) {
chVTSet(&vt1, MS2ST(500), vt1_callback, NULL);
}
/* 取消定时器 */
void stop_timer(void) {
chVTReset(&vt1);
}

延迟超前处理#

ChibiOS/RT 支持延迟超前处理(Deferred Timeout Processing),在 tick ISR 中不直接处理超时,而是标记后延迟到线程上下文处理:

chcfg.h
#define CH_CFG_USE_TM TRUE /* 启用时间管理 */

这种机制减少了中断延迟,适用于超时处理较复杂或需要调用线程安全 API 的场景。

总结#

ChibiOS/RT 的调度器和系统管理机制提供了丰富的配置选项和诊断工具。合理配置优先级数量、时间片、堆大小等参数,结合 CPU 使用率测量和栈检查,可以构建出高效、可靠的嵌入式实时系统。SMP 支持和虚拟定时器则为更复杂的应用场景提供了扩展能力。

ChibiOS/RT 系统管理与调度器
/posts/chibios-rt-scheduler/
作者
JJZBQA
发布于
2024-12-16
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时