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 2021/06/02 02:37:34 UTC

[incubator-nuttx] branch master updated: risc-v/esp32-c3: Add support for HW flow control.

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


The following commit(s) were added to refs/heads/master by this push:
     new b54be4e  risc-v/esp32-c3: Add support for HW flow control.
b54be4e is described below

commit b54be4e946b3d9bf0bdf55207abc11dec78bdd76
Author: Sara Souza <sa...@espressif.com>
AuthorDate: Fri May 28 14:42:24 2021 -0300

    risc-v/esp32-c3: Add support for HW flow control.
---
 arch/risc-v/src/esp32c3/Kconfig           |  28 +++++-
 arch/risc-v/src/esp32c3/esp32c3_lowputc.c | 119 ++++++++++++++++++++++++
 arch/risc-v/src/esp32c3/esp32c3_lowputc.h |  42 +++++++++
 arch/risc-v/src/esp32c3/esp32c3_serial.c  | 150 +++++++++++++++++++++++++++++-
 4 files changed, 332 insertions(+), 7 deletions(-)

diff --git a/arch/risc-v/src/esp32c3/Kconfig b/arch/risc-v/src/esp32c3/Kconfig
index 2222e6a..e102dcb 100644
--- a/arch/risc-v/src/esp32c3/Kconfig
+++ b/arch/risc-v/src/esp32c3/Kconfig
@@ -413,17 +413,41 @@ config ESP32C3_UART0_RXPIN
 	int "UART0 RX Pin"
 	default 20
 
+config ESP32C3_UART0_RTSPIN
+	int "UART0 RTS Pin"
+	depends on SERIAL_IFLOWCONTROL
+	default 16
+	range 0 21
+
+config ESP32C3_UART0_CTSPIN
+	int "UART0 CTS Pin"
+	depends on SERIAL_OFLOWCONTROL
+	default 15
+	range 0 21
+
 endif # ESP32C3_UART0
 
 if ESP32C3_UART1
 
 config ESP32C3_UART1_TXPIN
 	int "UART1 TX Pin"
-	default 6
+	default 8
 
 config ESP32C3_UART1_RXPIN
 	int "UART1 RX Pin"
-	default 7
+	default 9
+
+config ESP32C3_UART1_RTSPIN
+	int "UART1 RTS Pin"
+	depends on SERIAL_IFLOWCONTROL
+	default 1
+	range 0 21
+
+config ESP32C3_UART1_CTSPIN
+	int "UART1 CTS Pin"
+	depends on SERIAL_OFLOWCONTROL
+	default 2
+	range 0 21
 
 endif # ESP32C3_UART1
 
diff --git a/arch/risc-v/src/esp32c3/esp32c3_lowputc.c b/arch/risc-v/src/esp32c3/esp32c3_lowputc.c
index 1aa4fdd..18e3842 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_lowputc.c
+++ b/arch/risc-v/src/esp32c3/esp32c3_lowputc.c
@@ -74,6 +74,24 @@ struct esp32c3_uart_s g_uart0_config =
   .txsig = U0TXD_OUT_IDX,
   .rxpin = CONFIG_ESP32C3_UART0_RXPIN,
   .rxsig = U0RXD_IN_IDX,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  .rtspin = CONFIG_ESP32C3_UART0_RTSPIN,
+  .rtssig = U0RTS_OUT_IDX,
+#ifdef CONFIG_UART0_IFLOWCONTROL
+  .iflow          = true,    /* input flow control (RTS) enabled */
+#else
+  .iflow          = false,   /* input flow control (RTS) disabled */
+#endif
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+  .ctspin = CONFIG_ESP32C3_UART0_CTSPIN,
+  .ctssig = U0CTS_IN_IDX,
+#ifdef CONFIG_UART0_OFLOWCONTROL
+  .oflow          = true,    /* output flow control (CTS) enabled */
+#else
+  .oflow          = false,   /* output flow control (CTS) disabled */
+#endif
+#endif
 };
 
 #endif /* CONFIG_ESP32C3_UART0 */
@@ -95,6 +113,24 @@ struct esp32c3_uart_s g_uart1_config =
   .txsig = U1TXD_OUT_IDX,
   .rxpin = CONFIG_ESP32C3_UART1_RXPIN,
   .rxsig = U1RXD_IN_IDX,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  .rtspin = CONFIG_ESP32C3_UART1_RTSPIN,
