3. 配置系统时钟节拍
任务目标
在Zephyr项目中,通过设备树和Kconfig将系统时钟节拍(SYSTEM_CLOCK_TICK_FREQ)从默认值修改为更高频率,并编写一个简单的延时测试任务,观察节拍频率变化对k_sleep()实际延时精度的影响。
环境与依赖
- Zephyr RTOS 3.x(以native_sim或qemu_x86为目标板验证)
- 已安装Zephyr SDK并初始化west工作区
- 本案例仅依赖Zephyr内核自带API,无额外第三方库
实现原理
Zephyr的系统节拍频率由CONFIG_SYS_CLOCK_TICKS_PER_SEC控制,默认值为100(即每 tick 10ms)。通过Kconfig将其改为1000后,每个tick变为1ms,k_sleep(100)的延时精度将从“至少100ms”提升为“至少100ms且误差不超过1ms”。设备树中chosen节点的zephyr,sys-clock属性通常指向系统定时器,但节拍频率主要由Kconfig决定,设备树仅需保持默认即可。本案例同时展示如何确认当前生效的节拍频率。
关键完整代码
// prj.conf
CONFIG_SYS_CLOCK_TICKS_PER_SEC=1000
CONFIG_PRINTK=y
// src/main.c
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
/* 延时误差统计结构 */
struct delay_stat {
uint32_t min_delta_us;
uint32_t max_delta_us;
uint32_t total_delta_us;
uint32_t samples;
};
static void measure_delay(struct delay_stat *stat, int sleep_ms)
{
uint32_t start = k_cycle_get_32();
k_sleep(K_MSEC(sleep_ms));
uint32_t end = k_cycle_get_32();
uint32_t delta_us = (end - start) / (sys_clock_hw_cycles_per_sec() / 1000000);
if (stat->samples == 0) {
stat->min_delta_us = delta_us;
stat->max_delta_us = delta_us;
} else {
if (delta_us < stat->min_delta_us)
stat->min_delta_us = delta_us;
if (delta_us > stat->max_delta_us)
stat->max_delta_us = delta_us;
}
stat->total_delta_us += delta_us;
stat->samples++;
}
void main(void)
{
struct delay_stat stat = {0};
const int sleep_ms = 100;
const int iterations = 10;
printk("System tick frequency: %d Hz\n",
CONFIG_SYS_CLOCK_TICKS_PER_SEC);
printk("HW cycles per sec: %d\n",
sys_clock_hw_cycles_per_sec());
for (int i = 0; i < iterations; i++) {
measure_delay(&stat, sleep_ms);
}
uint32_t avg_us = stat.total_delta_us / stat.samples;
printk("Sleep %d ms over %d iterations:\n", sleep_ms, iterations);
printk(" avg: %d us, min: %d us, max: %d us\n",
avg_us, stat.min_delta_us, stat.max_delta_us);
printk(" expected: %d us (ideal)\n", sleep_ms * 1000);
}
构建与运行
# 在west工作区中创建项目后执行
west build -b native_sim -d build .
west build -d build -t run
若使用qemu_x86,将-b native_sim替换为-b qemu_x86,运行命令改为west build -d build -t qemu。
验证方法与判定标准
- 运行后首先观察打印的
System tick frequency是否为1000,确认Kconfig生效。 - 观察
avg值:当节拍频率为1000Hz时,平均延时应在100000us(100ms)附近,且max - min的抖动通常不超过1个tick周期(即1000us)。 - 将
prj.conf中的值改回100并重新构建运行,对比两次的max值:100Hz时最大误差可达10000us(10ms),而1000Hz时最大误差应明显减小。这一对比直接证明节拍频率对延时精度的影响。
通过条件:两次运行结果中,1000Hz配置下的最大延时误差显著小于100Hz配置(至少减小5倍以上),且打印的tick频率与配置一致。
常见问题
- 修改后无变化:确认
prj.conf位于项目根目录且拼写正确;若使用设备树覆盖,需检查chosen节点是否被意外修改。 - native_sim时间不精确:native_sim的计时基于主机系统,误差可能受宿主机调度影响,建议用qemu_x86获得更稳定的结果。
- 周期计数溢出:本测试延时短、循环少,不会触发32位周期计数回绕;若增加循环次数需处理回绕。