esp32: Re-use allocated timer interrupts and simplify UART timer code.

If the interrupt is not freed but merely disabled, instead of reallocating
it every time the timer is enabled again we can instead just re-enable it.
That means we're no longer setting the handler every time, and we need to
ensure it does not change. Doing so by adding an additional wrapper
function does not only solve that problem, it also allows us to remove
some code duplication and simplify how machine_uart uses the timer.

Signed-off-by: Daniël van de Giessen <daniel@dvdgiessen.nl>
This commit is contained in:
Daniël van de Giessen
2025-04-22 17:42:29 +02:00
committed by Damien George
parent bf909303ff
commit 2c2f0b292a
3 changed files with 31 additions and 36 deletions

View File

@@ -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);
}
}
@@ -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;
@@ -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;
}
}