+  .rtssig = U1RTS_OUT_IDX,
+#ifdef CONFIG_UART1_IFLOWCONTROL
+  .iflow          = true,    /* input flow control (RTS) enabled */
+#else
+  .iflow          = false,   /* input flow control (RTS) disabled */
+#endif
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+  .ctspin = CONFIG_ESP32C3_UART1_CTSPIN,
+  .ctssig = U1CTS_IN_IDX,
+#ifdef CONFIG_UART1_OFLOWCONTROL
+  .oflow          = true,    /* output flow control (CTS) enabled */
+#else
+  .oflow          = false,   /* output flow control (CTS) disabled */
+#endif
+#endif
 };
 
 #endif /* CONFIG_ESP32C3_UART1 */
@@ -105,6 +141,72 @@ struct esp32c3_uart_s g_uart1_config =
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: esp32c3_lowputc_set_iflow
+ *
+ * Description:
+ *   Configure the input hardware flow control.
+ *
+ * Parameters:
+ *   priv           - Pointer to the private driver struct.
+ *   threshold      - RX FIFO value from which RST will automatically be
+ *                    asserted.
+ *   enable         - true = enable, false = disable
+ *
+ ****************************************************************************/
+
+void esp32c3_lowputc_set_iflow(const struct esp32c3_uart_s *priv,
+                               uint8_t threshold, bool enable)
+{
+  uint32_t mask;
+  if (enable)
+    {
+      /* Enable RX flow control */
+
+      modifyreg32(UART_CONF1_REG(priv->id), 0, UART_RX_FLOW_EN);
+
+      /* Configure the threshold */
+
+      mask = VALUE_TO_FIELD(threshold, UART_RX_FLOW_THRHD);
+      modifyreg32(UART_MEM_CONF_REG(priv->id), UART_RX_FLOW_THRHD_M, mask);
+    }
+  else
+    {
+      /* Disable RX flow control */
+
+      modifyreg32(UART_CONF1_REG(priv->id), UART_RX_FLOW_EN, 0);
+    }
+}
+
+/****************************************************************************
+ * Name: esp32c3_lowputc_set_oflow
+ *
+ * Description:
+ *   Configure the output hardware flow control.
+ *
+ * Parameters:
+ *   priv           - Pointer to the private driver struct.
+ *   enable         - true = enable, false = disable
+ *
+ ****************************************************************************/
+
+void esp32c3_lowputc_set_oflow(const struct esp32c3_uart_s *priv,
+                               bool enable)
+{
+  if (enable)
+    {
+      /* Enable TX flow control */
+
+      modifyreg32(UART_CONF0_REG(priv->id), 0, UART_TX_FLOW_EN);
+    }
+  else
+    {
+      /* Disable TX flow control */
+
+      modifyreg32(UART_CONF0_REG(priv->id), UART_TX_FLOW_EN, 0);
+    }
+}
+
+/****************************************************************************
  * Name: esp32c3_lowputc_reset_core
  *
  * Description:
@@ -642,6 +744,23 @@ void esp32c3_lowputc_config_pins(const struct esp32c3_uart_s *priv)
 
   esp32c3_configgpio(priv->rxpin, INPUT_FUNCTION_1);
   esp32c3_gpio_matrix_in(priv->rxpin, priv->rxsig, 0);
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  if (priv->iflow)
+    {
+      esp32c3_configgpio(priv->rtspin, OUTPUT_FUNCTION_1);
+      esp32c3_gpio_matrix_out(priv->rtspin, priv->rtssig,
+                              0, 0);
+    }
+
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+  if (priv->oflow)
+    {
+      esp32c3_configgpio(priv->ctspin, INPUT_FUNCTION_1);
+      esp32c3_gpio_matrix_in(priv->ctspin, priv->ctssig, 0);
+    }
+#endif
 }
 
 /****************************************************************************
diff --git a/arch/risc-v/src/esp32c3/esp32c3_lowputc.h b/arch/risc-v/src/esp32c3/esp32c3_lowputc.h
index d429571..e8455ca 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_lowputc.h
+++ b/arch/risc-v/src/esp32c3/esp32c3_lowputc.h
@@ -105,6 +105,16 @@ struct esp32c3_uart_s
   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 */
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+  uint8_t  ctspin;          /* CTS pin number */
+  uint8_t  ctssig;          /* CTS signal */
+  bool     oflow;           /* Output flow control (CTS) enabled */
+#endif
 };
 
 extern struct esp32c3_uart_s g_uart0_config;
@@ -115,6 +125,38 @@ extern struct esp32c3_uart_s g_uart1_config;
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: esp32c3_lowputc_set_iflow
+ *
+ * Description:
+ *   Configure the input hardware flow control.
+ *
+ * Parameters:
+ *   priv           - Pointer to the private driver struct.
+ *   threshold      - RX FIFO value from which RST will automatically be
+ *                    asserted.
+ *   enable         - true = enable, false = disable
+ *
+ ****************************************************************************/
+
+void esp32c3_lowputc_set_iflow(const struct esp32c3_uart_s *priv,
+                               uint8_t threshold, bool enable);
+
+/****************************************************************************
+ * Name: esp32c3_lowputc_set_oflow
+ *
+ * Description:
+ *   Configure the output hardware flow control.
+ *
+ * Parameters:
+ *   priv           - Pointer to the private driver struct.
+ *   enable         - true = enable, false = disable
+ *
+ ****************************************************************************/
+
+void esp32c3_lowputc_set_oflow(const struct esp32c3_uart_s *priv,
+                               bool enable);
+
+/****************************************************************************
  * Name: esp32c3_lowputc_reset_core
  *
  * Description:
diff --git a/arch/risc-v/src/esp32c3/esp32c3_serial.c b/arch/risc-v/src/esp32c3/esp32c3_serial.c
index 196a8b0..4670d20 100644
--- a/arch/risc-v/src/esp32c3/esp32c3_serial.c
+++ b/arch/risc-v/src/esp32c3/esp32c3_serial.c
@@ -122,6 +122,10 @@ static bool esp32c3_txempty(struct uart_dev_s *dev);
 static void esp32c3_send(struct uart_dev_s *dev, int ch);
 static int  esp32c3_receive(struct uart_dev_s *dev, unsigned int *status);
 static int  esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg);
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+static bool esp32c3_rxflowcontrol(struct uart_dev_s *dev,
+                                  unsigned int nbuffered, bool upper);
+#endif
 
 /****************************************************************************
  * Private Data
@@ -144,7 +148,7 @@ static struct uart_ops_s g_uart_ops =
     .receive     = esp32c3_receive,
     .ioctl       = esp32c3_ioctl,
 #ifdef CONFIG_SERIAL_IFLOWCONTROL
-    .rxflowcontrol = NULL,
+    .rxflowcontrol  = esp32c3_rxflowcontrol,
 #endif
 };
 
@@ -244,16 +248,16 @@ static int uart_handler(int irq, FAR void *context, FAR void *arg)
 
   if (int_status & tx_mask)
     {
-        uart_xmitchars(dev);
-        modifyreg32(UART_INT_CLR_REG(priv->id), tx_mask, tx_mask);
+      uart_xmitchars(dev);
+      modifyreg32(UART_INT_CLR_REG(priv->id), tx_mask, tx_mask);
     }
 
   /* Rx fifo timeout interrupt or rx fifo full interrupt */
 
   if (int_status & rx_mask)
     {
-        uart_recvchars(dev);
-        modifyreg32(UART_INT_CLR_REG(priv->id), rx_mask, rx_mask);
+      uart_recvchars(dev);
+      modifyreg32(UART_INT_CLR_REG(priv->id), rx_mask, rx_mask);
     }
 
   return OK;
@@ -332,6 +336,44 @@ static int esp32c3_setup(struct uart_dev_s *dev)
 
   esp32c3_lowputc_stop_length(priv);
 
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+  /* Configure the input flow control */
+
+  if (priv->iflow)
+    {
+      /* Enable input flow control and set the RX FIFO threshold
+       * to assert the RTS line to half the RX FIFO buffer.
+       * It will then save some space on the hardware fifo to
+       * remaining bytes that may arrive after RTS be asserted
+       * and before the transmitter stops sending data.
+       */
+
+      esp32c3_lowputc_set_iflow(priv, (uint8_t)(UART_RX_FIFO_SIZE / 2),
+                                true);
+    }
+  else
+    {
+      /* Just disable input flow control, threshold parameter
+       * will be discarded.
+       */
+
+      esp32c3_lowputc_set_iflow(priv, 0 , false);
+    }
+
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+  /* Configure the ouput flow control */
+
+  if (priv->oflow)
+    {
+      esp32c3_lowputc_set_oflow(priv, true);
+    }
+  else
+    {
+      esp32c3_lowputc_set_oflow(priv, false);
+    }
+#endif
+
   /* No Tx idle interval */
 
   esp32c3_lowputc_set_tx_idle_time(priv, 0);
@@ -725,6 +767,13 @@ static int esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg)
 
         termiosp->c_cflag |= (priv->stop_b2) ? CSTOPB : 0;
 
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+        termiosp->c_cflag |=  (priv->oflow) ? CCTS_OFLOW : 0;
+#endif
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+        termiosp->c_cflag |=  (priv->iflow) ? CRTS_IFLOW : 0;
+#endif
+
         /* Set the baud rate in ther termiosp using the
          * cfsetispeed interface.
          */
@@ -764,6 +813,12 @@ static int esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg)
         uint8_t  parity;
         uint8_t  bits;
         uint8_t  stop2;
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+        bool iflow;
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+        bool oflow;
+#endif
 
         if (!termiosp)
           {
@@ -815,6 +870,13 @@ static int esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg)
 
         stop2 = (termiosp->c_cflag & CSTOPB) ? 1 : 0;
 
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+        iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0;
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+        oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0;
+#endif
+
         /* Verify that all settings are valid before
          * performing the changes.
          */
@@ -827,6 +889,12 @@ static int esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg)
             priv->parity    = parity;
             priv->bits      = bits;
             priv->stop_b2   = stop2;
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+            priv->iflow     = iflow;
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+            priv->oflow     = oflow;
+#endif
 
             /* Effect the changes immediately - note that we do not
              * implement TCSADRAIN or TCSAFLUSH, only TCSANOW option.
@@ -853,6 +921,78 @@ static int esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg)
 }
 
 /****************************************************************************
+ * Name: esp32c3_rxflowcontrol
+ *
+ * Description:
+ *   Called when upper half RX buffer is full (or exceeds configured
+ *   watermark levels if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined).
+ *   Return true if UART activated RX flow control to block more incoming
+ *   data.
+ *   NOTE: ESP32-C3 has a hardware RX FIFO threshold mechanism to control
+ *   RTS line and to stop receiving data. This is very similar to the concept
+ *   behind upper watermark level. The hardware threshold is used here
+ *   to control the RTS line. When setting the threshold to zero, RTS will
+ *   immediately be asserted. If nbuffered = 0 or the lower watermark is
+ *   crossed and the serial driver decides to disable RX flow control, the
+ *   threshold will be changed to UART_RX_FLOW_THRHD_VALUE, which is almost
+ *   half the HW RX FIFO capacity. It keeps some space to keep the data
+ *   received between the RTS assertion and the stop by the sender.
+ *
+ * Input Parameters:
+ *   dev       - UART device instance
+ *   nbuffered - the number of characters currently buffered
+ *               (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is
+ *               not defined the value will be 0 for an empty buffer or the
+ *               defined buffer size for a full buffer)
+ *   upper     - true indicates the upper watermark was crossed where
+ *               false indicates the lower watermark has been crossed
+ *
+ * Returned Value:
+ *   true if RX flow control activated.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+static bool esp32c3_rxflowcontrol(struct uart_dev_s *dev,
+                                  unsigned int nbuffered, bool upper)
+{
+  bool ret = false;
+  struct esp32c3_uart_s *priv = dev->priv;
+  if (priv->iflow)
+    {
+      if (nbuffered == 0 || upper == false)
+        {
+          /* Empty buffer, RTS should be de-asserted and logic in above
+           * layers should re-enable RX interrupt.
+           */
+
+          esp32c3_lowputc_set_iflow(priv, (uint8_t)(UART_RX_FIFO_SIZE / 2),
+                                    true);
+          esp32c3_rxint(dev, true);
+          ret = false;
+        }
+      else
+        {
+          /* If the RX buffer is not zero and watermarks are not enabled,
+           * then this function is called to announce RX buffer is full.
+           * The first thing it should do is to immediately assert RTS.
+           * Software RX FIFO is full, so besides asserting RTS, it's
+           * necessary to disable RX interrupts to prevent remaining bytes
+           * (that arrive after asserting RTS) to be pushed to the
+           * SW RX FIFO.
+           */
+
+          esp32c3_lowputc_set_iflow(priv, 0 , true);
+          esp32c3_rxint(dev, false);
+          ret = true;
+        }
+    }
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
  * Public Functions
  ****************************************************************************/