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
|
@page page_device_clock_time_core Clock Time Core
# Overview
The clock_time core defines the device model and conversion helpers used by the
subsystem. It manages the default clock source and clock event devices and
provides fixed-point conversion between counters and nanoseconds.
# Device Model
## Clock Time Operations
```c
struct rt_clock_time_ops
{
rt_uint64_t (*get_freq)(struct rt_clock_time_device *dev);
rt_uint64_t (*get_counter)(struct rt_clock_time_device *dev);
rt_err_t (*set_timeout)(struct rt_clock_time_device *dev, rt_uint64_t delta);
};
```
### get_freq
- Purpose: return the counter frequency in Hz.
- Requirements:
- Must be stable and match the source used by get_counter.
- Should be non-zero; zero indicates the device is not ready.
### get_counter
- Purpose: return a monotonically increasing counter value.
- Requirements:
- Must not go backwards.
- Wrap behavior is allowed but should be consistent with the width of the
counter used by the device.
### set_timeout
- Purpose: program the next timeout relative to the current counter value.
- Parameters: `delta` is in the same counter units returned by get_counter.
- Behavior:
- If `delta` is 0 and the hardware supports it, the event can be canceled.
- Return -RT_ENOSYS when the device does not support event programming.
## Clock Time Device
```c
struct rt_clock_time_device
{
struct rt_device parent;
const struct rt_clock_time_ops *ops;
rt_uint64_t res_scale;
rt_uint8_t caps; /* RT_CLOCK_TIME_CAP_SOURCE / RT_CLOCK_TIME_CAP_EVENT */
};
```
- res_scale provides extra precision in the conversion pipeline. If set to 0,
RT_CLOCK_TIME_RESMUL is used by default.
- caps advertises whether the device can be used as a clock source, a clock
event, or both.
## Register and Select Devices
```c
rt_err_t rt_clock_time_device_register(struct rt_clock_time_device *dev,
const char *name,
rt_uint8_t caps);
void rt_clock_time_set_default_source(struct rt_clock_time_device *dev);
void rt_clock_time_set_default_event(struct rt_clock_time_device *dev);
struct rt_clock_time_device *rt_clock_time_get_default_source(void);
struct rt_clock_time_device *rt_clock_time_get_default_event(void);
```
### rt_clock_time_device_register
- Purpose: register a clock_time device and its capabilities.
- Parameters:
- `dev`: device object with ops and res_scale initialized.
- `name`: device name; if NULL, only capability registration is performed.
- `caps`: RT_CLOCK_TIME_CAP_SOURCE and/or RT_CLOCK_TIME_CAP_EVENT.
- Behavior:
- Registers the device under RT_Device_Class_Timer when `name` is provided.
- If this is the first source, it becomes the default source.
- If this is the first event, it becomes the default event.
- Return values:
- RT_EOK on success.
- Negative error code if device registration fails.
### rt_clock_time_set_default_source / rt_clock_time_set_default_event
- Purpose: explicitly select the default source or event device.
- Behavior: overrides the auto-selected default.
### rt_clock_time_get_default_source / rt_clock_time_get_default_event
- Purpose: query the current default devices.
- Behavior:
- Source defaults to the internal tick-based device if none was registered.
- Event returns NULL if no event device is available.
### rt_clock_time_source_init
- Purpose: BSP hook to register an architecture counter or board source.
- Notes: this function is weak and may be overridden by BSP code.
# Clock Time Query APIs
```c
rt_uint64_t rt_clock_time_get_freq(void);
rt_uint64_t rt_clock_time_get_counter(void);
rt_uint64_t rt_clock_time_get_event_freq(void);
rt_uint64_t rt_clock_time_get_event_res_scaled(void);
```
## rt_clock_time_get_freq
- Purpose: return the frequency of the default source in Hz.
- Return values:
- Non-zero frequency on success.
- 0 if no valid source is available.
## rt_clock_time_get_counter
- Purpose: return the current counter from the default source.
- Return values:
- Monotonic counter value on success.
- 0 if no valid source is available.
## rt_clock_time_get_event_freq
- Purpose: return the event device frequency in Hz.
- Behavior: if no event device exists, falls back to the default source.
## rt_clock_time_get_event_res_scaled
- Purpose: return the scaled resolution for the event device.
- Behavior: if no event device exists, falls back to the default source.
# Conversion Helpers
```c
rt_uint64_t rt_clock_time_get_res_scaled(void);
rt_uint64_t rt_clock_time_counter_to_ns(rt_uint64_t cnt);
rt_uint64_t rt_clock_time_ns_to_counter(rt_uint64_t ns);
```
## rt_clock_time_get_res_scaled
- Purpose: return the scaled resolution for the default source.
- Return values:
- Non-zero scaled resolution when the source is ready.
- 0 when the source is missing or frequency is invalid.
## rt_clock_time_counter_to_ns
- Purpose: convert a counter value to nanoseconds based on the default source.
- Notes: returns 0 when resolution is unavailable.
## rt_clock_time_ns_to_counter
- Purpose: convert nanoseconds to counter units for the default source.
- Notes: returns 0 when resolution is unavailable.
Internally, the core computes a scaled resolution:
```
res_scaled = (1e9 * res_scale) / freq
```
Nanoseconds are then derived using the scale factor RT_CLOCK_TIME_RESMUL to
avoid floating-point math. This keeps precision stable even when freq is not a
power of ten.
# Event API
```c
rt_err_t rt_clock_time_set_timeout(rt_uint64_t delta);
void rt_clock_time_event_isr(void);
```
## rt_clock_time_set_timeout
- Purpose: program the next event using the default event device.
- Parameters: `delta` in event counter units (same as event get_counter).
- Return values:
- RT_EOK on success.
- -RT_ENOSYS if no event device exists or set_timeout is unsupported.
## rt_clock_time_event_isr
- Purpose: drive the hrtimer scheduler when an event expires.
- Usage:
- Call from the hardware timer ISR after acknowledging the interrupt.
- This function processes expired hrtimers and programs the next event.
# BSP Integration Example
## Register a Clock Source
```c
static rt_uint64_t demo_get_freq(struct rt_clock_time_device *dev)
{
RT_UNUSED(dev);
return 10000000ULL; /* 10 MHz */
}
static rt_uint64_t demo_get_counter(struct rt_clock_time_device *dev)
{
RT_UNUSED(dev);
return demo_hw_counter_read();
}
static const struct rt_clock_time_ops demo_src_ops =
{
demo_get_freq,
demo_get_counter,
RT_NULL,
};
static struct rt_clock_time_device demo_src_dev =
{
.ops = &demo_src_ops,
.res_scale = RT_CLOCK_TIME_RESMUL,
};
void rt_clock_time_source_init(void)
{
rt_clock_time_device_register(&demo_src_dev, "clock_time_demo_src",
RT_CLOCK_TIME_CAP_SOURCE);
rt_clock_time_set_default_source(&demo_src_dev);
}
```
## Register a Clock Event
```c
static rt_err_t demo_set_timeout(struct rt_clock_time_device *dev, rt_uint64_t delta)
{
RT_UNUSED(dev);
return demo_hw_timer_program(delta);
}
static const struct rt_clock_time_ops demo_evt_ops =
{
demo_get_freq,
demo_get_counter,
demo_set_timeout,
};
static struct rt_clock_time_device demo_evt_dev =
{
.ops = &demo_evt_ops,
.res_scale = RT_CLOCK_TIME_RESMUL,
};
static void demo_timer_isr(void)
{
demo_hw_timer_ack();
rt_clock_time_event_isr();
}
void demo_register_event(void)
{
rt_clock_time_device_register(&demo_evt_dev, "clock_time_demo_evt",
RT_CLOCK_TIME_CAP_EVENT);
rt_clock_time_set_default_event(&demo_evt_dev);
}
```
# Notes
- Event callbacks may run in interrupt context when backed by a hardware event.
- If no event device is available, the hrtimer subsystem falls back to a
software timer.
|