1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date             Author           Notes
8  * 2023-11-15       BetMul      first version
9  */
10 
11 #include "drv_hwtimer.h"
12 
13 #include <rtthread.h>
14 #include <rtdevice.h>
15 #include "driver/gptimer.h"
16 #include "sdkconfig.h"
17 
18 #ifdef RT_USING_HWTIMER
19 
20 /**
21  * handle interrupt for hwtimer.
22  */
mcu_hwtimer_intr_handler(gptimer_handle_t gptimer,const gptimer_alarm_event_data_t * edata,void * user_ctx)23 static bool mcu_hwtimer_intr_handler(gptimer_handle_t gptimer, const gptimer_alarm_event_data_t *edata, void *user_ctx)
24 {
25     rt_interrupt_enter();
26 
27     rt_hwtimer_t *hwtimer = (rt_hwtimer_t *)user_ctx;
28     rt_device_hwtimer_isr(hwtimer);
29 
30     rt_interrupt_leave();
31 
32     return 0;
33 }
34 
35 /**
36  * init the hwtimer
37 */
mcu_hwtimer_init(rt_hwtimer_t * timer,rt_uint32_t state)38 static void mcu_hwtimer_init(rt_hwtimer_t *timer, rt_uint32_t state)
39 {
40     gptimer_handle_t gptimer = (gptimer_handle_t)timer->parent.user_data;
41 
42     // let the gptimer into enable status
43     ESP_ERROR_CHECK(gptimer_enable(gptimer));
44 }
45 
46 /**
47  * start the hwtimer, change status into running
48 */
mcu_hwtimer_start(rt_hwtimer_t * timer,rt_uint32_t cnt,rt_hwtimer_mode_t mode)49 static rt_err_t mcu_hwtimer_start(rt_hwtimer_t *timer, rt_uint32_t cnt, rt_hwtimer_mode_t mode)
50 {
51     gptimer_handle_t gptimer = (gptimer_handle_t)timer->parent.user_data;
52     gptimer_alarm_config_t alarm_config = {
53         .alarm_count = cnt,
54     };
55     if (mode == HWTIMER_MODE_ONESHOT)
56     {
57 
58     }
59     else
60     {
61         alarm_config.reload_count = 0;
62         alarm_config.flags.auto_reload_on_alarm = true;
63     }
64     ESP_ERROR_CHECK(gptimer_set_alarm_action(gptimer, &alarm_config));
65     ESP_ERROR_CHECK(gptimer_start(gptimer));
66 
67     return RT_EOK;
68 }
69 
70 /**
71  * stop the hwtimer, change the status from running into enable
72 */
mcu_hwtimer_stop(rt_hwtimer_t * timer)73 static void mcu_hwtimer_stop(rt_hwtimer_t *timer)
74 {
75     gptimer_handle_t gptimer = (gptimer_handle_t)timer->parent.user_data;
76 
77     ESP_ERROR_CHECK(gptimer_stop(gptimer));
78 }
79 
80 /**
81  * get count
82 */
mcu_hwtimer_count_get(rt_hwtimer_t * timer)83 static rt_uint32_t mcu_hwtimer_count_get(rt_hwtimer_t *timer)
84 {
85     gptimer_handle_t gptimer = (gptimer_handle_t)timer->parent.user_data;
86     // get count number
87     uint64_t value;
88     ESP_ERROR_CHECK(gptimer_get_raw_count(gptimer, &value));
89     return (rt_uint32_t)value;
90 }
91 
92 /**
93  * control the hwtimer
94 */
mcu_hwtimer_control(rt_hwtimer_t * timer,rt_uint32_t cmd,void * args)95 static rt_err_t mcu_hwtimer_control(rt_hwtimer_t *timer, rt_uint32_t cmd, void *args)
96 {
97 
98     rt_err_t err = RT_EOK;
99 
100     switch (cmd)
101     {
102     case HWTIMER_CTRL_FREQ_SET:
103         err = -RT_ERROR;
104         break;
105 
106     case HWTIMER_CTRL_INFO_GET:
107         err = -RT_ERROR;
108         break;
109 
110     case HWTIMER_CTRL_MODE_SET:
111         timer->mode = *(rt_uint32_t *)args;
112         break;
113 
114     case HWTIMER_CTRL_STOP:
115         mcu_hwtimer_stop(timer);
116         break;
117     }
118 
119     return err;
120 }
121 
122 static struct rt_hwtimer_device _hwtimer;
123 static const struct rt_hwtimer_ops _hwtimer_ops =
124     {
125         .init = mcu_hwtimer_init,
126         .start = mcu_hwtimer_start,
127         .stop = mcu_hwtimer_stop,
128         .count_get = mcu_hwtimer_count_get,
129         .control = mcu_hwtimer_control};
130 
131 static const struct rt_hwtimer_info _hwtimer_info =
132     {
133         // TODO:what is the true max and  min?
134         .maxfreq = 1000000UL,
135         .minfreq = 1000000UL,
136         .maxcnt = 0xFFFF,
137         .cntmode = HWTIMER_MODE_ONESHOT};
138 
rt_hw_hwtimer_init(void)139 int rt_hw_hwtimer_init(void)
140 {
141 
142     char *name = "timer0";
143 
144     gptimer_handle_t gptimer = NULL;
145     gptimer_config_t timer_config = {
146         .clk_src = GPTIMER_CLK_SRC_DEFAULT,
147         .direction = GPTIMER_COUNT_UP,
148         .resolution_hz = 1 * 1000 * 1000,
149     };
150 
151     gptimer_event_callbacks_t cbs = {
152         .on_alarm = mcu_hwtimer_intr_handler,
153     };
154 
155     ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
156     ESP_ERROR_CHECK(gptimer_register_event_callbacks(gptimer, &cbs, &_hwtimer));
157 
158     _hwtimer.info = &_hwtimer_info;
159     _hwtimer.ops = &_hwtimer_ops;
160 
161     return rt_device_hwtimer_register(&_hwtimer, name, (void *)gptimer);
162 
163 }
164 
165 INIT_DEVICE_EXPORT(rt_hw_hwtimer_init);
166 #endif /* RT_USING_HWTIMER */
167