summaryrefslogtreecommitdiff
path: root/documentation/6.components/device-driver/clock_time.md
blob: a7bd0ab56d7afb172c8e938866e81e916162c7a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
# Clock Time Device

## Introduction

The `clock_time` subsystem provides a unified framework for time management in RT-Thread, consolidating the functionality of the legacy `hwtimer`, `ktime`, and `cputime` subsystems into a single, coherent API.

### Key Features

- **Clocksource**: Free-running counter for timekeeping and timestamps
- **Clockevent**: Programmable timeout events for high-precision timing
- **High-Resolution Timers (hrtimer)**: Efficient timer management with linked-list scheduling
- **POSIX Clock Support**: Compatible with standard POSIX clock APIs
- **Boottime Tracking**: Monotonic time since system boot
- **Backward Compatibility**: Compatibility layers for legacy APIs

### Design Philosophy

The clock_time subsystem follows RT-Thread's C-OOP (Object-Oriented Programming in C) design pattern:

1. **Unified Device Abstraction**: `rt_clock_time_device` encapsulates hardware timer capabilities
2. **Operations Structure**: `rt_clock_time_ops` defines hardware-specific operations
3. **Capability Flags**: Explicitly indicates clocksource and clockevent support
4. **Flexible Integration**: Works with both MCU and MPU platforms

## Architecture

```
┌─────────────────────────────────────────────────────────┐
│                   Application Layer                      │
│  (POSIX APIs, Delays, Timekeeping, High-Res Timers)    │
└──────────────────┬──────────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────────┐
│              clock_time Subsystem                        │
│  ┌─────────────┐  ┌──────────┐  ┌──────────────────┐   │
│  │ Clocksource │  │ Boottime │  │ High-Res Timers │   │
│  └─────────────┘  └──────────┘  └──────────────────┘   │
│  ┌─────────────┐  ┌──────────────────────────────┐     │
│  │ Clockevent  │  │    Compatibility Layers      │     │
│  └─────────────┘  └──────────────────────────────┘     │
└──────────────────┬──────────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────────┐
│           Hardware Timer Abstraction                     │
│        (rt_clock_time_device + ops)                     │
└──────────────────┬──────────────────────────────────────┘
                   │
┌──────────────────▼──────────────────────────────────────┐
│              BSP Timer Driver                           │
│   (SysTick, ARM Arch Timer, RISC-V Timer, etc.)        │
└─────────────────────────────────────────────────────────┘
```

## Usage

### Registering a Clock Time Device

BSP drivers should implement the `rt_clock_time_ops` and register a device:

```c
#include <rtdevice.h>

static rt_uint64_t my_timer_get_freq(void)
{
    return 1000000; /* 1MHz timer */
}

static rt_uint64_t my_timer_get_counter(void)
{
    return MY_TIMER->CNT; /* Read hardware counter */
}

static rt_err_t my_timer_set_timeout(rt_uint64_t delta)
{
    if (delta == 0)
    {
        /* Cancel timeout */
        MY_TIMER->CR &= ~TIMER_ENABLE;
        return RT_EOK;
    }
    
    MY_TIMER->CMP = MY_TIMER->CNT + delta;
    MY_TIMER->CR |= TIMER_ENABLE | TIMER_INT_ENABLE;
    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_clock_device;

int my_timer_init(void)
{
    /* Initialize hardware timer */
    my_clock_device.ops = &my_timer_ops;
    
    /* Register with both clocksource and clockevent capabilities */
    rt_clock_time_device_register(&my_clock_device, 
                                  "hw_timer",
                                  RT_CLOCK_TIME_CAP_CLOCKSOURCE | 
                                  RT_CLOCK_TIME_CAP_CLOCKEVENT);
    
    return 0;
}
INIT_DEVICE_EXPORT(my_timer_init);

/* Timer ISR should call rt_clock_hrtimer_process() */
void MY_TIMER_IRQHandler(void)
{
    /* Clear interrupt flag */
    MY_TIMER->SR = 0;
    
    /* Process hrtimer timeouts */
    rt_clock_hrtimer_process();
}
```

### Using Clocksource APIs

#### Get Time Information

```c
/* Get clock resolution (in ns, scaled by RT_CLOCK_TIME_RESMUL) */
rt_uint64_t res = rt_clock_time_getres();

/* Get clock frequency in Hz */
rt_uint64_t freq = rt_clock_time_getfreq();

/* Get current counter value */
rt_uint64_t cnt = rt_clock_time_getcnt();
```

#### Get Boottime

```c
struct timespec ts;
rt_clock_time_boottime_ns(&ts);
rt_kprintf("Boot time: %d.%09d seconds\n", ts.tv_sec, ts.tv_nsec);

struct timeval tv;
rt_clock_time_boottime_us(&tv);

time_t t;
rt_clock_time_boottime_s(&t);
```

#### Time Conversion

```c
rt_uint64_t cnt = 1000000; /* counter ticks */

/* Convert to time units */
rt_uint64_t ns = rt_clock_time_cnt_to_ns(cnt);
rt_uint64_t us = rt_clock_time_cnt_to_us(cnt);
rt_uint64_t ms = rt_clock_time_cnt_to_ms(cnt);

/* Convert from time units */
cnt = rt_clock_time_ns_to_cnt(1000000); /* 1ms in nanoseconds */
cnt = rt_clock_time_us_to_cnt(1000);    /* 1ms in microseconds */
cnt = rt_clock_time_ms_to_cnt(1);       /* 1ms */
```

### Using High-Resolution Timers

#### Create and Start a Timer

```c
#include <rtdevice.h>

static void timeout_callback(void *param)
{
    rt_kprintf("Timer timeout!\n");
}

void hrtimer_example(void)
{
    struct rt_clock_hrtimer timer;
    
    /* Initialize timer */
    rt_clock_hrtimer_init(&timer, "my_timer", 
                         RT_TIMER_FLAG_ONE_SHOT,
                         timeout_callback, 
                         RT_NULL);
    
    /* Start timer with 1ms delay */
    rt_uint64_t delay_cnt = rt_clock_time_ms_to_cnt(1);
    rt_clock_hrtimer_start(&timer, delay_cnt);
    
    /* ... */
    
    /* Stop timer if needed */
    rt_clock_hrtimer_stop(&timer);
    
    /* Cleanup */
    rt_clock_hrtimer_detach(&timer);
}
```

#### Periodic Timer

```c
static void periodic_callback(void *param)
{
    rt_kprintf("Periodic tick\n");
}

void periodic_timer_example(void)
{
    struct rt_clock_hrtimer timer;
    
    rt_clock_hrtimer_init(&timer, "periodic", 
                         RT_TIMER_FLAG_PERIODIC,
                         periodic_callback, 
                         RT_NULL);
    
    /* Start with 100ms period */
    rt_uint64_t period_cnt = rt_clock_time_ms_to_cnt(100);
    rt_clock_hrtimer_start(&timer, period_cnt);
}
```

### High-Precision Delays

```c
/* Delay in nanoseconds */
rt_clock_ndelay(1000);  /* 1 microsecond */

/* Delay in microseconds */
rt_clock_udelay(1000);  /* 1 millisecond */

/* Delay in milliseconds */
rt_clock_mdelay(100);   /* 100 milliseconds */

/* Using a custom timer for delays */
struct rt_clock_hrtimer timer;
rt_clock_hrtimer_mdelay(&timer, 50);  /* 50ms delay */
```

## Migration Guide

### From ktime

The clock_time subsystem provides direct API compatibility when `RT_CLOCK_TIME_COMPAT_KTIME` is enabled:

| Old ktime API | New clock_time API |
|--------------|-------------------|
| `rt_ktime_boottime_get_ns()` | `rt_clock_time_boottime_ns()` |
| `rt_ktime_cputimer_getres()` | `rt_clock_time_getres()` |
| `rt_ktime_cputimer_getcnt()` | `rt_clock_time_getcnt()` |
| `rt_ktime_hrtimer_init()` | `rt_clock_hrtimer_init()` |
| `rt_ktime_hrtimer_start()` | `rt_clock_hrtimer_start()` |

### From cputime

When `RT_CLOCK_TIME_COMPAT_CPUTIME` is enabled:

| Old cputime API | New clock_time API |
|----------------|-------------------|
| `clock_cpu_gettime()` | `rt_clock_time_getcnt()` |
| `clock_cpu_getres()` | `rt_clock_time_getres()` |
| `rt_cputime_sleep()` | `rt_clock_mdelay()` or use hrtimer |
| `rt_cputime_udelay()` | `rt_clock_udelay()` |

### From hwtimer

Hardware timer devices should be migrated to the new clock_time device model:

**Old hwtimer approach:**
```c
static const struct rt_hwtimer_ops my_ops = { ... };
static struct rt_hwtimer_device my_device;
my_device.ops = &my_ops;
rt_device_hwtimer_register(&my_device, "timer0", RT_NULL);
```

**New clock_time approach:**
```c
static const struct rt_clock_time_ops my_ops = { ... };
static struct rt_clock_time_device my_device;
my_device.ops = &my_ops;
rt_clock_time_device_register(&my_device, "timer0",
    RT_CLOCK_TIME_CAP_CLOCKSOURCE | RT_CLOCK_TIME_CAP_CLOCKEVENT);
```

## Configuration

### Kconfig Options

```
RT_USING_CLOCK_TIME              - Enable clock_time subsystem
RT_CLOCK_TIME_COMPAT_KTIME       - Enable ktime compatibility layer
RT_CLOCK_TIME_COMPAT_CPUTIME     - Enable cputime compatibility layer
RT_CLOCK_TIME_COMPAT_HWTIMER     - Enable hwtimer compatibility layer
```

### Typical Configuration

For new projects:
```
CONFIG_RT_USING_CLOCK_TIME=y
# Compatibility layers not needed
```

For migrating projects:
```
CONFIG_RT_USING_CLOCK_TIME=y
CONFIG_RT_CLOCK_TIME_COMPAT_KTIME=y
CONFIG_RT_CLOCK_TIME_COMPAT_CPUTIME=y
CONFIG_RT_CLOCK_TIME_COMPAT_HWTIMER=y
```

## Best Practices

### For MCU Scenarios

1. **Use SysTick or similar**: For basic timekeeping, SysTick provides adequate resolution
2. **Hardware timers for precision**: Use dedicated hardware timers for microsecond-level precision
3. **Consider power**: Minimize timer wakeups in low-power applications

### For MPU Scenarios

1. **Architecture timers**: Use ARM Generic Timer or RISC-V timer for best performance
2. **SMP safety**: The hrtimer implementation uses spinlocks for SMP systems
3. **High-frequency sources**: MPUs can handle higher frequency timers (MHz range)

### General Guidelines

1. **Single default device**: Register one primary clock_time device as the system default
2. **ISR efficiency**: Keep `rt_clock_hrtimer_process()` call in ISR short
3. **Resolution vs. overhead**: Higher resolution timers have higher overhead
4. **Fallback support**: The tick-based fallback ensures functionality even without hardware timer

## API Reference

See the complete API documentation in `/components/drivers/include/drivers/clock_time.h`.

## Examples

Complete examples can be found in:
- `/examples/clock_time/` - Basic usage examples
- BSP timer driver implementations for reference

## Troubleshooting

### Timer not firing

- Verify hardware timer is properly configured
- Check that ISR calls `rt_clock_hrtimer_process()`
- Ensure timer interrupt is enabled

### Poor precision

- Verify timer frequency is appropriate for your use case
- Check for interrupt latency issues
- Consider using a higher frequency timer

### Compatibility issues

- Enable appropriate compatibility layer in Kconfig
- Check for API signature changes in migration
- Verify BSP-specific timer implementation

## See Also

- [Timer Management](timer.md)
- [Real-Time Clock (RTC)](rtc.md)
- [Device Driver Framework](framework.md)