|
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | 15 | #include "esp32-hal-timer.h" |
16 | | -#include "driver/timer.h" |
| 16 | +#include "driver/gptimer.h" |
17 | 17 | #include "soc/soc_caps.h" |
| 18 | +#include "clk_tree.h" |
18 | 19 |
|
19 | | -typedef union { |
20 | | - struct { |
21 | | - uint32_t reserved0: 10; |
22 | | - uint32_t alarm_en: 1; /*When set alarm is enabled*/ |
23 | | - uint32_t level_int_en: 1; /*When set level type interrupt will be generated during alarm*/ |
24 | | - uint32_t edge_int_en: 1; /*When set edge type interrupt will be generated during alarm*/ |
25 | | - uint32_t divider: 16; /*Timer clock (T0/1_clk) pre-scale value.*/ |
26 | | - uint32_t autoreload: 1; /*When set timer 0/1 auto-reload at alarming is enabled*/ |
27 | | - uint32_t increase: 1; /*When set timer 0/1 time-base counter increment. When cleared timer 0 time-base counter decrement.*/ |
28 | | - uint32_t enable: 1; /*When set timer 0/1 time-base counter is enabled*/ |
29 | | - }; |
30 | | - uint32_t val; |
31 | | -} timer_cfg_t; |
32 | | - |
33 | | -#define NUM_OF_TIMERS SOC_TIMER_GROUP_TOTAL_TIMERS |
| 20 | +typedef void (*voidFuncPtr)(void); |
| 21 | +typedef void (*voidFuncPtrArg)(void*); |
34 | 22 |
|
35 | | -typedef struct hw_timer_s |
36 | | -{ |
37 | | - uint8_t group; |
38 | | - uint8_t num; |
39 | | -} hw_timer_t; |
| 23 | +typedef struct { |
| 24 | + voidFuncPtr fn; |
| 25 | + void* arg; |
| 26 | +} interrupt_config_t; |
40 | 27 |
|
41 | | -// Works for all chips |
42 | | -static hw_timer_t timer_dev[4] = { |
43 | | - {0,0}, {1,0}, {0,1}, {1,1} |
| 28 | +struct timer_struct_t { |
| 29 | + gptimer_handle_t timer_handle; |
| 30 | + interrupt_config_t interrupt_handle; |
44 | 31 | }; |
45 | 32 |
|
46 | | -// NOTE: (in IDF 5.0 there wont be need to know groups/numbers |
47 | | -// timer_init() will list thru all timers and return free timer handle) |
48 | | - |
49 | | - |
50 | | -inline uint64_t timerRead(hw_timer_t *timer){ |
51 | | - |
52 | | - uint64_t value; |
53 | | - timer_get_counter_value(timer->group, timer->num,&value); |
54 | | - return value; |
55 | | -} |
| 33 | +inline uint64_t timerRead(hw_timer_t * timer){ |
56 | 34 |
|
57 | | -uint64_t timerAlarmRead(hw_timer_t *timer){ |
58 | 35 | uint64_t value; |
59 | | - timer_get_alarm_value(timer->group, timer->num, &value); |
| 36 | + gptimer_get_raw_count(timer->timer_handle, &value); |
60 | 37 | return value; |
61 | 38 | } |
62 | 39 |
|
63 | | -void timerWrite(hw_timer_t *timer, uint64_t val){ |
64 | | - timer_set_counter_value(timer->group, timer->num, val); |
65 | | -} |
66 | | - |
67 | | -void timerAlarmWrite(hw_timer_t *timer, uint64_t alarm_value, bool autoreload){ |
68 | | - timer_set_alarm_value(timer->group, timer->num, alarm_value); |
69 | | - timerSetAutoReload(timer,autoreload); |
70 | | -} |
71 | | - |
72 | | -void timerSetConfig(hw_timer_t *timer, uint32_t config){ |
73 | | - timer_cfg_t cfg; |
74 | | - cfg.val = config; |
75 | | - timer_set_alarm(timer->group, timer->num, cfg.alarm_en); |
76 | | - timerSetDivider(timer,cfg.divider); |
77 | | - timerSetAutoReload(timer,cfg.autoreload); |
78 | | - timerSetCountUp(timer, cfg.increase); |
79 | | - |
80 | | - if (cfg.enable) { |
81 | | - timerStart(timer); |
82 | | - } |
83 | | - else{ |
84 | | - timerStop(timer); |
85 | | - } |
86 | | - return; |
87 | | -} |
88 | | - |
89 | | -uint32_t timerGetConfig(hw_timer_t *timer){ |
90 | | - timer_config_t timer_cfg; |
91 | | - timer_get_config(timer->group, timer->num,&timer_cfg); |
92 | | - |
93 | | - //Translate to default uint32_t |
94 | | - timer_cfg_t cfg; |
95 | | - cfg.alarm_en = timer_cfg.alarm_en; |
96 | | - cfg.autoreload = timer_cfg.auto_reload; |
97 | | - cfg.divider = timer_cfg.divider; |
98 | | - cfg.edge_int_en = timer_cfg.intr_type; |
99 | | - cfg.level_int_en = !timer_cfg.intr_type; |
100 | | - cfg.enable = timer_cfg.counter_en; |
101 | | - cfg.increase = timer_cfg.counter_dir; |
102 | | - |
103 | | - return cfg.val; |
104 | | -} |
105 | | - |
106 | | -void timerSetCountUp(hw_timer_t *timer, bool countUp){ |
107 | | - timer_set_counter_mode(timer->group, timer->num,countUp); |
| 40 | +void timerWrite(hw_timer_t * timer, uint64_t val){ |
| 41 | + gptimer_set_raw_count(timer->timer_handle, val); |
108 | 42 | } |
109 | 43 |
|
110 | | -bool timerGetCountUp(hw_timer_t *timer){ |
111 | | - timer_cfg_t config; |
112 | | - config.val = timerGetConfig(timer); |
113 | | - return config.increase; |
114 | | -} |
115 | | - |
116 | | -void timerSetAutoReload(hw_timer_t *timer, bool autoreload){ |
117 | | - timer_set_auto_reload(timer->group, timer->num,autoreload); |
118 | | -} |
119 | | - |
120 | | -bool timerGetAutoReload(hw_timer_t *timer){ |
121 | | - timer_cfg_t config; |
122 | | - config.val= timerGetConfig(timer); |
123 | | - return config.autoreload; |
124 | | -} |
125 | | - |
126 | | -// Set divider from 2 to 65535 |
127 | | -void timerSetDivider(hw_timer_t *timer, uint16_t divider){ |
128 | | - if(divider < 2) |
129 | | - { |
130 | | - log_e("Timer divider must be set in range of 2 to 65535"); |
131 | | - return; |
132 | | - } |
133 | | - timer_set_divider(timer->group, timer->num,divider); |
134 | | -} |
135 | | - |
136 | | -uint16_t timerGetDivider(hw_timer_t *timer){ |
137 | | - timer_cfg_t config; |
138 | | - config.val = timerGetConfig(timer); |
139 | | - return config.divider; |
140 | | -} |
141 | | - |
142 | | -void timerStart(hw_timer_t *timer){ |
143 | | - timer_start(timer->group, timer->num); |
144 | | -} |
145 | | - |
146 | | -void timerStop(hw_timer_t *timer){ |
147 | | - timer_pause(timer->group, timer->num); |
| 44 | +void timerAlarm(hw_timer_t * timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count){ |
| 45 | + esp_err_t err = ESP_OK; |
| 46 | + gptimer_alarm_config_t alarm_cfg = { |
| 47 | + .alarm_count = alarm_value, |
| 48 | + .reload_count = reload_count, |
| 49 | + .flags.auto_reload_on_alarm = autoreload, |
| 50 | + }; |
| 51 | + err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg); |
| 52 | + if (err != ESP_OK){ |
| 53 | + log_e("Timer Alarm Write failed, error num=%d", err); |
| 54 | + } |
148 | 55 | } |
149 | 56 |
|
150 | | -void timerRestart(hw_timer_t *timer){ |
151 | | - timerWrite(timer,0); |
| 57 | +uint32_t timerGetFrequency(hw_timer_t * timer){ |
| 58 | + uint32_t frequency; |
| 59 | + gptimer_get_resolution(timer->timer_handle, &frequency); |
| 60 | + return frequency; |
152 | 61 | } |
153 | 62 |
|
154 | | -bool timerStarted(hw_timer_t *timer){ |
155 | | - timer_cfg_t config; |
156 | | - config.val = timerGetConfig(timer); |
157 | | - return config.enable; |
| 63 | +void timerStart(hw_timer_t * timer){ |
| 64 | + gptimer_start(timer->timer_handle); |
158 | 65 | } |
159 | 66 |
|
160 | | -void timerAlarmEnable(hw_timer_t *timer){ |
161 | | - timer_set_alarm(timer->group, timer->num,true); |
| 67 | +void timerStop(hw_timer_t * timer){ |
| 68 | + gptimer_stop(timer->timer_handle); |
162 | 69 | } |
163 | 70 |
|
164 | | -void timerAlarmDisable(hw_timer_t *timer){ |
165 | | - timer_set_alarm(timer->group, timer->num,false); |
| 71 | +void timerRestart(hw_timer_t * timer){ |
| 72 | + gptimer_set_raw_count(timer->timer_handle,0); |
166 | 73 | } |
167 | 74 |
|
168 | | -bool timerAlarmEnabled(hw_timer_t *timer){ |
169 | | - timer_cfg_t config; |
170 | | - config.val = timerGetConfig(timer); |
171 | | - return config.alarm_en; |
172 | | -} |
| 75 | +hw_timer_t * timerBegin(uint32_t frequency){ |
| 76 | + esp_err_t err = ESP_OK; |
| 77 | + uint32_t counter_src_hz = 0; |
| 78 | + uint32_t divider = 0; |
| 79 | + soc_periph_gptimer_clk_src_t clk; |
173 | 80 |
|
174 | | -static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb){ |
175 | | - hw_timer_t * timer = (hw_timer_t *)arg; |
176 | | - if(ev_type == APB_BEFORE_CHANGE){ |
177 | | - timerStop(timer); |
178 | | - } else { |
179 | | - old_apb /= 1000000; |
180 | | - new_apb /= 1000000; |
181 | | - uint16_t divider = (new_apb * timerGetDivider(timer)) / old_apb; |
182 | | - timerSetDivider(timer,divider); |
183 | | - timerStart(timer); |
| 81 | + soc_periph_gptimer_clk_src_t gptimer_clks[] = SOC_GPTIMER_CLKS; |
| 82 | + for (size_t i = 0; i < sizeof(gptimer_clks) / sizeof(gptimer_clks[0]); i++){ |
| 83 | + clk = gptimer_clks[i]; |
| 84 | + clk_tree_src_get_freq_hz(clk, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz); |
| 85 | + divider = counter_src_hz / frequency; |
| 86 | + if((divider >= 2) && (divider <= 65536)){ |
| 87 | + break; |
| 88 | + } |
| 89 | + else divider = 0; |
184 | 90 | } |
185 | | -} |
186 | 91 |
|
187 | | -hw_timer_t * timerBegin(uint8_t num, uint16_t divider, bool countUp){ |
188 | | - if(num >= NUM_OF_TIMERS) |
189 | | - { |
190 | | - log_e("Timer number %u exceeds available number of Timers.", num); |
| 92 | + if(divider == 0){ |
| 93 | + log_e("Resolution cannot be reached with any clock source, aborting!"); |
191 | 94 | return NULL; |
192 | 95 | } |
193 | 96 |
|
194 | | - hw_timer_t * timer = &timer_dev[num]; //Get Timer group/num from 0-3 number |
195 | | - |
196 | | - timer_config_t config = { |
197 | | - .divider = divider, |
198 | | - .counter_dir = countUp, |
199 | | - .counter_en = TIMER_PAUSE, |
200 | | - .alarm_en = TIMER_ALARM_DIS, |
201 | | - .auto_reload = false, |
| 97 | + gptimer_config_t config = { |
| 98 | + .clk_src = clk, |
| 99 | + .direction = GPTIMER_COUNT_UP, |
| 100 | + .resolution_hz = frequency, |
| 101 | + .flags.intr_shared = true, |
202 | 102 | }; |
203 | 103 |
|
204 | | - timer_init(timer->group, timer->num, &config); |
205 | | - timer_set_counter_value(timer->group, timer->num, 0); |
206 | | - timerStart(timer); |
207 | | - addApbChangeCallback(timer, _on_apb_change); |
| 104 | + hw_timer_t *timer = malloc(sizeof(hw_timer_t)); |
| 105 | + |
| 106 | + err = gptimer_new_timer(&config, &timer->timer_handle); |
| 107 | + if (err != ESP_OK){ |
| 108 | + log_e("Failed to create a new GPTimer, error num=%d", err); |
| 109 | + free(timer); |
| 110 | + return NULL; |
| 111 | + } |
| 112 | + gptimer_enable(timer->timer_handle); |
| 113 | + gptimer_start(timer->timer_handle); |
208 | 114 | return timer; |
209 | 115 | } |
210 | 116 |
|
211 | | -void timerEnd(hw_timer_t *timer){ |
212 | | - removeApbChangeCallback(timer, _on_apb_change); |
213 | | - timer_deinit(timer->group, timer->num); |
| 117 | +void timerEnd(hw_timer_t * timer){ |
| 118 | + esp_err_t err = ESP_OK; |
| 119 | + gptimer_disable(timer->timer_handle); |
| 120 | + err = gptimer_del_timer(timer->timer_handle); |
| 121 | + if (err != ESP_OK){ |
| 122 | + log_e("Failed to destroy GPTimer, error num=%d", err); |
| 123 | + return; |
| 124 | + } |
| 125 | + free(timer); |
214 | 126 | } |
215 | 127 |
|
216 | | -bool IRAM_ATTR timerFnWrapper(void *arg){ |
217 | | - void (*fn)(void) = arg; |
218 | | - fn(); |
219 | | - |
| 128 | +bool IRAM_ATTR timerFnWrapper(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void * args){ |
| 129 | + interrupt_config_t * isr = (interrupt_config_t*)args; |
| 130 | + if(isr->fn) { |
| 131 | + if(isr->arg){ |
| 132 | + ((voidFuncPtrArg)isr->fn)(isr->arg); |
| 133 | + } else { |
| 134 | + isr->fn(); |
| 135 | + } |
| 136 | + } |
220 | 137 | // some additional logic or handling may be required here to approriately yield or not |
221 | 138 | return false; |
222 | 139 | } |
223 | 140 |
|
224 | | -void timerAttachInterruptFlag(hw_timer_t *timer, void (*fn)(void), bool edge, int intr_alloc_flags){ |
225 | | - if(edge){ |
226 | | - log_w("EDGE timer interrupt is not supported! Setting to LEVEL..."); |
227 | | - } |
228 | | - timer_isr_callback_add(timer->group, timer->num, timerFnWrapper, fn, intr_alloc_flags); |
229 | | -} |
| 141 | +void timerAttachInterruptFunctionalArg(hw_timer_t * timer, void (*userFunc)(void*), void * arg){ |
| 142 | + esp_err_t err = ESP_OK; |
| 143 | + gptimer_event_callbacks_t cbs = { |
| 144 | + .on_alarm = timerFnWrapper, |
| 145 | + }; |
230 | 146 |
|
231 | | -void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ |
232 | | - timerAttachInterruptFlag(timer, fn, edge, 0); |
233 | | -} |
| 147 | + timer->interrupt_handle.fn = (voidFuncPtr)userFunc; |
| 148 | + timer->interrupt_handle.arg = arg; |
234 | 149 |
|
235 | | -void timerDetachInterrupt(hw_timer_t *timer){ |
236 | | - timer_isr_callback_remove(timer->group, timer->num); |
| 150 | + gptimer_disable(timer->timer_handle); |
| 151 | + err = gptimer_register_event_callbacks(timer->timer_handle, &cbs, &timer->interrupt_handle); |
| 152 | + if (err != ESP_OK){ |
| 153 | + log_e("Timer Attach Interrupt failed, error num=%d", err); |
| 154 | + } |
| 155 | + gptimer_enable(timer->timer_handle); |
237 | 156 | } |
238 | 157 |
|
239 | | -uint64_t timerReadMicros(hw_timer_t *timer){ |
240 | | - uint64_t timer_val = timerRead(timer); |
241 | | - uint16_t div = timerGetDivider(timer); |
242 | | - return timer_val * div / (getApbFrequency() / 1000000); |
| 158 | + |
| 159 | +void timerAttachInterruptArg(hw_timer_t * timer, void (*userFunc)(void*), void * arg){ |
| 160 | + timerAttachInterruptFunctionalArg(timer, userFunc, arg); |
243 | 161 | } |
244 | 162 |
|
245 | | -uint64_t timerReadMilis(hw_timer_t *timer){ |
246 | | - uint64_t timer_val = timerRead(timer); |
247 | | - uint16_t div = timerGetDivider(timer); |
248 | | - return timer_val * div / (getApbFrequency() / 1000); |
| 163 | +void timerAttachInterrupt(hw_timer_t * timer, voidFuncPtr userFunc){ |
| 164 | + timerAttachInterruptFunctionalArg(timer, (voidFuncPtrArg)userFunc, NULL); |
249 | 165 | } |
250 | 166 |
|
251 | | -double timerReadSeconds(hw_timer_t *timer){ |
252 | | - uint64_t timer_val = timerRead(timer); |
253 | | - uint16_t div = timerGetDivider(timer); |
254 | | - return (double)timer_val * div / getApbFrequency(); |
| 167 | +void timerDetachInterrupt(hw_timer_t * timer){ |
| 168 | + esp_err_t err = ESP_OK; |
| 169 | + err = gptimer_set_alarm_action(timer->timer_handle, NULL); |
| 170 | + timer->interrupt_handle.fn = NULL; |
| 171 | + timer->interrupt_handle.arg = NULL; |
| 172 | + if (err != ESP_OK){ |
| 173 | + log_e("Timer Detach Interrupt failed, error num=%d", err); |
| 174 | + } |
255 | 175 | } |
256 | 176 |
|
257 | | -uint64_t timerAlarmReadMicros(hw_timer_t *timer){ |
258 | | - uint64_t timer_val = timerAlarmRead(timer); |
259 | | - uint16_t div = timerGetDivider(timer); |
260 | | - return timer_val * div / (getApbFrequency() / 1000000); |
| 177 | +uint64_t timerReadMicros(hw_timer_t * timer){ |
| 178 | + uint64_t timer_val = timerRead(timer); |
| 179 | + uint32_t frequency = timerGetFrequency(timer); |
| 180 | + return timer_val * 1000000 / frequency; |
261 | 181 | } |
262 | 182 |
|
263 | | -uint64_t timerAlarmReadMilis(hw_timer_t *timer){ |
264 | | - uint64_t timer_val = timerAlarmRead(timer); |
265 | | - uint16_t div = timerGetDivider(timer); |
266 | | - return timer_val * div / (getApbFrequency() / 1000); |
| 183 | +uint64_t timerReadMilis(hw_timer_t * timer){ |
| 184 | + uint64_t timer_val = timerRead(timer); |
| 185 | + uint32_t frequency = timerGetFrequency(timer); |
| 186 | + return timer_val * 1000 / frequency; |
267 | 187 | } |
268 | 188 |
|
269 | | -double timerAlarmReadSeconds(hw_timer_t *timer){ |
270 | | - uint64_t timer_val = timerAlarmRead(timer); |
271 | | - uint16_t div = timerGetDivider(timer); |
272 | | - return (double)timer_val * div / getApbFrequency(); |
| 189 | +double timerReadSeconds(hw_timer_t * timer){ |
| 190 | + uint64_t timer_val = timerRead(timer); |
| 191 | + uint32_t frequency = timerGetFrequency(timer); |
| 192 | + return (double)timer_val / frequency; |
273 | 193 | } |
0 commit comments