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