|
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