Skip to content

Commit eaa7eaf

Browse files
committed
esp32/machine_timer.c: Add find free timer id.
``id`` of -2 selects the ``id`` of a free timer. Check the timer `id` range. Check if the timer is already in use. Signed-off-by: IhorNehrutsa <[email protected]>
1 parent 7ecff51 commit eaa7eaf

File tree

3 files changed

+201
-58
lines changed

3 files changed

+201
-58
lines changed

docs/library/machine.Timer.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Constructors
3131

3232
Construct a new timer object of the given ``id``. ``id`` of -1 constructs a
3333
virtual timer (if supported by a board).
34+
``id`` of -2 selects the ``id`` of a free timer (Supported at ESP32 port).
3435
``id`` shall not be passed as a keyword argument.
3536

3637
See ``init`` for parameters of initialisation.

ports/esp32/machine_timer.c

100644100755
Lines changed: 138 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -30,69 +30,96 @@
3030
#include <stdint.h>
3131
#include <stdio.h>
3232

33+
#include "py/mphal.h"
3334
#include "py/obj.h"
3435
#include "py/runtime.h"
3536
#include "modmachine.h"
36-
#include "mphalport.h"
3737

3838
#include "hal/timer_hal.h"
3939
#include "hal/timer_ll.h"
4040
#include "soc/timer_periph.h"
41+
#include "esp_private/esp_clk_tree_common.h"
42+
#include "esp_private/periph_ctrl.h"
43+
#include "machine_timer.h"
4144

45+
#define TIMER_CLK_SRC GPTIMER_CLK_SRC_DEFAULT
4246
#define TIMER_DIVIDER 8
4347

44-
// TIMER_BASE_CLK is normally 80MHz. TIMER_DIVIDER ought to divide this exactly
45-
#define TIMER_SCALE (APB_CLK_FREQ / TIMER_DIVIDER)
46-
4748
#define TIMER_FLAGS 0
4849

49-
typedef struct _machine_timer_obj_t {
50-
mp_obj_base_t base;
51-
52-
timer_hal_context_t hal_context;
53-
mp_uint_t group;
54-
mp_uint_t index;
55-
56-
mp_uint_t repeat;
57-
// ESP32 timers are 64-bit
58-
uint64_t period;
59-
60-
mp_obj_t callback;
61-
62-
intr_handle_t handle;
63-
64-
struct _machine_timer_obj_t *next;
65-
} machine_timer_obj_t;
66-
6750
const mp_obj_type_t machine_timer_type;
6851

69-
STATIC void machine_timer_disable(machine_timer_obj_t *self);
70-
STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
52+
static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args);
53+
static mp_obj_t machine_timer_deinit(mp_obj_t self_in);
54+
55+
uint32_t machine_timer_freq_hz(void) {
56+
// The timer source clock is APB or a fixed PLL (depending on chip), both constant frequency.
57+
uint32_t freq;
58+
check_esp_err(esp_clk_tree_src_get_freq_hz(TIMER_CLK_SRC, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &freq));
59+
assert(freq % TIMER_DIVIDER == 0); // Source clock should divide evenly into TIMER_DIVIDER
60+
return freq / TIMER_DIVIDER;
61+
}
7162

7263
void machine_timer_deinit_all(void) {
7364
// Disable, deallocate and remove all timers from list
7465
machine_timer_obj_t **t = &MP_STATE_PORT(machine_timer_obj_head);
7566
while (*t != NULL) {
76-
machine_timer_disable(*t);
67+
machine_timer_deinit(*t);
7768
machine_timer_obj_t *next = (*t)->next;
7869
m_del_obj(machine_timer_obj_t, *t);
7970
*t = next;
8071
}
8172
}
8273

