diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig index 67d2894b2ad..4c0d3b12f6b 100644 --- a/arch/xtensa/src/esp32/Kconfig +++ b/arch/xtensa/src/esp32/Kconfig @@ -566,6 +566,32 @@ menu "UART configuration" if ESP32_UART0 +config ESP32_UART0_RS485 + bool "RS-485 on UART0" + default n + ---help--- + Enable RS-485 interface on UART0. Your board config will have to + provide GPIO_UART0_RS485_DIR pin definition. Currently it cannot be + used with UART0_RXDMA. + +config ESP32_UART0_RS485_DIR_PIN + int "UART0 RS-485 DIR pin" + default 4 + range 1 39 + depends on ESP32_UART0_RS485 + ---help--- + DIR pin for RS-485 on UART0. This pin will control the RS485 enable + TX of the RS485 transceiver. + +config ESP32_UART0_RS485_DIR_POLARITY + int "UART0 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on ESP32_UART0_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART0. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + config ESP32_UART0_TXPIN int "UART0 Tx Pin" default 1 @@ -606,6 +632,32 @@ endif # ESP32_UART0 if ESP32_UART1 +config ESP32_UART1_RS485 + bool "RS-485 on UART1" + default n + ---help--- + Enable RS-485 interface on UART1. Your board config will have to + provide GPIO_UART1_RS485_DIR pin definition. Currently it cannot be + used with UART1_RXDMA. + +config ESP32_UART1_RS485_DIR_PIN + int "UART1 RS-485 DIR pin" + default 14 + range 1 39 + depends on ESP32_UART1_RS485 + ---help--- + DIR pin for RS-485 on UART1. This pin will control the RS485 enable + TX of the RS485 transceiver. + +config ESP32_UART1_RS485_DIR_POLARITY + int "UART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on ESP32_UART1_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART1. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + config ESP32_UART1_TXPIN int "UART1 Tx Pin" default 10 @@ -646,6 +698,32 @@ endif # ESP32_UART1 if ESP32_UART2 +config ESP32_UART2_RS485 + bool "RS-485 on UART2" + default n + ---help--- + Enable RS-485 interface on UART2. Your board config will have to + provide GPIO_UART2_RS485_DIR pin definition. Currently it cannot be + used with UART2_RXDMA. + +config ESP32_UART2_RS485_DIR_PIN + int "UART2 RS-485 DIR pin" + default 18 + range 1 39 + depends on ESP32_UART2_RS485 + ---help--- + DIR pin for RS-485 on UART2. This pin will control the RS485 enable + TX of the RS485 transceiver. + +config ESP32_UART2_RS485_DIR_POLARITY + int "UART2 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on ESP32_UART2_RS485 + ---help--- + Polarity of DIR pin for RS-485 on UART2. Set to state on DIR pin which + enables TX (0 - low / nTXEN, 1 - high / TXEN). + config ESP32_UART2_TXPIN int "UART2 Tx Pin" default 19 diff --git a/arch/xtensa/src/esp32/esp32_config.h b/arch/xtensa/src/esp32/esp32_config.h index 4f16f25e1e3..47e154e4e06 100644 --- a/arch/xtensa/src/esp32/esp32_config.h +++ b/arch/xtensa/src/esp32/esp32_config.h @@ -59,6 +59,14 @@ # define HAVE_UART_DEVICE 1 #endif +/* Is RS-485 used? */ + +#if defined(CONFIG_ESP32_UART0_RS485) || \ + defined(CONFIG_ESP32_UART1_RS485) || \ + defined(CONFIG_ESP32_UART2_RS485) +# define HAVE_RS485 1 +#endif + /* UART Flow Control ********************************************************/ #ifndef CONFIG_ESP32_UART0 diff --git a/arch/xtensa/src/esp32/esp32_serial.c b/arch/xtensa/src/esp32/esp32_serial.c index f56eb5a8456..e10e9996c27 100644 --- a/arch/xtensa/src/esp32/esp32_serial.c +++ b/arch/xtensa/src/esp32/esp32_serial.c @@ -246,6 +246,10 @@ struct esp32_config_s uint8_t dma_chan; /* DMA instance 0-1 */ sem_t * dma_sem; /* DMA semaphore */ #endif +#ifdef HAVE_RS485 + uint8_t rs485_dir_gpio; /* UART RS-485 DIR GPIO pin cfg */ + bool rs485_dir_polarity; /* UART RS-485 DIR TXEN polarity */ +#endif }; /* Current state of the UART */ @@ -380,6 +384,14 @@ static const struct esp32_config_s g_uart0config = #endif #endif #endif +#ifdef CONFIG_ESP32_UART0_RS485 + .rs485_dir_gpio = CONFIG_ESP32_UART0_RS485_DIR_PIN, +#if (CONFIG_ESP32_UART0_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +#else + .rs485_dir_polarity = true, +#endif +#endif }; static struct esp32_dev_s g_uart0priv = @@ -459,6 +471,14 @@ static const struct esp32_config_s g_uart1config = #endif #endif #endif +#ifdef CONFIG_ESP32_UART1_RS485 + .rs485_dir_gpio = CONFIG_ESP32_UART1_RS485_DIR_PIN, +#if (CONFIG_ESP32_UART1_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +#else + .rs485_dir_polarity = true, +#endif +#endif }; static struct esp32_dev_s g_uart1priv = @@ -538,6 +558,14 @@ static const struct esp32_config_s g_uart2config = #endif #endif #endif +#ifdef CONFIG_ESP32_UART2_RS485 + .rs485_dir_gpio = CONFIG_ESP32_UART2_RS485_DIR_PIN, +#if (CONFIG_ESP32_UART2_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +#else + .rs485_dir_polarity = true, +#endif +#endif }; static struct esp32_dev_s g_uart2priv = @@ -1345,9 +1373,26 @@ static int esp32_interrupt(int cpuint, void *context, void *arg) regval = (UART_RXFIFO_FULL_INT_CLR | UART_FRM_ERR_INT_CLR | UART_RXFIFO_TOUT_INT_CLR | UART_TX_DONE_INT_CLR | - UART_TXFIFO_EMPTY_INT_CLR); + UART_TXFIFO_EMPTY_INT_CLR | UART_TX_BRK_IDLE_DONE_INT_CLR); putreg32(regval, UART_INT_CLR_REG(priv->config->id)); +#ifdef HAVE_RS485 + if ((enabled & UART_TX_BRK_IDLE_DONE_INT_ENA) != 0 && + (status & UART_TX_DONE_INT_ST) != 0) + { + /* If al bytes were transmited, then we can disable the RS485 + * transmit (TX/nTX) pin. + */ + + nfifo = REG_MASK(status, UART_TXFIFO_CNT); + if (nfifo == 0) + { + esp32_gpiowrite(priv->config->rs485_dir_gpio, + !priv->config->rs485_dir_polarity); + } + } +#endif + /* Are Rx interrupts enabled? The upper layer may hold off Rx input * by disabling the Rx interrupts if there is no place to saved the * data, possibly resulting in an overrun error. @@ -1697,6 +1742,14 @@ static void esp32_send(struct uart_dev_s *dev, int ch) { struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv; +#ifdef HAVE_RS485 + if (priv->config->rs485_dir_gpio != 0) + { + esp32_gpiowrite(priv->config->rs485_dir_gpio, + priv->config->rs485_dir_polarity); + } +#endif + putreg32((uint32_t)ch, AHB_UART_FIFO_REG(priv->config->id)); } @@ -1720,6 +1773,18 @@ static void esp32_txint(struct uart_dev_s *dev, bool enable) if (enable) { + /* After all bytes physically transmitted in the RS485 bus + * the TX_BRK_IDLE will indicate we can disable the TX pin. + */ + + #ifdef HAVE_RS485 + if (priv->config->rs485_dir_gpio != 0) + { + modifyreg32(UART_INT_ENA_REG(priv->config->id), + 0, UART_TX_BRK_IDLE_DONE_INT_ENA); + } + #endif + /* Set to receive an interrupt when the TX holding register * is empty. */ @@ -1829,6 +1894,17 @@ static void esp32_config_pins(struct esp32_dev_s *priv) esp32_gpio_matrix_in(priv->config->ctspin, priv->config->ctssig, 0); } #endif + +#ifdef HAVE_RS485 + if (priv->config->rs485_dir_gpio != 0) + { + esp32_configgpio(priv->config->rs485_dir_gpio, OUTPUT_FUNCTION_3); + esp32_gpio_matrix_out(priv->config->rs485_dir_gpio, + SIG_GPIO_OUT_IDX, 0, 0); + esp32_gpiowrite(priv->config->rs485_dir_gpio, + !priv->config->rs485_dir_polarity); + } +#endif } /****************************************************************************