Skip to content

Commit 7d66ae6

Browse files
committed
esp32/machine_timer: Switch from legacy driver to timer HAL.
The legacy driver was deprecated in IDF v5, and crashes when the ISR handler is called. Instead of fixing the legacy code, this commit reworks the machine.Timer class to use the low-level HAL driver. Tested on ESP32, ESP32S2, ESP32S3 and ESP32C3. Behaviour is the same as it was before this commit, except the way the Timer object is printed, it now gives more useful information (timer id, mode, period in ms). Fixes issue micropython#11970. Signed-off-by: Damien George <[email protected]>
1 parent 671b35c commit 7d66ae6

File tree

2 files changed

+52
-46
lines changed

2 files changed

+52
-46
lines changed

ports/esp32/boards/sdkconfig.base

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,5 @@ CONFIG_UART_ISR_IN_IRAM=y
7575

7676
# IDF 5 deprecated
7777
CONFIG_ADC_SUPPRESS_DEPRECATE_WARN=y
78-
CONFIG_GPTIMER_SUPPRESS_DEPRECATE_WARN=y
7978
CONFIG_RMT_SUPPRESS_DEPRECATE_WARN=y
8079
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y

ports/esp32/machine_timer.c

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@
3535
#include "modmachine.h"
3636
#include "mphalport.h"
3737

38-
#include "driver/timer.h"
38+
#include "hal/timer_hal.h"
3939
#include "hal/timer_ll.h"
40+
#include "soc/timer_periph.h"
4041

41-
#define TIMER_INTR_SEL TIMER_INTR_LEVEL
4242
#define TIMER_DIVIDER 8
4343

4444
// TIMER_BASE_CLK is normally 80MHz. TIMER_DIVIDER ought to divide this exactly
@@ -48,6 +48,8 @@
4848

