From d83c17deece655b1891d1f14ab5db7e9b4455997 Mon Sep 17 00:00:00 2001 From: aleks Date: Wed, 21 Jul 2021 06:33:51 +0200 Subject: [PATCH 1/3] driver: uart fix the rts line assertion issue --- components/driver/uart.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/driver/uart.c b/components/driver/uart.c index bd5652bbe3..f9431f0b02 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -768,6 +768,7 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) // 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_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); 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)); @@ -1057,6 +1058,7 @@ int uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len) 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_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); 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)); @@ -1102,6 +1104,7 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool 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_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); 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)); From 5c332a574930eb3b24c0da7f29737cde6f016004 Mon Sep 17 00:00:00 2001 From: aleks Date: Mon, 26 Jul 2021 11:49:40 +0200 Subject: [PATCH 2/3] driver: fixes context switch while sending cause rts reset before send fixes tx bytes w/o ring buffer causes rts reset before send data put uart_hal_write_txfifo() under critical section --- components/driver/uart.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/components/driver/uart.c b/components/driver/uart.c index f9431f0b02..d9df14571b 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -768,7 +768,6 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) // 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_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); 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)); @@ -1056,14 +1055,13 @@ 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); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); - uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); 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); + uart_hal_write_txfifo(&(uart_context[uart_num].hal), (const uint8_t*) buffer, len, (uint32_t *)&tx_len); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); return tx_len; } @@ -1102,15 +1100,15 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool //semaphore for tx_fifo available if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) { uint32_t sent = 0; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); - uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); 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); - if (sent < size) { + // Write of TX FIFO inside critical section to prevent context switch + uart_hal_write_txfifo(&(uart_context[uart_num].hal), (const uint8_t*)src, size, &sent); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + if(sent < size) { p_uart_obj[uart_num]->tx_waiting_fifo = true; uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT); } From c02cfc39e5303700c00219c7852790cda01b0d7c Mon Sep 17 00:00:00 2001 From: aleks Date: Mon, 28 Mar 2022 18:23:53 +0200 Subject: [PATCH 3/3] uart: add separate function to control mode and fill fifo --- components/driver/uart.c | 55 ++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/components/driver/uart.c b/components/driver/uart.c index d9df14571b..3b8edf7d5c 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #include +#include #include "esp_types.h" #include "esp_attr.h" #include "esp_intr_alloc.h" @@ -68,6 +69,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) @@ -694,6 +698,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) { @@ -763,19 +780,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; @@ -979,6 +986,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)) { @@ -986,7 +994,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 { @@ -1055,13 +1062,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); - UART_ENTER_CRITICAL(&(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), (const uint8_t*) buffer, len, (uint32_t *)&tx_len); - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + 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; } @@ -1099,16 +1100,8 @@ 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; - UART_ENTER_CRITICAL(&(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); - } - // Write of TX FIFO inside critical section to prevent context switch - uart_hal_write_txfifo(&(uart_context[uart_num].hal), (const uint8_t*)src, size, &sent); - UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); - if(sent < size) { + 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); }