83-
STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
74+
static void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
8475
machine_timer_obj_t *self = self_in;
8576
qstr mode = self->repeat ? MP_QSTR_PERIODIC : MP_QSTR_ONE_SHOT;
86-
uint64_t period = self->period / (TIMER_SCALE / 1000); // convert to ms
77+
uint64_t period = self->period / (machine_timer_freq_hz() / 1000); // convert to ms
78+
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP == 1
79+
mp_printf(print, "Timer(%u, mode=%q, period=%lu)", self->group, mode, period);
80+
#else
8781
mp_printf(print, "Timer(%u, mode=%q, period=%lu)", (self->group << 1) | self->index, mode, period);
82+
#endif
8883
}
8984

90-
STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
91-
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
92-
mp_uint_t group = (mp_obj_get_int(args[0]) >> 1) & 1;
93-
mp_uint_t index = mp_obj_get_int(args[0]) & 1;
85+
static bool find_free_timer(mp_int_t *group, mp_int_t *index) {
86+
// from highest to lowest id
87+
for (*group = SOC_TIMER_GROUPS - 1; *group >= 0; --(*group)) {
88+
for (*index = SOC_TIMER_GROUP_TIMERS_PER_GROUP - 1; *index >= 0; --(*index)) {
89+
bool free = true;
90+
// Check whether the timer is already initialized, if so skip it
91+
for (machine_timer_obj_t *t = MP_STATE_PORT(machine_timer_obj_head); t; t = t->next) {
92+
if (t->group == *group && t->index == *index) {
93+
free = false;
94+
break;
95+
}
96+
}
97+
if (free) {
98+
return true;
99+
}
100+
}
101+
}
102+
return false;
103+
}
104+
105+
machine_timer_obj_t *machine_timer_create(mp_int_t timer) {
94106

95107
machine_timer_obj_t *self = NULL;
108+
mp_int_t group;
109+
mp_int_t index;
110+
if (timer == -2) {
111+
if (!find_free_timer(&group, &index)) {
112+
mp_raise_msg_varg(&mp_type_RuntimeError, MP_ERROR_TEXT("out of Timers:%d"), SOC_TIMER_GROUP_TOTAL_TIMERS);
113+
}
114+
} else {
115+
#if SOC_TIMER_GROUP_TIMERS_PER_GROUP == 1
116+
group = timer & 1;
117+
index = 0;
118+
#else
119+
group = (timer >> 1) & 1;
120+
index = timer & 1;
121+
#endif
122+
}
96123

97124
// Check whether the timer is already initialized, if so use it
98125
for (machine_timer_obj_t *t = MP_STATE_PORT(machine_timer_obj_head); t; t = t->next) {
@@ -106,11 +133,24 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
106133
self = mp_obj_malloc(machine_timer_obj_t, &machine_timer_type);
107134
self->group = group;
108135
self->index = index;
136+
self->handle = NULL;
109137

110138
// Add the timer to the linked-list of timers
111139
self->next = MP_STATE_PORT(machine_timer_obj_head);
112140
MP_STATE_PORT(machine_timer_obj_head) = self;
113141
}
142+
return self;
143+
}
144+
145+
static mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
146+
mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);
147+
148+
// Create the new timer.
149+
mp_int_t timer_number = mp_obj_get_int(args[0]);
150+
if (timer_number >= SOC_TIMER_GROUP_TOTAL_TIMERS) {
151+
mp_raise_ValueError(MP_ERROR_TEXT("invalid Timer number"));
152+
}
153+
machine_timer_obj_t *self = machine_timer_create(timer_number);
114154

115155
if (n_args > 1 || n_kw > 0) {
116156
mp_map_t kw_args;
@@ -121,24 +161,23 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
121161
return self;
122162
}
123163

