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 * 2022-07-29 rtthread qiu first version
9 */
10 #include "drv_common.h"
11 #include "drv_hwtimer.h"
12
13 #include <board.h>
14 #ifdef BSP_USING_TIM
15
16 /*#define DRV_DEBUG*/
17 #define LOG_TAG "drv.hwtimer"
18 #include <drv_log.h>
19
20 static void isr_timer(void *callback_arg, cyhal_timer_event_t event);
21
22 #ifdef RT_USING_HWTIMER
23 enum
24 {
25 #ifdef BSP_USING_TIM1
26 TIM1_INDEX,
27 #endif
28 #ifdef BSP_USING_TIM2
29 TIM2_INDEX,
30 #endif
31 };
32
33 struct cyp_hwtimer
34 {
35 rt_hwtimer_t time_device;
36 cyhal_timer_t tim_handle;
37 IRQn_Type tim_irqn;
38 char *name;
39 };
40
41 static struct cyp_hwtimer cyp_hwtimer_obj[] =
42 {
43 #ifdef BSP_USING_TIM1
44 TIM1_CONFIG,
45 #endif
46 #ifdef BSP_USING_TIM2
47 TIM2_CONFIG,
48 #endif
49 };
50
timer_init(rt_hwtimer_t * timer,rt_uint32_t state)51 static void timer_init(rt_hwtimer_t *timer, rt_uint32_t state)
52 {
53 RT_ASSERT(timer != RT_NULL);
54
55 cy_rslt_t result = RT_EOK;
56
57 cyhal_timer_t *tim = RT_NULL;
58
59 tim = (cyhal_timer_t *)timer->parent.user_data;
60
61 const cyhal_timer_cfg_t init_timer_cfg =
62 {
63 .compare_value = 0, /* Timer compare value, not used */
64 .period = 9999, /* Defines the timer period */
65 .direction = CYHAL_TIMER_DIR_UP, /* Timer counts up */
66 .is_compare = false, /* Don't use compare mode */
67 .is_continuous = true, /* Run timer indefinitely */
68 .value = 0 /* Initial value of counter */
69 };
70
71 if (state)
72 {
73 /* Initialize the timer object. Does not use input pin ('pin' is NC) and
74 * does not use a pre-configured clock source ('clk' is NULL). */
75 result = cyhal_timer_init(tim, NC, NULL);
76
77 if (result != CY_RSLT_SUCCESS)
78 {
79 LOG_E("timer init error \r\n");
80 return;
81 }
82 else
83 {
84 /* Configure timer period and operation mode such as count direction,
85 duration */
86 cyhal_timer_configure(tim, &init_timer_cfg);
87
88 /* Set the frequency of timer's clock source */
89 cyhal_timer_set_frequency(tim, 10000);
90
91 cyhal_timer_start(tim);
92 }
93 }
94 else
95 {
96 cyhal_timer_free(tim);
97 LOG_E("free time \r\n");
98 }
99 }
100
timer_start(rt_hwtimer_t * timer,rt_uint32_t t,rt_hwtimer_mode_t opmode)101 static rt_err_t timer_start(rt_hwtimer_t *timer, rt_uint32_t t, rt_hwtimer_mode_t opmode)
102 {
103 RT_ASSERT(timer != RT_NULL);
104 RT_ASSERT(opmode != RT_NULL);
105
106 cy_rslt_t result = RT_EOK;
107
108 cyhal_timer_t *tim = RT_NULL;
109
110 tim = (cyhal_timer_t *)timer->parent.user_data;
111
112 const cyhal_timer_cfg_t init_timer_cfg =
113 {
114 .compare_value = 0, /* Timer compare value, not used */
115 .period = t - 1, /* Defines the timer period */
116 .direction = CYHAL_TIMER_DIR_UP, /* Timer counts up */
117 .is_compare = false, /* Don't use compare mode */
118 .is_continuous = true, /* Run timer indefinitely */
119 .value = 0 /* Initial value of counter */
120 };
121 /* Configure timer period and operation mode such as count direction,
122 duration */
123 cyhal_timer_configure(tim, &init_timer_cfg);
124
125 if (opmode == HWTIMER_MODE_ONESHOT)
126 {
127 /* set timer to single mode */
128 cyhal_timer_stop(tim);
129 }
130 else
131 {
132 cyhal_timer_reset(tim);
133 }
134
135 result = cyhal_timer_start(tim);
136 if (result != CY_RSLT_SUCCESS)
137 {
138 LOG_E("time start error\r\n");
139 cyhal_timer_free(tim);
140 }
141
142 /* Assign the ISR to execute on timer interrupt */
143 cyhal_timer_register_callback(tim, isr_timer, NULL);
144
145 /* Set the event on which timer interrupt occurs and enable it */
146 cyhal_timer_enable_event(tim, CYHAL_TIMER_IRQ_TERMINAL_COUNT, 1, true);
147
148 return result;
149 }
150
timer_stop(rt_hwtimer_t * timer)151 static void timer_stop(rt_hwtimer_t *timer)
152 {
153
154 RT_ASSERT(timer != RT_NULL);
155
156 cyhal_timer_t *tim = RT_NULL;
157
158 tim = (cyhal_timer_t *)timer->parent.user_data;
159
160 cyhal_timer_stop(tim);
161 }
162
timer_counter_get(rt_hwtimer_t * timer)163 static rt_uint32_t timer_counter_get(rt_hwtimer_t *timer)
164 {
165 cyhal_timer_t *tim = RT_NULL;
166
167 rt_uint32_t count;
168
169 RT_ASSERT(timer != RT_NULL);
170
171 tim = (cyhal_timer_t *)timer->parent.user_data;
172
173 count = cyhal_timer_read(tim);
174
175 return count;
176 }
177
timer_ctrl(rt_hwtimer_t * timer,rt_uint32_t cmd,void * arg)178 static rt_err_t timer_ctrl(rt_hwtimer_t *timer, rt_uint32_t cmd, void *arg)
179 {
180 RT_ASSERT(timer != RT_NULL);
181 RT_ASSERT(arg != RT_NULL);
182
183 cyhal_timer_t *tim = RT_NULL;
184
185 rt_err_t result = -RT_ERROR;
186
187 tim = (cyhal_timer_t *)timer->parent.user_data;
188
189 switch (cmd)
190 {
191 case HWTIMER_CTRL_FREQ_SET:
192 {
193 rt_uint32_t freq;
194 rt_uint16_t val;
195
196 freq = *((rt_uint32_t *)arg);
197
198 result = cyhal_timer_set_frequency(tim, freq);
199
200 if (result != CY_RSLT_SUCCESS)
201 {
202 LOG_E("cyhal_timer_set_frequency error\r\n");
203 return -RT_ERROR;
204 }
205 }
206 break;
207 default:
208 {
209 result = -RT_EINVAL;
210 }
211 break;
212 }
213 return result;
214 }
215
216 static const struct rt_hwtimer_info _info = TIM_DEV_INFO_CONFIG;
217
218 static const struct rt_hwtimer_ops _ops =
219 {
220 .init = timer_init,
221 .start = timer_start,
222 .stop = timer_stop,
223 .count_get = timer_counter_get,
224 .control = timer_ctrl,
225 };
226
isr_timer(void * callback_arg,cyhal_timer_event_t event)227 static void isr_timer(void *callback_arg, cyhal_timer_event_t event)
228 {
229 /* enter interrupt */
230 rt_interrupt_enter();
231
232 (void)callback_arg;
233 (void)event;
234 #ifdef BSP_USING_TIM1
235 rt_device_hwtimer_isr(&cyp_hwtimer_obj[TIM1_INDEX].time_device);
236 #endif
237 #ifdef BSP_USING_TIM2
238 rt_device_hwtimer_isr(&cyp_hwtimer_obj[TIM2_INDEX].time_device);
239 #endif
240 /* leave interrupt */
241 rt_interrupt_leave();
242 }
243
cyp_hwtimer_init(void)244 int cyp_hwtimer_init(void)
245 {
246 int i = 0;
247 int result = RT_EOK;
248
249 for (i = 0; i < sizeof(cyp_hwtimer_obj) / sizeof(cyp_hwtimer_obj[0]); i++)
250 {
251 cyp_hwtimer_obj[i].time_device.info = &_info;
252 cyp_hwtimer_obj[i].time_device.ops = &_ops;
253 if (rt_device_hwtimer_register(&cyp_hwtimer_obj[i].time_device, cyp_hwtimer_obj[i].name, &cyp_hwtimer_obj[i].tim_handle) != RT_EOK)
254 {
255 LOG_E("%s register failed", cyp_hwtimer_obj[i].name);
256 result = -RT_ERROR;
257 }
258 }
259 return result;
260 }
261 INIT_BOARD_EXPORT(cyp_hwtimer_init);
262
263 #endif /*RT_USING_HWTIMER*/
264 #endif /*BSP_USING_TIM*/
265
266 /* this is a hwtimer test demo*/
267 #include <rtthread.h>
268 #include <rtdevice.h>
269
270 #define HWTIMER_DEV_NAME "time2" /* device name */
271
timeout_cb(rt_device_t dev,rt_size_t size)272 static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
273 {
274 rt_kprintf("this is hwtimer timeout callback fucntion!\n");
275 rt_kprintf("tick is :%d !\n", rt_tick_get());
276
277 return 0;
278 }
279
hwtimer_sample()280 int hwtimer_sample()
281 {
282 rt_err_t ret = RT_EOK;
283 rt_hwtimerval_t timeout_s;
284 rt_device_t hw_dev = RT_NULL;
285 rt_hwtimer_mode_t mode;
286 rt_uint32_t freq = 10000;
287
288 hw_dev = rt_device_find(HWTIMER_DEV_NAME);
289 if (hw_dev == RT_NULL)
290 {
291 rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
292 return -RT_ERROR;
293 }
294
295 ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
296 if (ret != RT_EOK)
297 {
298 rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
299 return ret;
300 }
301
302 rt_device_set_rx_indicate(hw_dev, timeout_cb);
303
304 rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
305
306 mode = HWTIMER_MODE_PERIOD;
307 ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
308 if (ret != RT_EOK)
309 {
310 rt_kprintf("set mode failed! ret is :%d\n", ret);
311 return ret;
312 }
313
314 /* Example Set the timeout period of the timer */
315 timeout_s.sec = 3; /* secend */
316 timeout_s.usec = 0; /* microsecend */
317 if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
318 {
319 rt_kprintf("set timeout value failed\n");
320 return -RT_ERROR;
321 }
322
323 while (1)
324 {
325 rt_thread_mdelay(1500);
326
327 rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
328 rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
329 }
330 return ret;
331 }
332 MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample);
333