# RT-Thread Clock Time Subsystem / RT-Thread 时钟时间子系统 English | [中文](#中文文档) ## Overview The `clock_time` subsystem provides a unified interface for time-related hardware and software functionality in RT-Thread. It consolidates and replaces the previous separate subsystems: - **hwtimer**: Hardware timer device drivers - **ktime**: Kernel time and high-resolution timers - **cputime**: CPU time measurement ## Architecture The clock_time subsystem follows a C-OOP (C Object-Oriented Programming) design pattern with clear separation of concerns: ``` ┌─────────────────────────────────────────────────────────┐ │ Application Layer │ │ (POSIX clock_gettime, nanosleep, etc.) │ └────────────────┬────────────────────────────────────────┘ │ ┌────────────────▼────────────────────────────────────────┐ │ Clock Time High-Level APIs │ │ • Boottime (monotonic time since boot) │ │ • High-Resolution Timers (hrtimer) │ │ • CPU Timer (counter access) │ └────────────────┬────────────────────────────────────────┘ │ ┌────────────────▼────────────────────────────────────────┐ │ Clock Time Device Abstraction │ │ struct rt_clock_time_device │ │ struct rt_clock_time_ops │ └────────────────┬────────────────────────────────────────┘ │ ┌────────────────▼────────────────────────────────────────┐ │ Hardware / BSP Implementation │ │ • ARM Arch Timer, RISC-V RDTIME │ │ • SysTick, System Timer │ │ • Hardware Timer Peripherals │ └─────────────────────────────────────────────────────────┘ ``` ### Key Components 1. **Device Abstraction** (`clock_time.c`) - Unified device interface for timer hardware - Device registration and management - Capability flags (clocksource, clockevent) 2. **High-Resolution Timers** (`hrtimer.c`) - Software timer scheduling on hardware timers - Linked-list or red-black tree management - SMP-safe with spinlock protection 3. **Boottime APIs** (`clock_time_boottime.c`) - Monotonic time since system boot - Nanosecond, microsecond, second precision 4. **CPU Timer** (`clock_time_tick.c`, `clock_time_cputime.c`) - Low-level counter access - Frequency and resolution queries - Tick-based fallback for simple systems ## Configuration Enable clock_time in menuconfig: ``` Device Drivers ---> [*] Using unified clock_time subsystem ---> [*] Enable high-resolution timer support [*] Enable CPU time APIs [*] Enable boottime APIs ``` ### Backward Compatibility When `RT_USING_CLOCK_TIME` is enabled, the old subsystems are automatically disabled and their APIs are redirected: - `RT_USING_HWTIMER` → Automatically set (compatibility mode) - `RT_USING_KTIME` → Automatically set (compatibility mode) - `RT_USING_CPUTIME` → Automatically set (compatibility mode) All `rt_ktime_*` APIs are mapped to `rt_clock_*` APIs via macros, ensuring existing code continues to work. ## API Reference ### Device Management ```c /* Register a clock time device */ rt_err_t rt_clock_time_device_register(struct rt_clock_time_device *dev, const char *name, rt_uint8_t caps); /* Get/set default system clock device */ rt_clock_time_t rt_clock_time_default(void); rt_err_t rt_clock_time_set_default(rt_clock_time_t dev); ``` ### Boottime APIs ```c /* Get system boottime (monotonic time since boot) */ rt_err_t rt_clock_boottime_get_ns(struct timespec *ts); // Nanosecond precision rt_err_t rt_clock_boottime_get_us(struct timeval *tv); // Microsecond precision rt_err_t rt_clock_boottime_get_s(time_t *t); // Second precision ``` ### CPU Timer APIs ```c /* Low-level counter access */ rt_uint64_t rt_clock_cputimer_getres(void); // Get resolution unsigned long rt_clock_cputimer_getfrq(void); // Get frequency in Hz unsigned long rt_clock_cputimer_getcnt(void); // Get current counter value void rt_clock_cputimer_init(void); // Initialize (called by system) ``` ### High-Resolution Timer APIs ```c /* Initialize and manage high-resolution timers */ void rt_clock_hrtimer_init(rt_clock_hrtimer_t timer, const char *name, rt_uint8_t flag, void (*timeout)(void *), void *param); rt_err_t rt_clock_hrtimer_start(rt_clock_hrtimer_t timer, unsigned long cnt); rt_err_t rt_clock_hrtimer_stop(rt_clock_hrtimer_t timer); rt_err_t rt_clock_hrtimer_detach(rt_clock_hrtimer_t timer); /* Delay functions (blocking) */ rt_err_t rt_clock_hrtimer_ndelay(struct rt_clock_hrtimer *timer, unsigned long ns); rt_err_t rt_clock_hrtimer_udelay(struct rt_clock_hrtimer *timer, unsigned long us); rt_err_t rt_clock_hrtimer_mdelay(struct rt_clock_hrtimer *timer, unsigned long ms); ``` ## BSP Porting Guide ### Minimal Implementation (Tick-based) The tick-based fallback works out-of-the-box for simple systems: ```c // No additional code needed - uses RT_TICK_PER_SECOND // Automatically provides: // - rt_clock_cputimer_getcnt() → rt_tick_get() // - rt_clock_cputimer_getfrq() → RT_TICK_PER_SECOND // - Resolution based on tick rate ``` ### Hardware Timer Implementation For better precision, implement hardware timer support: ```c #include /* Define hardware operations */ static rt_uint64_t my_timer_get_freq(void) { return 1000000; // 1 MHz } static rt_uint64_t my_timer_get_counter(void) { return READ_TIMER_COUNTER_REG(); } static rt_err_t my_timer_set_timeout(rt_uint64_t delta) { if (delta == 0) { DISABLE_TIMER_INTERRUPT(); return RT_EOK; } SET_TIMER_COMPARE_VALUE(delta); ENABLE_TIMER_INTERRUPT(); return RT_EOK; } static const struct rt_clock_time_ops my_timer_ops = { .get_freq = my_timer_get_freq, .get_counter = my_timer_get_counter, .set_timeout = my_timer_set_timeout, }; /* Define device structure */ static struct rt_clock_time_device my_timer_dev; /* Initialize and register */ int my_timer_init(void) { HARDWARE_TIMER_INIT(); my_timer_dev.ops = &my_timer_ops; return rt_clock_time_device_register(&my_timer_dev, "timer0", RT_CLOCK_TIME_CAP_CLOCKSOURCE | RT_CLOCK_TIME_CAP_CLOCKEVENT); } INIT_BOARD_EXPORT(my_timer_init); /* Timer interrupt handler */ void timer_irq_handler(void) { CLEAR_TIMER_INTERRUPT(); rt_clock_hrtimer_process(); // Process expired timers } ``` ### Overriding CPU Timer Functions For architecture-specific high-performance counters (e.g., ARM DWT, RISC-V RDTIME): ```c /* Override weak functions in your BSP */ unsigned long rt_clock_cputimer_getcnt(void) { return READ_CPU_CYCLE_COUNTER(); } unsigned long rt_clock_cputimer_getfrq(void) { return CPU_FREQUENCY_HZ; } rt_uint64_t rt_clock_cputimer_getres(void) { // Resolution in ns * RT_CLOCK_TIME_RESMUL return ((1000000000ULL * RT_CLOCK_TIME_RESMUL) / CPU_FREQUENCY_HZ); } ``` ## Migration Guide ### From ktime All `rt_ktime_*` APIs are automatically mapped. No code changes needed: ```c // Old code (still works) #include rt_ktime_boottime_get_ns(&ts); rt_ktime_hrtimer_init(&timer, "mytimer", ...); // Equivalent new code (optional migration) #include rt_clock_boottime_get_ns(&ts); rt_clock_hrtimer_init(&timer, "mytimer", ...); ``` ### From hwtimer Hardware timer drivers should be updated to use the new device abstraction: ```c // Old: struct rt_hwtimer_device + rt_device_hwtimer_register() // New: struct rt_clock_time_device + rt_clock_time_device_register() ``` ### From cputime CPU time APIs have been unified: ```c // Old: clock_cpu_gettime() / clock_cpu_getres() // New: rt_clock_cputimer_getcnt() / rt_clock_cputimer_getres() // Note: Old APIs still work if using old cputime module ``` ## Examples ### Example 1: One-shot Timer ```c #include static void timer_callback(void *param) { rt_kprintf("Timer expired!\n"); } void example_oneshot_timer(void) { struct rt_clock_hrtimer timer; rt_clock_hrtimer_init(&timer, "oneshot", RT_TIMER_FLAG_ONE_SHOT, timer_callback, NULL); // Start timer for 1 second (using CPU timer frequency) unsigned long freq = rt_clock_cputimer_getfrq(); rt_clock_hrtimer_start(&timer, freq * 1); // Timer will fire callback after 1 second } ``` ### Example 2: Microsecond Delay ```c #include void example_delay(void) { struct rt_clock_hrtimer timer; rt_clock_hrtimer_delay_init(&timer); // Delay for 500 microseconds rt_clock_hrtimer_udelay(&timer, 500); rt_clock_hrtimer_delay_detach(&timer); } ``` ### Example 3: Boottime Measurement ```c #include void example_boottime(void) { struct timespec ts; rt_clock_boottime_get_ns(&ts); rt_kprintf("System has been running for %ld.%09ld seconds\n", ts.tv_sec, ts.tv_nsec); } ``` --- ## 中文文档 ## 概述 `clock_time` 子系统为 RT-Thread 中的时间相关硬件和软件功能提供统一接口。它整合并替代了以前的独立子系统: - **hwtimer**:硬件定时器设备驱动 - **ktime**:内核时间和高分辨率定时器 - **cputime**:CPU 时间测量 ## 架构 clock_time 子系统遵循 C-OOP(C 语言面向对象编程)设计模式,职责清晰分离: ``` ┌─────────────────────────────────────────────────────────┐ │ 应用层 │ │ (POSIX clock_gettime, nanosleep 等) │ └────────────────┬────────────────────────────────────────┘ │ ┌────────────────▼────────────────────────────────────────┐ │ 时钟时间高层 API │ │ • Boottime (自启动以来的单调时间) │ │ • 高分辨率定时器 (hrtimer) │ │ • CPU 定时器 (计数器访问) │ └────────────────┬────────────────────────────────────────┘ │ ┌────────────────▼────────────────────────────────────────┐ │ 时钟时间设备抽象 │ │ struct rt_clock_time_device │ │ struct rt_clock_time_ops │ └────────────────┬────────────────────────────────────────┘ │ ┌────────────────▼────────────────────────────────────────┐ │ 硬件 / BSP 实现 │ │ • ARM Arch Timer, RISC-V RDTIME │ │ • SysTick, 系统定时器 │ │ • 硬件定时器外设 │ └─────────────────────────────────────────────────────────┘ ``` ### 关键组件 1. **设备抽象** (`clock_time.c`) - 定时器硬件的统一设备接口 - 设备注册和管理 - 能力标志(时钟源、时钟事件) 2. **高分辨率定时器** (`hrtimer.c`) - 在硬件定时器上的软件定时器调度 - 链表或红黑树管理 - SMP 安全,带自旋锁保护 3. **Boottime API** (`clock_time_boottime.c`) - 自系统启动以来的单调时间 - 纳秒、微秒、秒精度 4. **CPU 定时器** (`clock_time_tick.c`, `clock_time_cputime.c`) - 底层计数器访问 - 频率和分辨率查询 - 简单系统的基于 tick 的回退 ## 配置 在 menuconfig 中启用 clock_time: ``` Device Drivers ---> [*] Using unified clock_time subsystem ---> [*] Enable high-resolution timer support [*] Enable CPU time APIs [*] Enable boottime APIs ``` ### 向后兼容 当启用 `RT_USING_CLOCK_TIME` 时,旧子系统自动禁用,其 API 被重定向: - `RT_USING_HWTIMER` → 自动设置(兼容模式) - `RT_USING_KTIME` → 自动设置(兼容模式) - `RT_USING_CPUTIME` → 自动设置(兼容模式) 所有 `rt_ktime_*` API 通过宏映射到 `rt_clock_*` API,确保现有代码继续工作。 ## API 参考 ### 设备管理 ```c /* 注册时钟时间设备 */ rt_err_t rt_clock_time_device_register(struct rt_clock_time_device *dev, const char *name, rt_uint8_t caps); /* 获取/设置默认系统时钟设备 */ rt_clock_time_t rt_clock_time_default(void); rt_err_t rt_clock_time_set_default(rt_clock_time_t dev); ``` ### Boottime API ```c /* 获取系统启动时间(自启动以来的单调时间) */ rt_err_t rt_clock_boottime_get_ns(struct timespec *ts); // 纳秒精度 rt_err_t rt_clock_boottime_get_us(struct timeval *tv); // 微秒精度 rt_err_t rt_clock_boottime_get_s(time_t *t); // 秒精度 ``` ### CPU 定时器 API ```c /* 底层计数器访问 */ rt_uint64_t rt_clock_cputimer_getres(void); // 获取分辨率 unsigned long rt_clock_cputimer_getfrq(void); // 获取频率(Hz) unsigned long rt_clock_cputimer_getcnt(void); // 获取当前计数器值 void rt_clock_cputimer_init(void); // 初始化(由系统调用) ``` ### 高分辨率定时器 API ```c /* 初始化和管理高分辨率定时器 */ void rt_clock_hrtimer_init(rt_clock_hrtimer_t timer, const char *name, rt_uint8_t flag, void (*timeout)(void *), void *param); rt_err_t rt_clock_hrtimer_start(rt_clock_hrtimer_t timer, unsigned long cnt); rt_err_t rt_clock_hrtimer_stop(rt_clock_hrtimer_t timer); rt_err_t rt_clock_hrtimer_detach(rt_clock_hrtimer_t timer); /* 延时函数(阻塞) */ rt_err_t rt_clock_hrtimer_ndelay(struct rt_clock_hrtimer *timer, unsigned long ns); rt_err_t rt_clock_hrtimer_udelay(struct rt_clock_hrtimer *timer, unsigned long us); rt_err_t rt_clock_hrtimer_mdelay(struct rt_clock_hrtimer *timer, unsigned long ms); ``` ## BSP 移植指南 ### 最小实现(基于 Tick) 基于 tick 的回退对简单系统开箱即用: ```c // 无需额外代码 - 使用 RT_TICK_PER_SECOND // 自动提供: // - rt_clock_cputimer_getcnt() → rt_tick_get() // - rt_clock_cputimer_getfrq() → RT_TICK_PER_SECOND // - 基于 tick 速率的分辨率 ``` ### 硬件定时器实现 为了更好的精度,实现硬件定时器支持: ```c #include /* 定义硬件操作 */ static rt_uint64_t my_timer_get_freq(void) { return 1000000; // 1 MHz } static rt_uint64_t my_timer_get_counter(void) { return READ_TIMER_COUNTER_REG(); } static rt_err_t my_timer_set_timeout(rt_uint64_t delta) { if (delta == 0) { DISABLE_TIMER_INTERRUPT(); return RT_EOK; } SET_TIMER_COMPARE_VALUE(delta); ENABLE_TIMER_INTERRUPT(); return RT_EOK; } static const struct rt_clock_time_ops my_timer_ops = { .get_freq = my_timer_get_freq, .get_counter = my_timer_get_counter, .set_timeout = my_timer_set_timeout, }; /* 定义设备结构 */ static struct rt_clock_time_device my_timer_dev; /* 初始化和注册 */ int my_timer_init(void) { HARDWARE_TIMER_INIT(); my_timer_dev.ops = &my_timer_ops; return rt_clock_time_device_register(&my_timer_dev, "timer0", RT_CLOCK_TIME_CAP_CLOCKSOURCE | RT_CLOCK_TIME_CAP_CLOCKEVENT); } INIT_BOARD_EXPORT(my_timer_init); /* 定时器中断处理程序 */ void timer_irq_handler(void) { CLEAR_TIMER_INTERRUPT(); rt_clock_hrtimer_process(); // 处理过期定时器 } ``` ### 覆盖 CPU 定时器函数 对于架构特定的高性能计数器(例如 ARM DWT、RISC-V RDTIME): ```c /* 在 BSP 中覆盖弱函数 */ unsigned long rt_clock_cputimer_getcnt(void) { return READ_CPU_CYCLE_COUNTER(); } unsigned long rt_clock_cputimer_getfrq(void) { return CPU_FREQUENCY_HZ; } rt_uint64_t rt_clock_cputimer_getres(void) { // 分辨率(纳秒 * RT_CLOCK_TIME_RESMUL) return ((1000000000ULL * RT_CLOCK_TIME_RESMUL) / CPU_FREQUENCY_HZ); } ``` ## 迁移指南 ### 从 ktime 迁移 所有 `rt_ktime_*` API 自动映射。无需更改代码: ```c // 旧代码(仍然有效) #include rt_ktime_boottime_get_ns(&ts); rt_ktime_hrtimer_init(&timer, "mytimer", ...); // 等效的新代码(可选迁移) #include rt_clock_boottime_get_ns(&ts); rt_clock_hrtimer_init(&timer, "mytimer", ...); ``` ### 从 hwtimer 迁移 硬件定时器驱动应更新为使用新的设备抽象: ```c // 旧:struct rt_hwtimer_device + rt_device_hwtimer_register() // 新:struct rt_clock_time_device + rt_clock_time_device_register() ``` ### 从 cputime 迁移 CPU 时间 API 已统一: ```c // 旧:clock_cpu_gettime() / clock_cpu_getres() // 新:rt_clock_cputimer_getcnt() / rt_clock_cputimer_getres() // 注意:如果使用旧 cputime 模块,旧 API 仍然有效 ``` ## 示例 ### 示例 1:一次性定时器 ```c #include static void timer_callback(void *param) { rt_kprintf("定时器过期!\n"); } void example_oneshot_timer(void) { struct rt_clock_hrtimer timer; rt_clock_hrtimer_init(&timer, "oneshot", RT_TIMER_FLAG_ONE_SHOT, timer_callback, NULL); // 启动定时器 1 秒(使用 CPU 定时器频率) unsigned long freq = rt_clock_cputimer_getfrq(); rt_clock_hrtimer_start(&timer, freq * 1); // 定时器将在 1 秒后触发回调 } ``` ### 示例 2:微秒延时 ```c #include void example_delay(void) { struct rt_clock_hrtimer timer; rt_clock_hrtimer_delay_init(&timer); // 延时 500 微秒 rt_clock_hrtimer_udelay(&timer, 500); rt_clock_hrtimer_delay_detach(&timer); } ``` ### 示例 3:启动时间测量 ```c #include void example_boottime(void) { struct timespec ts; rt_clock_boottime_get_ns(&ts); rt_kprintf("系统已运行 %ld.%09ld 秒\n", ts.tv_sec, ts.tv_nsec); } ``` ## License Apache-2.0 ## References - RT-Thread Programming Guide: https://www.rt-thread.io/document/site/ - RT-Thread Coding Style: https://github.com/RT-Thread/rt-thread/blob/master/documentation/coding_style_cn.md