diff --git a/arch/xtensa/src/esp32s3/Kconfig b/arch/xtensa/src/esp32s3/Kconfig index 9de68c92b29..3129dcb9c7e 100644 --- a/arch/xtensa/src/esp32s3/Kconfig +++ b/arch/xtensa/src/esp32s3/Kconfig @@ -979,6 +979,31 @@ menu "UART Configuration" if ESP32S3_UART0 +config ESP32S3_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. + +config ESP32S3_UART0_RS485_DIR_PIN + int "UART0 RS-485 DIR pin" + default 25 + range 0 48 + depends on ESP32S3_UART0_RS485 + ---help--- + DIR pin for RS-485 on UART0. This pin will control the RS485 enable + TX of the RS485 transceiver. + +config ESP32S3_UART0_RS485_DIR_POLARITY + int "UART0 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on ESP32S3_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 ESP32S3_UART0_TXPIN int "UART0 Tx Pin" default 43 @@ -1005,6 +1030,31 @@ endif # ESP32S3_UART0 if ESP32S3_UART1 +config ESP32S3_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. + +config ESP32S3_UART1_RS485_DIR_PIN + int "UART1 RS-485 DIR pin" + default 26 + range 0 48 + depends on ESP32S3_UART1_RS485 + ---help--- + DIR pin for RS-485 on UART1. This pin will control the RS485 enable + TX of the RS485 transceiver. + +config ESP32S3_UART1_RS485_DIR_POLARITY + int "UART1 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on ESP32S3_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 ESP32S3_UART1_TXPIN int "UART1 Tx Pin" default 17 @@ -1031,26 +1081,51 @@ endif # ESP32S3_UART1 if ESP32S3_UART2 +config ESP32S3_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. + +config ESP32S3_UART2_RS485_DIR_PIN + int "UART2 RS-485 DIR pin" + default 27 + range 0 48 + depends on ESP32S3_UART2_RS485 + ---help--- + DIR pin for RS-485 on UART2. This pin will control the RS485 enable + TX of the RS485 transceiver. + +config ESP32S3_UART2_RS485_DIR_POLARITY + int "UART2 RS-485 DIR pin polarity" + default 1 + range 0 1 + depends on ESP32S3_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 ESP32S3_UART2_TXPIN int "UART2 Tx Pin" - default 17 + default 21 range 0 48 config ESP32S3_UART2_RXPIN int "UART2 Rx Pin" - default 16 + default 22 range 0 48 config ESP32S3_UART2_RTSPIN int "UART2 RTS Pin" depends on SERIAL_IFLOWCONTROL - default 35 + default 23 range 0 48 config ESP32S3_UART2_CTSPIN int "UART2 CTS Pin" depends on SERIAL_OFLOWCONTROL - default 36 + default 24 range 0 48 endif # ESP32S3_UART2 diff --git a/arch/xtensa/src/esp32s3/esp32s3_config.h b/arch/xtensa/src/esp32s3/esp32s3_config.h index 17fcc7c09b0..7ed128210ad 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_config.h +++ b/arch/xtensa/src/esp32s3/esp32s3_config.h @@ -43,6 +43,14 @@ # define HAVE_UART_DEVICE 1 #endif +/* Is RS-485 used? */ + +#if defined(CONFIG_ESP32S3_UART0_RS485) || \ + defined(CONFIG_ESP32S3_UART1_RS485) || \ + defined(CONFIG_ESP32S3_UART2_RS485) +# define HAVE_RS485 1 +#endif + /* Serial Console ***********************************************************/ /* Is there a serial console? There should be no more than one defined. It diff --git a/arch/xtensa/src/esp32s3/esp32s3_lowputc.c b/arch/xtensa/src/esp32s3/esp32s3_lowputc.c index 34bd8da912b..0ae6ba65763 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_lowputc.c +++ b/arch/xtensa/src/esp32s3/esp32s3_lowputc.c @@ -101,6 +101,14 @@ struct esp32s3_uart_s g_uart0_config = .oflow = false, /* output flow control (CTS) disabled */ #endif #endif +#ifdef CONFIG_ESP32S3_UART0_RS485 + .rs485_dir_gpio = CONFIG_ESP32S3_UART0_RS485_DIR_PIN, +#if (CONFIG_ESP32S3_UART0_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +#else + .rs485_dir_polarity = true, +#endif +#endif }; #endif /* CONFIG_ESP32S3_UART0 */ @@ -140,6 +148,14 @@ struct esp32s3_uart_s g_uart1_config = .oflow = false, /* output flow control (CTS) disabled */ #endif #endif +#ifdef CONFIG_ESP32S3_UART1_RS485 + .rs485_dir_gpio = CONFIG_ESP32S3_UART1_RS485_DIR_PIN, +#if (CONFIG_ESP32S3_UART1_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +#else + .rs485_dir_polarity = true, +#endif +#endif }; #endif /* CONFIG_ESP32S3_UART1 */ @@ -179,6 +195,14 @@ struct esp32s3_uart_s g_uart2_config = .oflow = false, /* output flow control (CTS) disabled */ #endif #endif +#ifdef CONFIG_ESP32S3_UART2_RS485 + .rs485_dir_gpio = CONFIG_ESP32S3_UART2_RS485_DIR_PIN, +#if (CONFIG_ESP32S3_UART2_RS485_DIR_POLARITY == 0) + .rs485_dir_polarity = false, +#else + .rs485_dir_polarity = true, +#endif +#endif }; #endif /* CONFIG_ESP32S3_UART2 */ @@ -900,6 +924,15 @@ void esp32s3_lowputc_config_pins(const struct esp32s3_uart_s *priv) } #endif } + +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + esp32s3_configgpio(priv->rs485_dir_gpio, OUTPUT); + esp32s3_gpio_matrix_out(priv->rs485_dir_gpio, SIG_GPIO_OUT_IDX, 0, 0); + esp32s3_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity); + } +#endif } /**************************************************************************** diff --git a/arch/xtensa/src/esp32s3/esp32s3_lowputc.h b/arch/xtensa/src/esp32s3/esp32s3_lowputc.h index 02ccd75eb56..8680dd09ddc 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_lowputc.h +++ b/arch/xtensa/src/esp32s3/esp32s3_lowputc.h @@ -94,31 +94,35 @@ enum uart_stop_length struct esp32s3_uart_s { - uint8_t periph; /* UART peripheral ID */ - int cpuint; /* CPU interrupt assigned to this UART */ - uint8_t id; /* UART ID */ - uint8_t irq; /* IRQ associated with this UART */ - uint8_t cpu; /* CPU ID */ - uint32_t baud; /* Configured baud rate */ - uint8_t bits; /* Data length (5 to 8 bits). */ - uint8_t parity; /* 0=no parity, 1=odd parity, 2=even parity */ - uint8_t stop_b2; /* Use 2 stop bits? 0 = no (use 1) 1 = yes (use 2) */ - uint8_t int_pri; /* UART Interrupt Priority */ - uint8_t txpin; /* TX pin */ - uint8_t txsig; /* TX signal */ - uint8_t rxpin; /* RX pin */ - uint8_t rxsig; /* RX signal */ + uint8_t periph; /* UART peripheral ID */ + uint8_t id; /* UART ID */ + uint8_t irq; /* IRQ associated with this UART */ + uint8_t cpu; /* CPU ID */ + int cpuint; /* CPU interrupt assigned to this UART */ + uint32_t baud; /* Configured baud rate */ + uint8_t bits; /* Data length (5 to 8 bits). */ + uint8_t parity; /* 0=no parity, 1=odd parity, 2=even parity */ + uint8_t stop_b2; /* Use 2 stop bits? 0 = no (use 1) 1 = yes (use 2) */ + uint8_t int_pri; /* UART Interrupt Priority */ + uint8_t txpin; /* TX pin */ + uint8_t txsig; /* TX signal */ + uint8_t rxpin; /* RX pin */ + uint8_t rxsig; /* RX signal */ #ifdef CONFIG_SERIAL_IFLOWCONTROL - uint8_t rtspin; /* RTS pin number */ - uint8_t rtssig; /* RTS signal */ - bool iflow; /* Input flow control (RTS) enabled */ + uint8_t rtspin; /* RTS pin number */ + uint8_t rtssig; /* RTS signal */ + bool iflow; /* Input flow control (RTS) enabled */ #endif #ifdef CONFIG_SERIAL_OFLOWCONTROL - uint8_t ctspin; /* CTS pin number */ - uint8_t ctssig; /* CTS signal */ - bool oflow; /* Output flow control (CTS) enabled */ + uint8_t ctspin; /* CTS pin number */ + uint8_t ctssig; /* CTS signal */ + bool oflow; /* Output flow control (CTS) enabled */ #endif - spinlock_t lock; /* Device-specific lock */ +#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 + spinlock_t lock; /* Device-specific lock */ }; extern struct esp32s3_uart_s g_uart0_config; diff --git a/arch/xtensa/src/esp32s3/esp32s3_serial.c b/arch/xtensa/src/esp32s3/esp32s3_serial.c index b948bc0daca..b4f13f25122 100644 --- a/arch/xtensa/src/esp32s3/esp32s3_serial.c +++ b/arch/xtensa/src/esp32s3/esp32s3_serial.c @@ -45,6 +45,7 @@ #include "esp32s3_config.h" #include "esp32s3_irq.h" #include "esp32s3_lowputc.h" +#include "esp32s3_gpio.h" #include "hardware/esp32s3_uart.h" #include "hardware/esp32s3_system.h" @@ -315,6 +316,18 @@ static int uart_handler(int irq, void *context, void *arg) int_status = getreg32(UART_INT_ST_REG(priv->id)); +#ifdef HAVE_RS485 + if ((int_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) != 0 && + esp32s3_txempty(dev)) + { + if (dev->xmit.tail == dev->xmit.head) + { + esp32s3_gpiowrite(priv->rs485_dir_gpio, + !priv->rs485_dir_polarity); + } + } +#endif + /* Tx fifo empty interrupt or UART tx done int */ if ((int_status & tx_mask) != 0) @@ -445,9 +458,18 @@ static int esp32s3_setup(struct uart_dev_s *dev) } #endif - /* No Tx idle interval */ +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + esp32s3_lowputc_set_tx_idle_time(priv, 1); + } + else +#endif + { + /* No Tx idle interval */ - esp32s3_lowputc_set_tx_idle_time(priv, 0); + esp32s3_lowputc_set_tx_idle_time(priv, 0); + } /* Enable cores */ @@ -590,6 +612,18 @@ static void esp32s3_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->rs485_dir_gpio != 0) + { + modifyreg32(UART_INT_ENA_REG(priv->id), + 0, UART_TX_BRK_IDLE_DONE_INT_ENA); + } +#endif + /* Set to receive an interrupt when the TX holding register register * is empty */ @@ -740,7 +774,16 @@ static bool esp32s3_txempty(struct uart_dev_s *dev) static void esp32s3_send(struct uart_dev_s *dev, int ch) { - esp32s3_lowputc_send_byte(dev->priv, (char)ch); + struct esp32s3_uart_s *priv = dev->priv; + +#ifdef HAVE_RS485 + if (priv->rs485_dir_gpio != 0) + { + esp32s3_gpiowrite(priv->rs485_dir_gpio, priv->rs485_dir_polarity); + } +#endif + + esp32s3_lowputc_send_byte(priv, (char)ch); } /****************************************************************************