From 6bf650c1598090ef3b9725ed90993f52750c1a0e Mon Sep 17 00:00:00 2001 From: Alex Lisitsyn Date: Thu, 19 May 2022 10:40:34 +0800 Subject: [PATCH] driver: fixes context switch while sending cause rts reset before send (backport v4.4) --- components/driver/uart.c | 52 ++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/components/driver/uart.c b/components/driver/uart.c index dda1f3b69a..1ee495b133 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ #include +#include #include "esp_types.h" #include "esp_attr.h" #include "esp_intr_alloc.h" @@ -64,6 +65,9 @@ static const char *UART_TAG = "uart"; | (UART_INTR_BRK_DET) \ | (UART_INTR_PARITY_ERR)) + +#define UART_ENTER_CRITICAL_SAFE(mux) portENTER_CRITICAL_SAFE(mux) +#define UART_EXIT_CRITICAL_SAFE(mux) portEXIT_CRITICAL_SAFE(mux) #define UART_ENTER_CRITICAL_ISR(mux) portENTER_CRITICAL_ISR(mux) #define UART_EXIT_CRITICAL_ISR(mux) portEXIT_CRITICAL_ISR(mux) #define UART_ENTER_CRITICAL(mux) portENTER_CRITICAL(mux) @@ -803,6 +807,19 @@ static int UART_ISR_ATTR uart_find_pattern_from_last(uint8_t *buf, int length, u return len; } +static uint32_t UART_ISR_ATTR uart_enable_tx_write_fifo(uart_port_t uart_num, const uint8_t *pbuf, uint32_t len) +{ + uint32_t sent_len = 0; + UART_ENTER_CRITICAL_SAFE(&(uart_context[uart_num].spinlock)); + if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { + uart_hal_set_rts(&(uart_context[uart_num].hal), 0); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + } + uart_hal_write_txfifo(&(uart_context[uart_num].hal), pbuf, len, &sent_len); + UART_EXIT_CRITICAL_SAFE(&(uart_context[uart_num].spinlock)); + return sent_len; +} + //internal isr handler for default driver code. static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) { @@ -872,19 +889,9 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) } } if (p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) { - //To fill the TX FIFO. - uint32_t send_len = 0; - // Set RS485 RTS pin before transmission if the half duplex mode is enabled - if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); - uart_hal_set_rts(&(uart_context[uart_num].hal), 0); - uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); - UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); - } - uart_hal_write_txfifo(&(uart_context[uart_num].hal), - (const uint8_t *)p_uart->tx_ptr, - (p_uart->tx_len_cur > tx_fifo_rem) ? tx_fifo_rem : p_uart->tx_len_cur, - &send_len); + // To fill the TX FIFO. + uint32_t send_len = uart_enable_tx_write_fifo(uart_num, (const uint8_t *) p_uart->tx_ptr, + MIN(p_uart->tx_len_cur, tx_fifo_rem)); p_uart->tx_ptr += send_len; p_uart->tx_len_tot -= send_len; p_uart->tx_len_cur -= send_len; @@ -1088,6 +1095,7 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) // Workaround for RS485: If the RS485 half duplex mode is active // and transmitter is in idle state then reset received buffer and reset RTS pin // skip this behavior for other UART modes + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { @@ -1095,7 +1103,6 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) uart_hal_set_rts(&(uart_context[uart_num].hal), 1); } UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); - uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); } } else { @@ -1164,13 +1171,7 @@ int uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len) } int tx_len = 0; xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY); - if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); - uart_hal_set_rts(&(uart_context[uart_num].hal), 0); - uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); - } - uart_hal_write_txfifo(&(uart_context[uart_num].hal), (const uint8_t *) buffer, len, (uint32_t *)&tx_len); + tx_len = (int)uart_enable_tx_write_fifo(uart_num, (const uint8_t *) buffer, len); xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); return tx_len; } @@ -1208,14 +1209,7 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool while (size) { //semaphore for tx_fifo available if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) { - uint32_t sent = 0; - if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); - uart_hal_set_rts(&(uart_context[uart_num].hal), 0); - uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); - } - uart_hal_write_txfifo(&(uart_context[uart_num].hal), (const uint8_t *)src, size, &sent); + uint32_t sent = uart_enable_tx_write_fifo(uart_num, (const uint8_t *) src, size); if (sent < size) { p_uart_obj[uart_num]->tx_waiting_fifo = true; uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT);