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