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
|
# Clock Time Adapters
This directory contains reference adapter implementations for various hardware timers.
These adapters demonstrate how to integrate hardware timers with the unified `clock_time` subsystem.
## Available Adapters
### 1. ARM Generic Timer (`clock_time_arm_gtimer.c`)
**Target Platforms:**
- ARMv7-A (ARM Cortex-A with Generic Timer)
- ARMv8-A/ARMv8-R (AArch64 and AArch32)
**Features:**
- Clocksource: Uses CNTPCT (physical counter)
- Clockevent: Uses CNTP_TVAL/CVAL for programmable interrupts
- Full capabilities: Both CLOCKSOURCE and CLOCKEVENT
**Usage:**
```c
// In your BSP board.c or timer initialization
rt_clock_time_arm_gtimer_init();
// In your timer ISR
void ARM_GTIMER_IRQHandler(void)
{
rt_interrupt_enter();
rt_clock_time_arm_gtimer_isr();
rt_interrupt_leave();
}
```
**Registers Used:**
- CNTFRQ_EL0: Counter frequency
- CNTPCT_EL0: Physical counter value
- CNTP_TVAL_EL0: Timer value (countdown)
- CNTP_CTL_EL0: Timer control
### 2. SysTick/DWT (`clock_time_systick.c`)
**Target Platforms:**
- ARM Cortex-M0/M0+/M3/M4/M7/M33/M55
**Features:**
- Clocksource: Uses DWT CYCCNT (cycle counter) if available
- Falls back to tick counter if DWT is not available
- Clockevent: Not supported (SysTick is used for system tick)
**Usage:**
```c
// DWT is automatically enabled during initialization
// No ISR needed - this is clocksource only
// Optional: Set CPU frequency if SystemCoreClock is not accurate
rt_clock_time_systick_set_freq(168000000); // 168 MHz
```
**Notes:**
- DWT may not be available on all Cortex-M cores or may be disabled by debugger
- Provides microsecond-level precision on typical MCUs (>= 1 MHz clock)
- For clockevent capability, pair with a hardware timer (TIM, LPTIM, etc.)
## Creating Your Own Adapter
To create an adapter for your hardware timer:
### Step 1: Implement the ops structure
```c
static rt_uint64_t my_timer_get_freq(void)
{
return TIMER_FREQUENCY_HZ;
}
static rt_uint64_t my_timer_get_counter(void)
{
return MY_TIMER->COUNT; /* Read hardware counter */
}
static rt_err_t my_timer_set_timeout(rt_uint64_t delta)
{
if (delta == 0)
{
/* Cancel timeout */
MY_TIMER->CTRL &= ~TIMER_ENABLE;
return RT_EOK;
}
/* Set compare value for interrupt */
MY_TIMER->COMPARE = MY_TIMER->COUNT + delta;
MY_TIMER->CTRL |= 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,
};
```
### Step 2: Register the device
```c
int my_timer_init(void)
{
static struct rt_clock_time_device my_device;
/* Initialize hardware */
// ... hardware setup code ...
my_device.ops = &my_timer_ops;
/* Register with appropriate capabilities */
return rt_clock_time_device_register(&my_device, "my_timer",
RT_CLOCK_TIME_CAP_CLOCKSOURCE | RT_CLOCK_TIME_CAP_CLOCKEVENT);
}
INIT_DEVICE_EXPORT(my_timer_init);
```
### Step 3: Implement ISR (if using clockevent)
```c
void MY_TIMER_IRQHandler(void)
{
rt_interrupt_enter();
/* Clear hardware interrupt flag */
MY_TIMER->STATUS = TIMER_INT_FLAG;
/* Process high-resolution timer timeouts */
rt_clock_hrtimer_process();
rt_interrupt_leave();
}
```
## Capability Selection Guidelines
### Clocksource Only
Use when:
- Timer can only provide a counter, no interrupt capability
- Timer is already used for system tick
- Examples: SysTick (used for OS tick), Read-only counters
### Clockevent Only
Use when:
- Timer can generate interrupts but has no readable counter
- Rare case, most timers have both
### Both Clocksource and Clockevent
Use when:
- Timer has a readable counter AND can generate interrupts
- This is the most common and preferred configuration
- Examples: ARM Generic Timer, most hardware timers
## Performance Considerations
### Counter Frequency
- **Low frequency (1-100 kHz)**: Good for power-sensitive applications, limited precision
- **Medium frequency (1-10 MHz)**: Good balance for most MCU applications
- **High frequency (>10 MHz)**: Best precision, higher CPU overhead
### Counter Width
- **16-bit**: May overflow quickly, need careful handling
- **32-bit**: Good for most applications, overflows after ~4 seconds at 1 GHz
- **64-bit**: Effectively never overflows, preferred for ARMv8
### Interrupt Latency
- Keep ISR short - only call `rt_clock_hrtimer_process()`
- Disable timer interrupt while processing to avoid re-entry
- Consider interrupt priority relative to other system interrupts
## Debugging Tips
1. **Verify frequency**: Print actual frequency during initialization
```c
rt_kprintf("Timer freq: %d Hz\n", (rt_uint32_t)rt_clock_time_getfreq());
```
2. **Test counter increment**: Verify counter is actually counting
```c
rt_uint64_t cnt1 = rt_clock_time_getcnt();
rt_thread_mdelay(1);
rt_uint64_t cnt2 = rt_clock_time_getcnt();
rt_kprintf("Counter delta: %d (expected ~%d)\n",
(rt_uint32_t)(cnt2 - cnt1),
(rt_uint32_t)(rt_clock_time_getfreq() / 1000));
```
3. **Check interrupt firing**: Add debug output in ISR
```c
static int isr_count = 0;
void timer_isr(void) {
isr_count++;
if (isr_count % 1000 == 0) {
rt_kprintf("Timer ISR count: %d\n", isr_count);
}
}
```
## Examples in BSPs
Look for these files in various BSPs for real-world examples:
- `bsp/qemu-virt64-aarch64/drivers/drv_timer.c` - ARM Generic Timer
- `bsp/stm32/libraries/HAL_Drivers/drv_hwtimer.c` - STM32 hardware timers
- `bsp/rockchip/*/driver/hwtimer/` - Rockchip timer drivers
## Contributing
When contributing a new adapter:
1. Add comprehensive comments explaining hardware specifics
2. Include initialization and ISR examples
3. Document any platform-specific requirements
4. Test on actual hardware if possible
5. Update this README with your adapter details
|