124-
STATIC void machine_timer_disable(machine_timer_obj_t *self) {
164+
void machine_timer_disable(machine_timer_obj_t *self) {
125165
if (self->hal_context.dev != NULL) {
126166
// Disable the counter and alarm.
127167
timer_ll_enable_counter(self->hal_context.dev, self->index, false);
128168
timer_ll_enable_alarm(self->hal_context.dev, self->index, false);
129169
}
130170

131171
if (self->handle) {
132-
// Free the interrupt handler.
133-
esp_intr_free(self->handle);
134-
self->handle = NULL;
172+
// Disable the interrupt
173+
ESP_ERROR_CHECK(esp_intr_disable(self->handle));
135174
}
136175

137176
// We let the disabled timer stay in the list, as it might be
138177
// referenced elsewhere
139178
}
140179

141-
STATIC void machine_timer_isr(void *self_in) {
180+
static void machine_timer_isr(void *self_in) {
142181
machine_timer_obj_t *self = self_in;
143182

144183
uint32_t intr_status = timer_ll_get_intr_status(self->hal_context.dev);
@@ -148,27 +187,53 @@ STATIC void machine_timer_isr(void *self_in) {
148187
if (self->repeat) {
149188
timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
150189
}
151-
mp_sched_schedule(self->callback, self);
152-
mp_hal_wake_main_task_from_isr();
190+
self->handler(self);
153191
}
154192
}
155193

156-
STATIC void machine_timer_enable(machine_timer_obj_t *self) {
194+
static void machine_timer_isr_handler(machine_timer_obj_t *self) {
195+
mp_sched_schedule(self->callback, self);
196+
mp_hal_wake_main_task_from_isr();
197+
}
198+
199+
void machine_timer_enable(machine_timer_obj_t *self) {
157200
// Initialise the timer.
158201
timer_hal_init(&self->hal_context, self->group, self->index);
202+
203+
PERIPH_RCC_ACQUIRE_ATOMIC(timer_group_periph_signals.groups[self->index].module, ref_count) {
204+
if (ref_count == 0) {
205+
timer_ll_enable_bus_clock(self->index, true);
206+
timer_ll_reset_register(self->index);
207+
}
208+
}
209+
159210
timer_ll_enable_counter(self->hal_context.dev, self->index, false);
160-
timer_ll_set_clock_source(self->hal_context.dev, self->index, GPTIMER_CLK_SRC_APB);
211+
esp_clk_tree_enable_src(TIMER_CLK_SRC, true);
212+
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 5, 0)
213+
timer_ll_set_clock_source(self->hal_context.dev, self->index, TIMER_CLK_SRC);
214+
timer_ll_enable_clock(self->hal_context.dev, self->index, true);
215+
#else
216+
timer_ll_set_clock_source(self->group, self->index, TIMER_CLK_SRC);
217+
timer_ll_enable_clock(self->group, self->index, true);
218+
#endif
161219
timer_ll_set_clock_prescale(self->hal_context.dev, self->index, TIMER_DIVIDER);
162220
timer_hal_set_counter_value(&self->hal_context, 0);
163221
timer_ll_set_count_direction(self->hal_context.dev, self->index, GPTIMER_COUNT_UP);
164222

165223
// Allocate and enable the alarm interrupt.
166224
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), false);
167225
timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
168-
ESP_ERROR_CHECK(
169-
esp_intr_alloc(timer_group_periph_signals.groups[self->group].timer_irq_id[self->index],
170-
TIMER_FLAGS, machine_timer_isr, self, &self->handle)
171-
);
226+
if (self->handle) {
227+
ESP_ERROR_CHECK(esp_intr_enable(self->handle));
228+
} else {
229+
ESP_ERROR_CHECK(esp_intr_alloc(
230+
timer_group_periph_signals.groups[self->group].timer_irq_id[self->index],
231+
TIMER_FLAGS,
232+
machine_timer_isr,
233+
self,
234+
&self->handle
235+
));
236+
}
172237
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), true);
173238

174239
// Enable the alarm to trigger at the given period.
@@ -183,13 +248,14 @@ STATIC void machine_timer_enable(machine_timer_obj_t *self) {
183248
timer_ll_enable_counter(self->hal_context.dev, self->index, true);
184249
}
185250

186-
STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
251+
static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
187252
enum {
188253
ARG_mode,
189254
ARG_callback,
190255
ARG_period,
191256
ARG_tick_hz,
192257
ARG_freq,
258+
ARG_hard,
193259
};
194260
static const mp_arg_t allowed_args[] = {
195261
{ MP_QSTR_mode, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} },
@@ -201,63 +267,77 @@ STATIC mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n
201267
#else
202268
{ MP_QSTR_freq, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0xffffffff} },
203269
#endif
270+
{ MP_QSTR_hard, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
204271
};
205272

