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