You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/01/10 02:49:26 UTC

[incubator-nuttx] 01/02: esp32: Add support to RS485

This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 2079cc0f6e479e93be2bf3f54c6cc85492b81752
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Sat Jan 8 18:25:30 2022 -0300

    esp32: Add support to RS485
---
 arch/xtensa/src/esp32/Kconfig        | 78 ++++++++++++++++++++++++++++++++++++
 arch/xtensa/src/esp32/esp32_config.h |  8 ++++
 arch/xtensa/src/esp32/esp32_serial.c | 78 +++++++++++++++++++++++++++++++++++-
 3 files changed, 163 insertions(+), 1 deletion(-)

diff --git a/arch/xtensa/src/esp32/Kconfig b/arch/xtensa/src/esp32/Kconfig
index 67d2894..4c0d3b1 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 4f16f25..47e154e 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 f56eb5a..e10e999 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
 }
 
 /****************************************************************************