Skip to content

Commit 155fa94

Browse files
committed
esp32/machine_uart: Correctly manage UART queue and event task.
If the driver was reinitialised while there was already an event task running the queue that task is trying to receive from would be deleted, causing it to try to take a lock that no longer existed and deadlocking the CPU. This change ensures the task is always shut down before recreating the queue and recreates the task afterwards. It also allows setting an IRQ handler before the UART is initialized (like other ports allow), removes the task when the UART is deinitialized (which was previously missing), adds a check that no event task can be started when no queue exists, and adds a check to prevent reinitialising the UART driver unnecessarily. Signed-off-by: Daniël van de Giessen <[email protected]>
1 parent 883dc41 commit 155fa94

File tree

1 file changed

+31
-8
lines changed

1 file changed

+31
-8
lines changed

ports/esp32/machine_uart.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#define UART_IRQ_BREAK (1 << UART_BREAK)
6060
#define MP_UART_ALLOWED_FLAGS (UART_IRQ_RX | UART_IRQ_RXIDLE | UART_IRQ_BREAK)
6161
#define RXIDLE_TIMER_MIN (5000) // 500 us
62+
#define UART_QUEUE_SIZE (3)
6263

6364
enum {
6465
RXIDLE_INACTIVE,
@@ -174,6 +175,13 @@ static void uart_event_task(void *self_in) {
174175
}
175176
}
176177

178+
static inline void uart_event_task_create(machine_uart_obj_t *self) {
179+
if (xTaskCreatePinnedToCore(uart_event_task, "uart_event_task", 2048, self,
180+
ESP_TASKD_EVENT_PRIO, (TaskHandle_t *)&self->uart_event_task, MP_TASK_COREID) != pdPASS) {
181+
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("failed to create UART event task"));
182+
}
183+
}
184+
177185
static void mp_machine_uart_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
178186
machine_uart_obj_t *self = MP_OBJ_TO_PTR(self_in);
179187
uint32_t baudrate;
@@ -250,7 +258,7 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args,
250258
// wait for all data to be transmitted before changing settings
251259
uart_wait_tx_done(self->uart_num, pdMS_TO_TICKS(1000));
252260

253-
if (args[ARG_txbuf].u_int >= 0 || args[ARG_rxbuf].u_int >= 0) {
261+
if ((args[ARG_txbuf].u_int >= 0 && args[ARG_txbuf].u_int != self->txbuf) || (args[ARG_rxbuf].u_int >= 0 && args[ARG_rxbuf].u_int != self->rxbuf)) {
254262
// must reinitialise driver to change the tx/rx buffer size
255263
#if MICROPY_HW_ENABLE_UART_REPL
256264
if (self->uart_num == MICROPY_HW_UART_REPL) {
@@ -275,9 +283,12 @@ static void mp_machine_uart_init_helper(machine_uart_obj_t *self, size_t n_args,
275283
check_esp_err(uart_get_word_length(self->uart_num, &uartcfg.data_bits));
276284
check_esp_err(uart_get_parity(self->uart_num, &uartcfg.parity));
277285
check_esp_err(uart_get_stop_bits(self->uart_num, &uartcfg.stop_bits));
278-
check_esp_err(uart_driver_delete(self->uart_num));
286+
mp_machine_uart_deinit(self);
279287
check_esp_err(uart_param_config(self->uart_num, &uartcfg));
280-
check_esp_err(uart_driver_install(self->uart_num, self->rxbuf, self->txbuf, 0, NULL, 0));
288+
check_esp_err(uart_driver_install(self->uart_num, self->rxbuf, self->txbuf, UART_QUEUE_SIZE, &self->uart_queue, 0));
289+
if (self->mp_irq_obj != NULL && self->mp_irq_obj->handler != mp_const_none) {
290+
uart_event_task_create(self);
291+
}
281292
}
282293

283294
// set baudrate
@@ -437,7 +448,8 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
437448
self->timeout_char = 0;
438449
self->invert = 0;
439450
self->flowcontrol = 0;
440-
self->uart_event_task = 0;
451+
self->uart_event_task = NULL;
452+
self->uart_queue = NULL;
441453
self->rxidle_state = RXIDLE_INACTIVE;
442454

443455
switch (uart_num) {
@@ -470,12 +482,13 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
470482
{
471483
// Remove any existing configuration
472484
check_esp_err(uart_driver_delete(self->uart_num));
485+
self->uart_queue = NULL;
473486

474487
// init the peripheral
475488
// Setup
476489
check_esp_err(uart_param_config(self->uart_num, &uartcfg));
477490

478-
check_esp_err(uart_driver_install(uart_num, self->rxbuf, self->txbuf, 3, &self->uart_queue, 0));
491+
check_esp_err(uart_driver_install(uart_num, self->rxbuf, self->txbuf, UART_QUEUE_SIZE, &self->uart_queue, 0));
479492
}
480493

481494
mp_map_t kw_args;
@@ -489,7 +502,12 @@ static mp_obj_t mp_machine_uart_make_new(const mp_obj_type_t *type, size_t n_arg
489502
}
490503

491504
static void mp_machine_uart_deinit(machine_uart_obj_t *self) {
505+
if (self->uart_event_task != NULL) {
506+
vTaskDelete(self->uart_event_task);
507+
self->uart_event_task = NULL;
508+
}
492509
check_esp_err(uart_driver_delete(self->uart_num));
510+
self->uart_queue = NULL;
493511
}
494512

495513
static mp_int_t mp_machine_uart_any(machine_uart_obj_t *self) {
@@ -568,6 +586,12 @@ static const mp_irq_methods_t uart_irq_methods = {
568586
};
569587

570588
static mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args, mp_arg_val_t *args) {
589+
#if MICROPY_HW_ENABLE_UART_REPL
590+
if (self->uart_num == MICROPY_HW_UART_REPL) {
591+
mp_raise_ValueError(MP_ERROR_TEXT("UART does not support IRQs"));
592+
}
593+
#endif
594+
571595
if (self->mp_irq_obj == NULL) {
572596
self->mp_irq_trigger = 0;
573597
self->mp_irq_obj = mp_irq_new(&uart_irq_methods, MP_OBJ_FROM_PTR(self));
@@ -597,9 +621,8 @@ static mp_irq_obj_t *mp_machine_uart_irq(machine_uart_obj_t *self, bool any_args
597621
uart_irq_configure_timer(self, trigger);
598622

599623
// Start a task for handling events
600-
if (handler != mp_const_none && self->uart_event_task == NULL) {
601-
xTaskCreatePinnedToCore(uart_event_task, "uart_event_task", 2048, self,
602-
ESP_TASKD_EVENT_PRIO, (TaskHandle_t *)&self->uart_event_task, MP_TASK_COREID);
624+
if (handler != mp_const_none && self->uart_event_task == NULL && self->uart_queue != NULL) {
625+
uart_event_task_create(self);
603626
} else if (handler == mp_const_none && self->uart_event_task != NULL) {
604627
vTaskDelete(self->uart_event_task);
605628
self->uart_event_task = NULL;

0 commit comments

Comments
 (0)