xref: /nrf52832-nimble/rt-thread/components/drivers/hwtimer/hwtimer.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, 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 <rtthread.h>
12 #include <rtdevice.h>
13 
timeout_calc(rt_hwtimer_t * timer,rt_hwtimerval_t * tv)14 rt_inline rt_uint32_t timeout_calc(rt_hwtimer_t *timer, rt_hwtimerval_t *tv)
15 {
16     float overflow;
17     float timeout;
18     rt_uint32_t counter;
19     int i, index = 0;
20     float tv_sec;
21     float devi_min = 1;
22     float devi;
23 
24     /* changed to second */
25     overflow = timer->info->maxcnt/(float)timer->freq;
26     tv_sec = tv->sec + tv->usec/(float)1000000;
27 
28     if (tv_sec < (1/(float)timer->freq))
29     {
30         /* little timeout */
31         i = 0;
32         timeout = 1/(float)timer->freq;
33     }
34     else
35     {
36         for (i = 1; i > 0; i ++)
37         {
38             timeout = tv_sec/i;
39 
40             if (timeout <= overflow)
41             {
42                 counter = timeout*timer->freq;
43                 devi = tv_sec - (counter/(float)timer->freq)*i;
44                 /* Minimum calculation error */
45                 if (devi > devi_min)
46                 {
47                     i = index;
48                     timeout = tv_sec/i;
49                     break;
50                 }
51                 else if (devi == 0)
52                 {
53                     break;
54                 }
55                 else if (devi < devi_min)
56                 {
57                     devi_min = devi;
58                     index = i;
59                 }
60             }
61         }
62     }
63 
64     timer->cycles = i;
65     timer->reload = i;
66     timer->period_sec = timeout;
67     counter = timeout*timer->freq;
68 
69     return counter;
70 }
71 
rt_hwtimer_init(struct rt_device * dev)72 static rt_err_t rt_hwtimer_init(struct rt_device *dev)
73 {
74     rt_err_t result = RT_EOK;
75     rt_hwtimer_t *timer;
76 
77     timer = (rt_hwtimer_t *)dev;
78     /* try to change to 1MHz */
79     if ((1000000 <= timer->info->maxfreq) && (1000000 >= timer->info->minfreq))
80     {
81         timer->freq = 1000000;
82     }
83     else
84     {
85         timer->freq = timer->info->minfreq;
86     }
87     timer->mode = HWTIMER_MODE_ONESHOT;
88     timer->cycles = 0;
89     timer->overflow = 0;
90 
91     if (timer->ops->init)
92     {
93         timer->ops->init(timer, 1);
94     }
95     else
96     {
97         result = -RT_ENOSYS;
98     }
99 
100     return result;
101 }
102 
rt_hwtimer_open(struct rt_device * dev,rt_uint16_t oflag)103 static rt_err_t rt_hwtimer_open(struct rt_device *dev, rt_uint16_t oflag)
104 {
105     rt_err_t result = RT_EOK;
106     rt_hwtimer_t *timer;
107 
108     timer = (rt_hwtimer_t *)dev;
109     if (timer->ops->control != RT_NULL)
110     {
111         timer->ops->control(timer, HWTIMER_CTRL_FREQ_SET, &timer->freq);
112     }
113     else
114     {
115         result = -RT_ENOSYS;
116     }
117 
118     return result;
119 }
120 
rt_hwtimer_close(struct rt_device * dev)121 static rt_err_t rt_hwtimer_close(struct rt_device *dev)
122 {
123     rt_err_t result = RT_EOK;
124     rt_hwtimer_t *timer;
125 
126     timer = (rt_hwtimer_t*)dev;
127     if (timer->ops->init != RT_NULL)
128     {
129         timer->ops->init(timer, 0);
130     }
131     else
132     {
133         result = -RT_ENOSYS;
134     }
135 
136     dev->flag &= ~RT_DEVICE_FLAG_ACTIVATED;
137     dev->rx_indicate = RT_NULL;
138 
139     return result;
140 }
141 
rt_hwtimer_read(struct rt_device * dev,rt_off_t pos,void * buffer,rt_size_t size)142 static rt_size_t rt_hwtimer_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size)
143 {
144     rt_hwtimer_t *timer;
145     rt_hwtimerval_t tv;
146     rt_uint32_t cnt;
147     float t;
148 
149     timer = (rt_hwtimer_t *)dev;
150     if (timer->ops->count_get == RT_NULL)
151         return 0;
152 
153     cnt = timer->ops->count_get(timer);
154     if (timer->info->cntmode == HWTIMER_CNTMODE_DW)
155     {
156         cnt = (timer->freq * timer->period_sec) - cnt;
157     }
158 
159     t = timer->overflow * timer->period_sec + cnt/(float)timer->freq;
160     tv.sec = t;
161     tv.usec = (t - tv.sec) * 1000000;
162     size = size > sizeof(tv)? sizeof(tv) : size;
163     rt_memcpy(buffer, &tv, size);
164 
165     return size;
166 }
167 
rt_hwtimer_write(struct rt_device * dev,rt_off_t pos,const void * buffer,rt_size_t size)168 static rt_size_t rt_hwtimer_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size)
169 {
170     rt_uint32_t t;
171     rt_hwtimer_mode_t opm = HWTIMER_MODE_PERIOD;
172     rt_hwtimer_t *timer;
173 
174     timer = (rt_hwtimer_t *)dev;
175     if ((timer->ops->start == RT_NULL) || (timer->ops->stop == RT_NULL))
176         return 0;
177 
178     if (size != sizeof(rt_hwtimerval_t))
179         return 0;
180 
181     timer->ops->stop(timer);
182     timer->overflow = 0;
183 
184     t = timeout_calc(timer, (rt_hwtimerval_t*)buffer);
185     if ((timer->cycles <= 1) && (timer->mode == HWTIMER_MODE_ONESHOT))
186     {
187         opm = HWTIMER_MODE_ONESHOT;
188     }
189 
190     if (timer->ops->start(timer, t, opm) != RT_EOK)
191         size = 0;
192 
193     return size;
194 }
195 
rt_hwtimer_control(struct rt_device * dev,int cmd,void * args)196 static rt_err_t rt_hwtimer_control(struct rt_device *dev, int cmd, void *args)
197 {
198     rt_err_t result = RT_EOK;
199     rt_hwtimer_t *timer;
200 
201     timer = (rt_hwtimer_t *)dev;
202 
203     switch (cmd)
204     {
205     case HWTIMER_CTRL_STOP:
206     {
207         if (timer->ops->stop != RT_NULL)
208         {
209             timer->ops->stop(timer);
210         }
211         else
212         {
213             result = -RT_ENOSYS;
214         }
215     }
216     break;
217     case HWTIMER_CTRL_FREQ_SET:
218     {
219         rt_uint32_t *f;
220 
221         if (args == RT_NULL)
222         {
223             result = -RT_EEMPTY;
224             break;
225         }
226 
227         f = (rt_uint32_t*)args;
228         if ((*f > timer->info->maxfreq) || (*f < timer->info->minfreq))
229         {
230             result = -RT_ERROR;
231             break;
232         }
233 
234         if (timer->ops->control != RT_NULL)
235         {
236             result = timer->ops->control(timer, cmd, args);
237             if (result == RT_EOK)
238             {
239                 timer->freq = *f;
240             }
241         }
242         else
243         {
244             result = -RT_ENOSYS;
245         }
246     }
247     break;
248     case HWTIMER_CTRL_INFO_GET:
249     {
250         if (args == RT_NULL)
251         {
252             result = -RT_EEMPTY;
253             break;
254         }
255 
256         *((struct rt_hwtimer_info*)args) = *timer->info;
257     }
258     case HWTIMER_CTRL_MODE_SET:
259     {
260         rt_hwtimer_mode_t *m;
261 
262         if (args == RT_NULL)
263         {
264             result = -RT_EEMPTY;
265             break;
266         }
267 
268         m = (rt_hwtimer_mode_t*)args;
269 
270         if ((*m != HWTIMER_MODE_ONESHOT) && (*m != HWTIMER_MODE_PERIOD))
271         {
272             result = -RT_ERROR;
273             break;
274         }
275 
276         timer->mode = *m;
277     }
278     break;
279     default:
280     {
281         result = -RT_ENOSYS;
282     }
283     break;
284     }
285 
286     return result;
287 }
288 
rt_device_hwtimer_isr(rt_hwtimer_t * timer)289 void rt_device_hwtimer_isr(rt_hwtimer_t *timer)
290 {
291     RT_ASSERT(timer != RT_NULL);
292 
293     timer->overflow ++;
294 
295     if (timer->cycles != 0)
296     {
297         timer->cycles --;
298     }
299 
300     if (timer->cycles == 0)
301     {
302         timer->cycles = timer->reload;
303 
304         if (timer->mode == HWTIMER_MODE_ONESHOT)
305         {
306             if (timer->ops->stop != RT_NULL)
307             {
308                 timer->ops->stop(timer);
309             }
310         }
311 
312         if (timer->parent.rx_indicate != RT_NULL)
313         {
314             timer->parent.rx_indicate(&timer->parent, sizeof(struct rt_hwtimerval));
315         }
316     }
317 }
318 
319 #ifdef RT_USING_DEVICE_OPS
320 const static struct rt_device_ops hwtimer_ops =
321 {
322     rt_hwtimer_init,
323     rt_hwtimer_open,
324     rt_hwtimer_close,
325     rt_hwtimer_read,
326     rt_hwtimer_write,
327     rt_hwtimer_control
328 };
329 #endif
330 
rt_device_hwtimer_register(rt_hwtimer_t * timer,const char * name,void * user_data)331 rt_err_t rt_device_hwtimer_register(rt_hwtimer_t *timer, const char *name, void *user_data)
332 {
333     struct rt_device *device;
334 
335     RT_ASSERT(timer != RT_NULL);
336     RT_ASSERT(timer->ops != RT_NULL);
337     RT_ASSERT(timer->info != RT_NULL);
338 
339     device = &(timer->parent);
340 
341     device->type        = RT_Device_Class_Timer;
342     device->rx_indicate = RT_NULL;
343     device->tx_complete = RT_NULL;
344 
345 #ifdef RT_USING_DEVICE_OPS
346     device->ops         = &hwtimer_ops;
347 #else
348     device->init        = rt_hwtimer_init;
349     device->open        = rt_hwtimer_open;
350     device->close       = rt_hwtimer_close;
351     device->read        = rt_hwtimer_read;
352     device->write       = rt_hwtimer_write;
353     device->control     = rt_hwtimer_control;
354 #endif
355     device->user_data   = user_data;
356 
357     return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_STANDALONE);
358 }
359