|
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 |
34 |
| - |
35 |
| -typedef struct hw_timer_s |
36 |
| -{ |
37 |
| - uint8_t group; |
38 |
| - uint8_t num; |
39 |
| -} hw_timer_t; |
40 |
| - |
41 |
| -// Works for all chips |
42 |
| -static hw_timer_t timer_dev[4] = { |
43 |
| - {0,0}, {1,0}, {0,1}, {1,1} |
44 |
| -}; |
45 |
| - |
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){ |
| 20 | +inline uint64_t timerRead(hw_timer_t timer_handle){ |
51 | 21 |
|
52 | 22 | uint64_t value;
|
53 |
| - timer_get_counter_value(timer->group, timer->num,&value); |
| 23 | + gptimer_get_raw_count(timer_handle, &value); |
54 | 24 | return value;
|
55 | 25 | }
|
56 |
| - |
57 |
| -uint64_t timerAlarmRead(hw_timer_t *timer){ |
58 |
| - uint64_t value; |
59 |
| - timer_get_alarm_value(timer->group, timer->num, &value); |
60 |
| - return value; |
61 |
| -} |
62 |
| - |
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); |
108 |
| -} |
109 |
| - |
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); |
| 26 | +void timerWrite(hw_timer_t timer_handle, uint64_t val){ |
| 27 | + gptimer_set_raw_count(timer_handle, val); |
144 | 28 | }
|
145 | 29 |
|
146 |
| -void timerStop(hw_timer_t *timer){ |
147 |
| - timer_pause(timer->group, timer->num); |
148 |
| -} |
149 |
| - |
150 |
| -void timerRestart(hw_timer_t *timer){ |
151 |
| - timerWrite(timer,0); |
| 30 | +void timerAlarmWrite(hw_timer_t timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count){ |
| 31 | + esp_err_t err = ESP_OK; |
| 32 | + gptimer_alarm_config_t alarm_cfg = { |
| 33 | + .alarm_count = alarm_value, |
| 34 | + .reload_count = reload_count, |
| 35 | + .flags.auto_reload_on_alarm = autoreload, |
| 36 | + }; |
| 37 | + err = gptimer_set_alarm_action(timer, &alarm_cfg); |
| 38 | + if (err != ESP_OK){ |
| 39 | + log_e("Timer Alarm Write failed, error num=%d", err); |
| 40 | + } |
152 | 41 | }
|
153 | 42 |
|
154 |
| -bool timerStarted(hw_timer_t *timer){ |
155 |
| - timer_cfg_t config; |
156 |
| - config.val = timerGetConfig(timer); |
157 |
| - return config.enable; |
| 43 | +uint32_t timerGetResolution(hw_timer_t timer_handle){ |
| 44 | + uint32_t resolution; |
| 45 | + gptimer_get_resolution(timer_handle, &resolution); |
| 46 | + return resolution; |
158 | 47 | }
|
159 | 48 |
|
160 |
| -void timerAlarmEnable(hw_timer_t *timer){ |
161 |
| - timer_set_alarm(timer->group, timer->num,true); |
| 49 | +void timerStart(hw_timer_t timer_handle){ |
| 50 | + gptimer_start(timer_handle); |
162 | 51 | }
|
163 | 52 |
|
164 |
| -void timerAlarmDisable(hw_timer_t *timer){ |
165 |
| - timer_set_alarm(timer->group, timer->num,false); |
| 53 | +void timerStop(hw_timer_t timer_handle){ |
| 54 | + gptimer_stop(timer_handle); |
166 | 55 | }
|
167 | 56 |
|
168 |
| -bool timerAlarmEnabled(hw_timer_t *timer){ |
169 |
| - timer_cfg_t config; |
170 |
| - config.val = timerGetConfig(timer); |
171 |
| - return config.alarm_en; |
| 57 | +void timerRestart(hw_timer_t timer_handle){ |
| 58 | + gptimer_set_raw_count(timer_handle,0); |
172 | 59 | }
|
173 | 60 |
|
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); |
| 61 | +hw_timer_t timerBegin(uint32_t resolution, bool countUp){ |
| 62 | + |
| 63 | + esp_err_t err = ESP_OK; |
| 64 | + hw_timer_t timer_handle; |
| 65 | + uint32_t counter_src_hz = 0; |
| 66 | + uint32_t divider = 0; |
| 67 | + soc_periph_gptimer_clk_src_t clk; |
| 68 | + |
| 69 | + soc_periph_gptimer_clk_src_t gptimer_clks[] = SOC_GPTIMER_CLKS; |
| 70 | + for (size_t i = 0; i < sizeof(gptimer_clks) / sizeof(gptimer_clks[0]); i++){ |
| 71 | + clk = gptimer_clks[i]; |
| 72 | + clk_tree_src_get_freq_hz(clk, CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz); |
| 73 | + divider = counter_src_hz / resolution; |
| 74 | + if((divider >= 2) && (divider <= 65536)){ |
| 75 | + break; |
| 76 | + } |
| 77 | + else divider = 0; |
184 | 78 | }
|
185 |
| -} |
186 | 79 |
|
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); |
| 80 | + if(divider == 0){ |
| 81 | + log_e("Resolution cannot be reached with any clock source, aborting!"); |
191 | 82 | return NULL;
|
192 | 83 | }
|
193 | 84 |
|
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, |
| 85 | + gptimer_config_t config = { |
| 86 | + .clk_src = clk, |
| 87 | + .direction = countUp, |
| 88 | + .resolution_hz = resolution, |
| 89 | + .flags.intr_shared = true, |
202 | 90 | };
|
203 | 91 |
|
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); |
208 |
| - return timer; |
| 92 | + err = gptimer_new_timer(&config, &timer_handle); |
| 93 | + if (err != ESP_OK){ |
| 94 | + log_e("Failed to create a new GPTimer, error num=%d", err); |
| 95 | + return NULL; |
| 96 | + } |
| 97 | + gptimer_enable(timer_handle); |
| 98 | + gptimer_start(timer_handle); |
| 99 | + return timer_handle; |
209 | 100 | }
|
210 | 101 |
|
211 |
| -void timerEnd(hw_timer_t *timer){ |
212 |
| - removeApbChangeCallback(timer, _on_apb_change); |
213 |
| - timer_deinit(timer->group, timer->num); |
| 102 | +void timerEnd(hw_timer_t timer_handle){ |
| 103 | + esp_err_t err = ESP_OK; |
| 104 | + gptimer_disable(timer_handle); |
| 105 | + err = gptimer_del_timer(timer_handle); |
| 106 | + if (err != ESP_OK){ |
| 107 | + log_e("Failed to destroy GPTimer, error num=%d", err); |
| 108 | + } |
214 | 109 | }
|
215 | 110 |
|
216 |
| -bool IRAM_ATTR timerFnWrapper(void *arg){ |
| 111 | +bool IRAM_ATTR timerFnWrapper(hw_timer_t timer, const gptimer_alarm_event_data_t *edata, void *arg){ |
217 | 112 | void (*fn)(void) = arg;
|
218 | 113 | fn();
|
219 | 114 |
|
220 | 115 | // some additional logic or handling may be required here to approriately yield or not
|
221 | 116 | return false;
|
222 | 117 | }
|
223 | 118 |
|
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 |
| -} |
| 119 | +void timerAttachInterrupt(hw_timer_t timer, void (*fn)(void)){ |
| 120 | + esp_err_t err = ESP_OK; |
| 121 | + gptimer_event_callbacks_t cbs = { |
| 122 | + .on_alarm = timerFnWrapper, |
| 123 | + }; |
230 | 124 |
|
231 |
| -void timerAttachInterrupt(hw_timer_t *timer, void (*fn)(void), bool edge){ |
232 |
| - timerAttachInterruptFlag(timer, fn, edge, 0); |
| 125 | + gptimer_disable(timer); |
| 126 | + err = gptimer_register_event_callbacks(timer, &cbs, fn); |
| 127 | + if (err != ESP_OK){ |
| 128 | + log_e("Timer Attach Interrupt failed, error num=%d", err); |
| 129 | + } |
| 130 | + gptimer_enable(timer); |
233 | 131 | }
|
234 | 132 |
|
235 |
| -void timerDetachInterrupt(hw_timer_t *timer){ |
236 |
| - timer_isr_callback_remove(timer->group, timer->num); |
| 133 | +void timerDetachInterrupt(hw_timer_t timer){ |
| 134 | + esp_err_t err = ESP_OK; |
| 135 | + err = gptimer_set_alarm_action(timer, NULL); |
| 136 | + if (err != ESP_OK){ |
| 137 | + log_e("Timer Detach Interrupt failed, error num=%d", err); |
| 138 | + } |
237 | 139 | }
|
238 | 140 |
|
239 |
| -uint64_t timerReadMicros(hw_timer_t *timer){ |
| 141 | +uint64_t timerReadMicros(hw_timer_t timer){ |
240 | 142 | uint64_t timer_val = timerRead(timer);
|
241 |
| - uint16_t div = timerGetDivider(timer); |
242 |
| - return timer_val * div / (getApbFrequency() / 1000000); |
| 143 | + uint32_t resolution = timerGetResolution(timer); |
| 144 | + return timer_val * 1000000 / resolution; |
243 | 145 | }
|
244 | 146 |
|
245 |
| -uint64_t timerReadMilis(hw_timer_t *timer){ |
| 147 | +uint64_t timerReadMilis(hw_timer_t timer){ |
246 | 148 | uint64_t timer_val = timerRead(timer);
|
247 |
| - uint16_t div = timerGetDivider(timer); |
248 |
| - return timer_val * div / (getApbFrequency() / 1000); |
| 149 | + uint32_t resolution = timerGetResolution(timer); |
| 150 | + return timer_val * 1000 / resolution; |
249 | 151 | }
|
250 | 152 |
|
251 |
| -double timerReadSeconds(hw_timer_t *timer){ |
| 153 | +double timerReadSeconds(hw_timer_t timer){ |
252 | 154 | uint64_t timer_val = timerRead(timer);
|
253 |
| - uint16_t div = timerGetDivider(timer); |
254 |
| - return (double)timer_val * div / getApbFrequency(); |
255 |
| -} |
256 |
| - |
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); |
261 |
| -} |
262 |
| - |
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); |
267 |
| -} |
268 |
| - |
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(); |
| 155 | + uint32_t resolution = timerGetResolution(timer); |
| 156 | + return (double)timer_val / resolution; |
273 | 157 | }
|
0 commit comments