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