206273
machine_timer_disable(self);
207274

208275
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
209276
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
210277

278+
if (args[ARG_hard].u_bool) {
279+
mp_raise_ValueError(MP_ERROR_TEXT("hard Timers are not implemented"));
280+
}
281+
211282
#if MICROPY_PY_BUILTINS_FLOAT
212283
if (args[ARG_freq].u_obj != mp_const_none) {
213-
self->period = (uint64_t)(TIMER_SCALE / mp_obj_get_float(args[ARG_freq].u_obj));
284+
self->period = (uint64_t)(machine_timer_freq_hz() / mp_obj_get_float(args[ARG_freq].u_obj));
214285
}
215286
#else
216287
if (args[ARG_freq].u_int != 0xffffffff) {
217288
self->period = TIMER_SCALE / ((uint64_t)args[ARG_freq].u_int);
218289
}
219290
#endif
220291
else {
221-
self->period = (((uint64_t)args[ARG_period].u_int) * TIMER_SCALE) / args[ARG_tick_hz].u_int;
292+
self->period = (((uint64_t)args[ARG_period].u_int) * machine_timer_freq_hz()) / args[ARG_tick_hz].u_int;
222293
}
223294

224295
self->repeat = args[ARG_mode].u_int;
296+
self->handler = machine_timer_isr_handler;
225297
self->callback = args[ARG_callback].u_obj;
226-
self->handle = NULL;
227298

228299
machine_timer_enable(self);
229300

230301
return mp_const_none;
231302
}
232303

233-
STATIC mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
234-
machine_timer_disable(self_in);
304+
static mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
305+
machine_timer_obj_t *self = self_in;
306+
307+
machine_timer_disable(self);
308+
if (self->handle) {
309+
ESP_ERROR_CHECK(esp_intr_free(self->handle));
310+
self->handle = NULL;
311+
}
235312

236313
return mp_const_none;
237314
}
238-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
315+
static MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_deinit_obj, machine_timer_deinit);
239316

240-
STATIC mp_obj_t machine_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
317+
static mp_obj_t machine_timer_init(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
241318
return machine_timer_init_helper(args[0], n_args - 1, args + 1, kw_args);
242319
}
243-
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
320+
static MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init);
244321

245-
STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) {
322+
static mp_obj_t machine_timer_value(mp_obj_t self_in) {
246323
machine_timer_obj_t *self = self_in;
324+
if (self->handle == NULL) {
325+
mp_raise_ValueError(MP_ERROR_TEXT("timer not set"));
326+
}
247327
uint64_t result = timer_ll_get_counter_value(self->hal_context.dev, self->index);
248-
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result / (TIMER_SCALE / 1000))); // value in ms
328+
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result / (machine_timer_freq_hz() / 1000))); // value in ms
249329
}
250-
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
330+
static MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
251331

252-
STATIC const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {
332+
static const mp_rom_map_elem_t machine_timer_locals_dict_table[] = {
253333
{ MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&machine_timer_deinit_obj) },
254334
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&machine_timer_deinit_obj) },
255335
{ MP_ROM_QSTR(MP_QSTR_init), MP_ROM_PTR(&machine_timer_init_obj) },
256336
{ MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&machine_timer_value_obj) },
257337
{ MP_ROM_QSTR(MP_QSTR_ONE_SHOT), MP_ROM_INT(false) },
258338
{ MP_ROM_QSTR(MP_QSTR_PERIODIC), MP_ROM_INT(true) },
259339
};
260-
STATIC MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
340+
static MP_DEFINE_CONST_DICT(machine_timer_locals_dict, machine_timer_locals_dict_table);
261341

262342
MP_DEFINE_CONST_OBJ_TYPE(
263343
machine_timer_type,

0 commit comments

Comments
 (0)