1 /*
2 * Copyright (c) 2006-2024 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2015-08-31 heyuanjie87 first version
9 */
10
11 #include <rtdevice.h>
12 #include <rthw.h>
13
14 #define DBG_TAG "hwtimer"
15 #define DBG_LVL DBG_INFO
16 #include <rtdbg.h>
17
18 #ifdef RT_USING_DM
19 void (*rt_device_hwtimer_us_delay)(rt_uint32_t us) = RT_NULL;
20
rt_hw_us_delay(rt_uint32_t us)21 void rt_hw_us_delay(rt_uint32_t us)
22 {
23 if (rt_device_hwtimer_us_delay)
24 {
25 rt_device_hwtimer_us_delay(us);
26 }
27 else
28 {
29 LOG_E("Implemented at least in the libcpu");
30
31 RT_ASSERT(0);
32 }
33 }
34 #endif /* RT_USING_DM */
35
timeout_calc(rt_hwtimer_t * timer,rt_hwtimerval_t * tv)36 rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv)
37 {
38 float overflow;
39 float timeout;
40 rt_uint32_t counter;
41 int i, index = 0;
42 float tv_sec;
43 float devi_min = 1;
44 float devi;
45
46 /* changed to second */
47 overflow = timer->info->maxcnt/(float)timer->freq;
48 tv_sec = tv->sec + tv->usec/(float)1000000;
49
50 if (tv_sec < (1/(float)timer->freq))
51 {
52 /* little timeout */
53 i = 0;
54 timeout = 1/(float)timer->freq;
55 }
56 else
57 {
58 for (i = 1; i > 0; i ++)
59 {
60 timeout = tv_sec/i;
61
62 if (timeout <= overflow)
63 {
64 counter = (rt_uint32_t)(timeout * timer->freq);
65 devi = tv_sec - (counter / (float)timer->freq) * i;
66 /* Minimum calculation error */
67 if (devi > devi_min)
68 {
69 i = index;
70 timeout = tv_sec/i;
71 break;
72 }
73 else if (devi == 0)
74 {
75 break;
76 }
77 else if (devi < devi_min)
78 {
79 devi_min = devi;
80 index = i;
81 }
82 }
83 }
84 }
85
86 timer->cycles = i;
87 timer->reload = i;
88 timer->period_sec = timeout;
89 counter = (rt_uint32_t)(timeout * timer->freq);
90
91 return counter;
92 }
93
rt_hwtimer_init(struct rt_device * dev)94 static rt_err_t rt_hwtimer_init(struct rt_device *dev)
95 {
96 rt_err_t result = RT_EOK;
97 rt_hwtimer_t *timer;
98
99 timer = (rt_hwtimer_t *)dev;
100 /* try to change to 1MHz */
101 if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq))
102 {
103 timer->freq = 1000000;
104 }
105 else
106 {
107 timer->freq = timer->info->minfreq;
108 }
109 timer->mode = HWTIMER_MODE_ONESHOT;
110 timer->cycles = 0;
111 timer->overflow = 0;
112
113 if (timer->ops->init)
114 {
115 timer->ops->init(timer, 1);
116 }
117 else
118 {
119 result = -RT_ENOSYS;
120 }
121
122 return result;
123 }
124
rt_hwtimer_open(struct rt_device * dev,rt_uint16_t oflag)125 static rt_err_t rt_hwtimer_open(struct rt_device *dev, rt_uint16_t oflag)
126 {
127 rt_err_t result = RT_EOK;
128 rt_hwtimer_t *timer;
129
130 timer = (rt_hwtimer_t *)dev;
131 if (timer->ops->control != RT_NULL)
132 {
133 timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq);
134 }
135 else
136 {
137 result = -RT_ENOSYS;
138 }
139
140 return result;
141 }
142
rt_hwtimer_close(struct rt_device * dev)143 static rt_err_t rt_hwtimer_close(struct rt_device *dev)
144 {
145 rt_err_t result = RT_EOK;
146 rt_hwtimer_t *timer;
147
148 timer = (rt_hwtimer_t*)dev;
149 if (timer->ops->init != RT_NULL)
150 {
151 timer->ops->init(timer, 0);
152 }
153 else
154 {
155 result = -RT_ENOSYS;
156 }
157
158 dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED;
159 dev->rx_indicate = RT_NULL;
160
161 return result;
162 }
163
rt_hwtimer_read(struct rt_device * dev,rt_off_t pos,void * buffer,rt_size_t size)164 static rt_ssize_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
165 {
166 rt_hwtimer_t *timer;
167 rt_hwtimerval_t tv;
168 rt_uint32_t cnt;
169 rt_base_t level;
170 rt_int32_t overflow;
171 float t;
172
173 timer = (rt_hwtimer_t *)dev;
174 if (timer->ops->count_get == RT_NULL)
175 return 0;
176
177 level = rt_hw_interrupt_disable();
178 cnt = timer->ops->count_get(timer);
179 overflow = timer->overflow;
180 rt_hw_interrupt_enable(level);
181
182 if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
183 {
184 cnt = (rt_uint32_t)(timer->freq * timer->period_sec) - cnt;
185 }
186 if (timer->mode == HWTIMER_MODE_ONESHOT)
187 {
188 overflow = 0;
189 }
190
191 t = overflow * timer->period_sec + cnt/(float)timer->freq;
192 tv.sec = (rt_int32_t)t;
193 tv.usec = (rt_int32_t)((t - tv.sec) * 1000000);
194 size = size > sizeof(tv)? sizeof(tv) : size;
195 rt_memcpy(buffer, &tv, size);
196
197 return size;
198 }
199
rt_hwtimer_write(struct rt_device * dev,rt_off_t pos,const void * buffer,rt_size_t size)200 static rt_ssize_t rt_hwtimer_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
201 {
202 rt_base_t level;
203 rt_uint32_t t;
204 rt_hwtimer_mode_t opm = HWTIMER_MODE_PERIOD;
205 rt_hwtimer_t *timer;
206
207 timer = (rt_hwtimer_t *)dev;
208 if ((timer->ops->start == RT_NULL) || (timer->ops->stop == RT_NULL))
209 return 0;
210
211 if (size != sizeof(rt_hwtimerval_t))
212 return 0;
213
214 timer->ops->stop(timer);
215
216 level = rt_hw_interrupt_disable();
217 timer->overflow = 0;
218 rt_hw_interrupt_enable(level);
219
220 t = timeout_calc(timer, (rt_hwtimerval_t*)buffer);
221 if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT))
222 {
223 opm = HWTIMER_MODE_ONESHOT;
224 }
225
226 if (timer->ops->start(timer, t, opm) != RT_EOK)
227 size = 0;
228
229 return size;
230 }
231
rt_hwtimer_control(struct rt_device * dev,int cmd,void * args)232 static rt_err_t rt_hwtimer_control(struct rt_device *dev, int cmd, void *args)
233 {
234 rt_base_t level;
235 rt_err_t result = RT_EOK;
236 rt_hwtimer_t *timer;
237
238 timer = (rt_hwtimer_t *)dev;
239
240 switch (cmd)
241 {
242 case HWTIMER_CTRL_STOP:
243 {
244 if (timer->ops->stop != RT_NULL)
245 {
246 timer->ops->stop(timer);
247 }
248 else
249 {
250 result = -RT_ENOSYS;
251 }
252 }
253 break;
254 case HWTIMER_CTRL_FREQ_SET:
255 {
256 rt_int32_t *f;
257
258 if (args == RT_NULL)
259 {
260 result = -RT_EEMPTY;
261 break;
262 }
263
264 f = (rt_int32_t*)args;
265 if ((*f > timer->info->maxfreq) || (*f < timer->info->minfreq))
266 {
267 LOG_W("frequency setting out of range! It will maintain at %d Hz", timer->freq);
268 result = -RT_EINVAL;
269 break;
270 }
271
272 if (timer->ops->control != RT_NULL)
273 {
274 result = timer->ops->control(timer, cmd, args);
275 if (result == RT_EOK)
276 {
277 level = rt_hw_interrupt_disable();
278 timer->freq = *f;
279 rt_hw_interrupt_enable(level);
280 }
281 }
282 else
283 {
284 result = -RT_ENOSYS;
285 }
286 }
287 break;
288 case HWTIMER_CTRL_INFO_GET:
289 {
290 if (args == RT_NULL)
291 {
292 result = -RT_EEMPTY;
293 break;
294 }
295
296 *((struct rt_hwtimer_info*)args) = *timer->info;
297 }
298 break;
299 case HWTIMER_CTRL_MODE_SET:
300 {
301 rt_hwtimer_mode_t *m;
302
303 if (args == RT_NULL)
304 {
305 result = -RT_EEMPTY;
306 break;
307 }
308
309 m = (rt_hwtimer_mode_t*)args;
310
311 if ((*m != HWTIMER_MODE_ONESHOT) && (*m != HWTIMER_MODE_PERIOD))
312 {
313 result = -RT_ERROR;
314 break;
315 }
316 level = rt_hw_interrupt_disable();
317 timer->mode = *m;
318 rt_hw_interrupt_enable(level);
319 }
320 break;
321 default:
322 {
323 if (timer->ops->control != RT_NULL)
324 {
325 result = timer->ops->control(timer, cmd, args);
326 }
327 else
328 {
329 result = -RT_ENOSYS;
330 }
331 }
332 break;
333 }
334
335 return result;
336 }
337
rt_device_hwtimer_isr(rt_hwtimer_t * timer)338 void rt_device_hwtimer_isr(rt_hwtimer_t *timer)
339 {
340 rt_base_t level;
341
342 RT_ASSERT(timer != RT_NULL);
343
344 level = rt_hw_interrupt_disable();
345
346 timer->overflow ++;
347
348 if (timer->cycles != 0)
349 {
350 timer->cycles --;
351 }
352
353 if (timer->cycles == 0)
354 {
355 timer->cycles = timer->reload;
356
357 rt_hw_interrupt_enable(level);
358
359 if (timer->mode == HWTIMER_MODE_ONESHOT)
360 {
361 if (timer->ops->stop != RT_NULL)
362 {
363 timer->ops->stop(timer);
364 }
365 }
366
367 if (timer->parent.rx_indicate != RT_NULL)
368 {
369 timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval));
370 }
371 }
372 else
373 {
374 rt_hw_interrupt_enable(level);
375 }
376 }
377
378 #ifdef RT_USING_DEVICE_OPS
379 const static struct rt_device_ops hwtimer_ops =
380 {
381 rt_hwtimer_init,
382 rt_hwtimer_open,
383 rt_hwtimer_close,
384 rt_hwtimer_read,
385 rt_hwtimer_write,
386 rt_hwtimer_control
387 };
388 #endif
389
rt_device_hwtimer_register(rt_hwtimer_t * timer,const char * name,void * user_data)390 rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data)
391 {
392 struct rt_device *device;
393
394 RT_ASSERT(timer != RT_NULL);
395 RT_ASSERT(timer->ops != RT_NULL);
396 RT_ASSERT(timer->info != RT_NULL);
397
398 device = &(timer->parent);
399
400 device->type = RT_Device_Class_Timer;
401 device->rx_indicate = RT_NULL;
402 device->tx_complete = RT_NULL;
403
404 #ifdef RT_USING_DEVICE_OPS
405 device->ops = &hwtimer_ops;
406 #else
407 device->init = rt_hwtimer_init;
408 device->open = rt_hwtimer_open;
409 device->close = rt_hwtimer_close;
410 device->read = rt_hwtimer_read;
411 device->write = rt_hwtimer_write;
412 device->control = rt_hwtimer_control;
413 #endif
414 device->user_data = user_data;
415
416 return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
417 }
418