Skip to content

ports/esp32: Fix crash and improve timer interrupt allocation #17265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 32 additions & 14 deletions ports/esp32/machine_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@
const mp_obj_type_t machine_timer_type;

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);
static mp_obj_t machine_timer_deinit(mp_obj_t self_in);

void machine_timer_deinit_all(void) {
// Disable, deallocate and remove all timers from list
machine_timer_obj_t **t = &MP_STATE_PORT(machine_timer_obj_head);
while (*t != NULL) {
machine_timer_disable(*t);
machine_timer_deinit(*t);
machine_timer_obj_t *next = (*t)->next;
m_del_obj(machine_timer_obj_t, *t);
*t = next;
Expand Down Expand Up @@ -96,6 +97,7 @@ machine_timer_obj_t *machine_timer_create(mp_uint_t timer) {
self = mp_obj_malloc(machine_timer_obj_t, &machine_timer_type);
self->group = group;
self->index = index;
self->handle = NULL;

// Add the timer to the linked-list of timers
self->next = MP_STATE_PORT(machine_timer_obj_head);
Expand Down Expand Up @@ -131,9 +133,8 @@ void machine_timer_disable(machine_timer_obj_t *self) {
}

if (self->handle) {
// Free the interrupt handler.
esp_intr_free(self->handle);
self->handle = NULL;
// Disable the interrupt
ESP_ERROR_CHECK(esp_intr_disable(self->handle));
}

// We let the disabled timer stay in the list, as it might be
Expand All @@ -150,12 +151,16 @@ static void machine_timer_isr(void *self_in) {
if (self->repeat) {
timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
}
mp_sched_schedule(self->callback, self);
mp_hal_wake_main_task_from_isr();
self->handler(self);
}
}

void machine_timer_enable(machine_timer_obj_t *self, void (*timer_isr)) {
static void machine_timer_isr_handler(machine_timer_obj_t *self) {
mp_sched_schedule(self->callback, self);
mp_hal_wake_main_task_from_isr();
}

void machine_timer_enable(machine_timer_obj_t *self) {
// Initialise the timer.
timer_hal_init(&self->hal_context, self->group, self->index);
timer_ll_enable_counter(self->hal_context.dev, self->index, false);
Expand All @@ -167,10 +172,17 @@ void machine_timer_enable(machine_timer_obj_t *self, void (*timer_isr)) {
// Allocate and enable the alarm interrupt.
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), false);
timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
ESP_ERROR_CHECK(
esp_intr_alloc(timer_group_periph_signals.groups[self->group].timer_irq_id[self->index],
TIMER_FLAGS, timer_isr, self, &self->handle)
);
if (self->handle) {
ESP_ERROR_CHECK(esp_intr_enable(self->handle));
} else {
ESP_ERROR_CHECK(esp_intr_alloc(
timer_group_periph_signals.groups[self->group].timer_irq_id[self->index],
TIMER_FLAGS,
machine_timer_isr,
self,
&self->handle
));
}
timer_ll_enable_intr(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index), true);

// Enable the alarm to trigger at the given period.
Expand Down Expand Up @@ -224,16 +236,22 @@ static mp_obj_t machine_timer_init_helper(machine_timer_obj_t *self, mp_uint_t n
}

self->repeat = args[ARG_mode].u_int;
self->handler = machine_timer_isr_handler;
self->callback = args[ARG_callback].u_obj;
self->handle = NULL;

machine_timer_enable(self, machine_timer_isr);
machine_timer_enable(self);

return mp_const_none;
}

static mp_obj_t machine_timer_deinit(mp_obj_t self_in) {
machine_timer_disable(self_in);
machine_timer_obj_t *self = self_in;

machine_timer_disable(self);
if (self->handle) {
ESP_ERROR_CHECK(esp_intr_free(self->handle));
self->handle = NULL;
}

return mp_const_none;
}
Expand Down
3 changes: 2 additions & 1 deletion ports/esp32/machine_timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,13 @@ typedef struct _machine_timer_obj_t {
mp_obj_t callback;

intr_handle_t handle;
void (*handler)(struct _machine_timer_obj_t *timer);

struct _machine_timer_obj_t *next;
} machine_timer_obj_t;

machine_timer_obj_t *machine_timer_create(mp_uint_t timer);
void machine_timer_enable(machine_timer_obj_t *self, void (*timer_isr));
void machine_timer_enable(machine_timer_obj_t *self);
void machine_timer_disable(machine_timer_obj_t *self);

#endif // MICROPY_INCLUDED_ESP32_MACHINE_TIMER_H
35 changes: 11 additions & 24 deletions ports/esp32/machine_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -110,30 +110,19 @@ static const char *_parity_name[] = {"None", "1", "0"};
{ MP_ROM_QSTR(MP_QSTR_IRQ_RXIDLE), MP_ROM_INT(UART_IRQ_RXIDLE) }, \
{ MP_ROM_QSTR(MP_QSTR_IRQ_BREAK), MP_ROM_INT(UART_IRQ_BREAK) }, \

static void uart_timer_callback(void *self_in) {
machine_timer_obj_t *self = self_in;

uint32_t intr_status = timer_ll_get_intr_status(self->hal_context.dev);

if (intr_status & TIMER_LL_EVENT_ALARM(self->index)) {
timer_ll_clear_intr_status(self->hal_context.dev, TIMER_LL_EVENT_ALARM(self->index));
if (self->repeat) {
timer_ll_enable_alarm(self->hal_context.dev, self->index, true);
}
}

static void uart_timer_callback(machine_timer_obj_t *timer) {
// The UART object is referred here by the callback field.
machine_uart_obj_t *uart = (machine_uart_obj_t *)self->callback;
if (uart->rxidle_state == RXIDLE_ALERT) {
machine_uart_obj_t *self = (machine_uart_obj_t *)timer->callback;
if (self->rxidle_state == RXIDLE_ALERT) {
// At the first call, just switch the state
uart->rxidle_state = RXIDLE_ARMED;
} else if (uart->rxidle_state == RXIDLE_ARMED) {
self->rxidle_state = RXIDLE_ARMED;
} else if (self->rxidle_state == RXIDLE_ARMED) {
// At the second call, run the irq callback and stop the timer
uart->rxidle_state = RXIDLE_STANDBY;
uart->mp_irq_flags = UART_IRQ_RXIDLE;
mp_irq_handler(uart->mp_irq_obj);
self->rxidle_state = RXIDLE_STANDBY;
self->mp_irq_flags = UART_IRQ_RXIDLE;
mp_irq_handler(self->mp_irq_obj);
mp_hal_wake_main_task_from_isr();
machine_timer_disable(uart->rxidle_timer);
machine_timer_disable(self->rxidle_timer);
}
}

Expand All @@ -150,9 +139,7 @@ static void uart_event_task(void *self_in) {
if (self->mp_irq_trigger & UART_IRQ_RXIDLE) {
if (self->rxidle_state != RXIDLE_INACTIVE) {
if (self->rxidle_state == RXIDLE_STANDBY) {
self->rxidle_timer->repeat = true;
self->rxidle_timer->handle = NULL;
machine_timer_enable(self->rxidle_timer, uart_timer_callback);
machine_timer_enable(self->rxidle_timer);
}
}
self->rxidle_state = RXIDLE_ALERT;
Expand Down Expand Up @@ -553,11 +540,11 @@ static void uart_irq_configure_timer(machine_uart_obj_t *self, mp_uint_t trigger
}
self->rxidle_period = period;
self->rxidle_timer->period = period;
self->rxidle_timer->handler = uart_timer_callback;
// The Python callback is not used. So use this
// data field to hold a reference to the UART object.
self->rxidle_timer->callback = self;
self->rxidle_timer->repeat = true;
self->rxidle_timer->handle = NULL;
self->rxidle_state = RXIDLE_STANDBY;
}
}
Expand Down
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy