RIOT 系统 ztimer 开销测量实战:用 ztimer_overhead 测试校准 ZTIMER_USEC 精度

发布时间:2026/9/20 12:47:11
RIOT 系统 ztimer 开销测量实战:用 ztimer_overhead 测试校准 ZTIMER_USEC 精度 RIOT 系统 ztimer 开销测量实战用 ztimer_overhead 测试校准 ZTIMER_USEC 精度【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT导读在 RIOT 操作系统中ztimer 是面向微控制器的通用定时抽象层其高精度时钟 ZTIMER_USEC 的每次ztimer_set()与ztimer_sleep()调用都会引入可测的系统开销函数调用、队列操作、中断处理等。本文以 tests/sys/ztimer_overhead/README.md 为线索完整讲解 RIOT 自带的开销测量测试应用它如何在 1MHz 的 ZTIMER_USEC 上采样 1024 次、如何借助ztimer_overhead_set()/ztimer_overhead_sleep()量化开销以及如何把测量结果写成CONFIG_ZTIMER_USEC_ADJUST_SET/CONFIG_ZTIMER_USEC_ADJUST_SLEEP固化到目标板卡的board.h中。读完本文你将掌握一套可复现的定时精度校准流程并理解其背后的源码实现原理。一、测试应用概述测量什么、为什么测量ztimer提供统一的ztimer_set()、ztimer_sleep()等接口但对真实硬件而言定时器的启动、计数回调、内核唤醒都存在固有延迟。若不对这些开销做补偿基于 ZTIMER_USEC 的精确延时与调度会系统性偏大。该测试应用tests/sys/ztimer_overhead/main.c做的事情如下初始化基于periph_timer的 ZTIMER_USEC运行频率为 1MHz即 1 个 tick 1 微秒连续1024 次调用ztimer_overhead_set()测量ztimer_set()引入的开销随后连续1024 次调用ztimer_overhead_sleep()测量ztimer_sleep()引入的开销每次测量以「真实耗时 − 请求的基准间隔」作为单次开销tick 数测试结束时打印出建议写入目标板卡board.h的两个校准值。测量代码中两个核心常量定义在 main.c#define BASE 1000 /* 基准间隔1000 ticks即 1ms */ #define SAMPLES 1024 /* 采样次数 */选择 1024 次采样并在_ztimer_usec_overhead()main.c中同时记录min/max并打印avg_diff是因为单次测量受中断抖动、后台负载影响较大多次采样取最小值可以逼近「纯系统开销」的稳定下界。二、两个核心测量函数ztimer_overhead_set 与 ztimer_overhead_sleep两个测量函数由ztimer_overhead模块提供声明位于 sys/include/ztimer/overhead.h实现位于 sys/ztimer/overhead.c。2.1 ztimer_overhead_set()int32_t ztimer_overhead_set(ztimer_clock_t *clock, uint32_t base);该函数配置一个回调在base个 tick 后触发然后返回「从调用ztimer_set()到回调实际执行的时间」减去base的差值即ztimer_set()的开销。实现要点sys/ztimer/overhead.c使用一个volatile uint32_t after变量与回调参数callback_arg_t回调_callback()在触发瞬间记录ztimer_now(clock)先ztimer_acquire(clock)独占时钟记录pre ztimer_now(clock)再ztimer_set(clock, t, base)随后while (!after) {}自旋等待回调完成返回after - pre - base若返回值接近 0说明ztimer_set()几乎没有额外开销若为正即每次设置定时器平均多花的 tick 数。2.2 ztimer_overhead_sleep()int32_t ztimer_overhead_sleep(ztimer_clock_t *clock, uint32_t base);该函数测量ztimer_sleep()的开销sys/ztimer/overhead.cztimer_acquire(clock); uint32_t pre ztimer_now(clock); ztimer_sleep(clock, base); uint32_t after ztimer_now(clock); ztimer_release(clock); return after - pre - base;与ztimer_overhead_set()的不同在于ztimer_sleep()会主动让出 CPU进入低功耗或让出调度其开销通常大于ztimer_set()因为它还包含线程重新调度与唤醒的延迟。三、运行流程与输出解读3.1 主流程逐步拆解main.c 的执行顺序值得仔细分析打印并清零自动校准值首先打印启动时若启用了ztimer_auto_adjust模块内核初始化阶段写入的ZTIMER_USEC-adjust_set/adjust_sleep然后显式清零保证后续测量基于「未补偿」的原始时钟测量 set 开销调用_ztimer_usec_overhead(SAMPLES, BASE, ztimer_overhead_set)并把返回的最小值写回ZTIMER_USEC-adjust_set测量 sleep 开销同样方式把最小值写回ZTIMER_USEC-adjust_sleep输出校准建议按目标板卡打印两个 Kconfig 配置项。3.2 输出示例README 中的 dwm1001 板卡原文档给出了 dwm1001 板卡的典型输出ZTIMER_USEC adjust params for dwm1001: CONFIG_ZTIMER_USEC_ADJUST_SET 6 CONFIG_ZTIMER_USEC_ADJUST_SLEEP 21含义是在 dwm1001 上每次ztimer_set()平均带来约 6 个 tick6 微秒的开销而ztimer_sleep()每次约 21 个 tick。把这两个值写入该板卡的board.h后ztimer 会在内部自动减去这些偏移从而让定时精度显著提升。注意不同 MCU 架构、时钟频率、中断实现下这些数值完全不同必须逐板实测。3.3 中间统计输出测量过程中_ztimer_usec_overhead()还会逐阶段打印统计信息main.cmin6 max31 avg_diff11其中min被用于最终的校准值——这是因为系统开销的「下限」最接近纯软件路径成本而max/avg_diff供开发者评估抖动范围。四、编译配置与运行方式4.1 依赖模块测试应用通过 tests/sys/ztimer_overhead/Makefile 声明了三个模块USEMODULE ztimer_auto_adjust USEMODULE ztimer_overhead USEMODULE ztimer_usecztimer_usec提供 1MHz 的 ZTIMER_USEC 时钟ztimer_overhead提供两个测量函数ztimer_auto_adjust使系统在初始化阶段ztimer_init()就自动估算一次校准值测试应用借此对比「初始化时算出的偏移」与「测试期间算出的偏移」验证自动校准的稳定性。4.2 编译烧录在任意支持的板卡上例如native、dwm1001、samr21-xpro等make -C tests/sys/ztimer_overhead flash term测试完成后把终端输出的CONFIG_ZTIMER_USEC_ADJUST_SET与CONFIG_ZTIMER_USEC_ADJUST_SLEEP配置到对应板卡目录的board.h中即可让该板卡的所有 ztimer 调用获得补偿。4.3 CI 黑名单的工程含义Makefile 将microbit、native32、native64加入了TEST_ON_CI_BLACKLIST并给出明确注释microbitqemu 模拟下计时不准确nativeCI 机器上并行编译任务会造成严重的后台 CPU 负载导致采样抖动、测试随机失败。这提示了该测量的一个固有特性它对 CPU 负载敏感因此在真实板卡上运行时也建议关闭无关后台任务以获得更稳定的校准值。五、源码级原理校准值如何被消费5.1 时钟结构体中的三个偏移字段ztimer_clock_t在 sys/include/ztimer.h 中定义了两个关键字段uint16_t adjust_set; /* 每次 set() 时被减去的值 */ uint16_t adjust_sleep; /* 每次 sleep() 时额外减去的值叠加在 adjust_set 之上 */ uint16_t adjust_clock_start; /* 每次 set() 时减去用于补偿外设启动开销 */5.2 在 core.c 中的实际扣减以ztimer_set()为例sys/ztimer/core.c 在计算目标触发时刻时会做如下补偿/* optionally subtract a configurable adjustment value */ if (val clock-adjust_set) { val - clock-adjust_set; }即请求的延时val先减去adjust_set使定时器实际触发时刻提前抵消软件路径造成的延迟最终回调在「期望时刻」附近执行。adjust_sleep则在ztimer_sleep()内部其底层同样基于ztimer_set()叠加扣减。5.3 配置项的默认值与优先级三个相关 Kconfig 默认值定义在 sys/include/ztimer/config.h配置项默认值说明CONFIG_ZTIMER_USEC_ADJUST_SET0补偿ztimer_set()的偏移用ztimer_overhead_set()测量config.hCONFIG_ZTIMER_USEC_ADJUST_SLEEP0补偿ztimer_sleep()的偏移用ztimer_overhead_sleep()测量config.hCONFIG_ZTIMER_USEC_ADJUST_CLOCK_START0补偿外设上电启动偏移用ztimer_ondemand_benchmark工具测量config.h官方文档明确指出由于ztimer_sleep()内部使用ztimer_set()应先校准CONFIG_ZTIMER_USEC_ADJUST_SET再校准CONFIG_ZTIMER_USEC_ADJUST_SLEEP。这些值本意就是按板卡固化在board.h中。六、与 ztimer_auto_adjust 的关系两种校准路径的对比本测试同时启用ztimer_auto_adjust因此可以从两个角度理解校准值来源。6.1 初始化阶段的自动估算在 sys/ztimer/init.c 中定义了内部辅助函数_ztimer_usec_overhead()同样以「多次采样取最小值」的方式估算adjust_set与adjust_sleep#ifndef CONFIG_ZTIMER_AUTO_ADJUST_BASE_ITVL #define CONFIG_ZTIMER_AUTO_ADJUST_BASE_ITVL 1000 /* 基准间隔 1000 ticks */ #endif #ifndef CONFIG_ZTIMER_AUTO_ADJUST_ITER #define CONFIG_ZTIMER_AUTO_ADJUST_ITER 100 /* 采样 100 次 */ #endifztimer_init()init.c的优先级逻辑为若CONFIG_ZTIMER_USEC_ADJUST_SET ! 0板卡已固化配置则直接采用该值否则若启用了ztimer_auto_adjust模块则用上述采样函数自动计算并写入ZTIMER_USEC-adjust_set/adjust_sleep。6.2 两种路径的差异路径采样次数触发时机用途ztimer_auto_adjust初始化阶段100 次CONFIG_ZTIMER_AUTO_ADJUST_ITER系统启动时快速获得可用校准值适合没有预配置的板卡ztimer_overhead测试应用1024 次SAMPLES用户手动运行更充分的采样生成建议固化的精确值对于某些时钟需要「预热」才能稳定的 MCUconfig.h 还提供了CONFIG_ZTIMER_AUTO_ADJUST_SETTLE默认0配置设置为非零值后自动校准前会先ztimer_sleep(ZTIMER_USEC, CONFIG_ZTIMER_AUTO_ADJUST_SETTLE)等待时钟进入稳定状态见 init.c代价是增加系统启动时间。七、如何把结果固化到板卡拿到测试输出后按以下步骤固化校准值以输出SET6, SLEEP21为例打开目标板卡目录下的board.h例如boards/dwm1001/include/board.h加入#define CONFIG_ZTIMER_USEC_ADJUST_SET 6 #define CONFIG_ZTIMER_USEC_ADJUST_SLEEP 21重新编译烧录固件后重新运行本测试可以验证第一段输出的「auto_adjust params」应与固化值一致或接近若板卡更换时钟源、运行频率或工具链版本建议重新执行本测试校准。八、总结tests/sys/ztimer_overhead是 RIOT 中一套简洁而实用的定时精度校准工具它以 1MHz 的 ZTIMER_USEC 为被测对象通过 1024 次采样分别量化ztimer_set()与ztimer_sleep()的开销并把最小值转化为可固化的CONFIG_ZTIMER_USEC_ADJUST_SET/CONFIG_ZTIMER_USEC_ADJUST_SLEEP。结合 overhead.c 的实现、core.c 的补偿逻辑以及 init.c 的自动校准路径开发者既能获得「开箱即用」的校准流程也能深入理解 ztimer 内部开销的来源与补偿机制从而为时间敏感型 IoT 应用提供可靠的时间基准。【免费下载链接】RIOTRIOT - The friendly OS for IoT项目地址: https://gitcode.com/GitHub_Trending/riot/RIOT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询