4949
typedef struct _machine_timer_obj_t {
5050
mp_obj_base_t base;
51+
52+
timer_hal_context_t hal_context;
5153
mp_uint_t group;
5254
mp_uint_t index;
5355

@@ -80,15 +82,9 @@ void machine_timer_deinit_all(void) {
8082

8183
STATIC void machine_timer_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
8284
machine_timer_obj_t *self = self_in;
83-
84-
timer_config_t config;
85-
mp_printf(print, "Timer(%p; ", self);
86-
87-
timer_get_config(self->group, self->index, &config);
88-
89-
mp_printf(print, "alarm_en=%d, ", config.alarm_en);
90-
mp_printf(print, "auto_reload=%d, ", config.auto_reload);
91-
mp_printf(print, "counter_en=%d)", config.counter_en);
85+
qstr mode = self->repeat ? MP_QSTR_PERIODIC : MP_QSTR_ONE_SHOT;
86+
uint64_t period = self->period / (TIMER_SCALE / 1000); // convert to ms
87+
mp_printf(print, "Timer(%u, mode=%q, period=%lu)", (self->group << 1) | self->index, mode, period);
9288
}
9389

9490
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) {
@@ -126,8 +122,14 @@ STATIC mp_obj_t machine_timer_make_new(const mp_obj_type_t *type, size_t n_args,
126122
}
127123

128124
STATIC void machine_timer_disable(machine_timer_obj_t *self) {
125+
if (self->hal_context.dev != NULL) {
126+
// Disable the counter and alarm.
127+
timer_ll_enable_counter(self->hal_context.dev, self->index, false);
128+
timer_ll_enable_alarm(self->hal_context.dev, self->index, false);
129+
}
130+
129131
if (self->handle) {
130-
timer_pause(self->group, self->index);
132+
// Free the interrupt handler.
131133
esp_intr_free(self->handle);
132134
self->handle = NULL;
133135
}
@@ -138,39 +140,47 @@ STATIC void machine_timer_disable(machine_timer_obj_t *self) {
138140

139141
STATIC void machine_timer_isr(void *self_in) {
140142
machine_timer_obj_t *self = self_in;
141-
timg_dev_t *device = self->group ? &(TIMERG1) : &(TIMERG0);
142143

143-
#if CONFIG_IDF_TARGET_ESP32S3
144-
device->hw_timer[self->index].update.tn_update = 1;
145-
#else
146-
device->hw_timer[self->index].update.tx_update = 1;
147-
#endif
144+
uint32_t intr_status = timer_ll_get_intr_status(self->hal_context.dev);
148145

149-
timer_ll_clear_intr_status(device, self->index);
150-
timer_ll_set_alarm_value(device, self->index, self->repeat);
151-
152-
mp_sched_schedule(self->callback, self);
153-
mp_hal_wake_main_task_from_isr();
146+
if (intr_status & TIMER_LL_EVENT_ALARM(self->index)) {
147+
timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
148+
if (self->repeat) {
149+
timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
150+
}
151+
mp_sched_schedule(self->callback, self);
152+
mp_hal_wake_main_task_from_isr();
153+
}
154154
}
155155

156156
STATIC void machine_timer_enable(machine_timer_obj_t *self) {
157-
timer_config_t config;
158-
config.alarm_en = TIMER_ALARM_EN;
159-
config.auto_reload = self->repeat;
160-
config.counter_dir = TIMER_COUNT_UP;
161-
config.divider = TIMER_DIVIDER;
162-
config.intr_type = TIMER_INTR_LEVEL;
163-
config.counter_en = TIMER_PAUSE;
164-
#if SOC_TIMER_GROUP_SUPPORT_XTAL
165-
config.clk_src = TIMER_SRC_CLK_APB;
166-
#endif
167-
168-
check_esp_err(timer_init(self->group, self->index, &config));
169-
check_esp_err(timer_set_counter_value(self->group, self->index, 0x00000000));
170-
check_esp_err(timer_set_alarm_value(self->group, self->index, self->period));
171-
check_esp_err(timer_enable_intr(self->group, self->index));
172-
check_esp_err(timer_isr_register(self->group, self->index, machine_timer_isr, (void *)self, TIMER_FLAGS, &self->handle));
173-
check_esp_err(timer_start(self->group, self->index));
157+
// Initialise the timer.
158+
timer_hal_init(&self->hal_context, self->group, self->index);
159+
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);
161+
timer_ll_set_clock_prescale(self->hal_context.dev, self->index, TIMER_DIVIDER);
162+
timer_hal_set_counter_value(&self->hal_context, 0);
163+
timer_ll_set_count_direction(self->hal_context.dev, self->index, GPTIMER_COUNT_UP);
164+
165+
// Allocate and enable the alarm interrupt.
166+
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), false);
167+
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+
);
172+
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), true);
173+
174+
// Enable the alarm to trigger at the given period.
175+
timer_ll_set_alarm_value(self->hal_context.dev, self->index, self->period);
176+
timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
177+
178+
// Set the counter to reload at 0 if it's in repeat mode.
179+
timer_ll_set_reload_value(self->hal_context.dev, self->index, 0);
180+
timer_ll_enable_auto_reload(self->hal_context.dev, self->index, self->repeat);
181+
182+
// Enable the counter.
183+
timer_ll_enable_counter(self->hal_context.dev, self->index, true);
174184
}
175185

176186
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) {
@@ -234,11 +244,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(machine_timer_init_obj, 1, machine_timer_init)
234244

235245
STATIC mp_obj_t machine_timer_value(mp_obj_t self_in) {
236246
machine_timer_obj_t *self = self_in;
237-
double result;
238-
239-
timer_get_counter_time_sec(self->group, self->index, &result);
240-
241-
return MP_OBJ_NEW_SMALL_INT((mp_uint_t)(result * 1000)); // value in ms
247+
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
242249
}
243250
STATIC MP_DEFINE_CONST_FUN_OBJ_1(machine_timer_value_obj, machine_timer_value);
244251

0 commit comments

Comments
 (0)