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:46 UTC
[incubator-nuttx] branch master updated: xtensa/esp32-s2: Add
support for serial 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 a54fe4e xtensa/esp32-s2: Add support for serial HW flow control.
a54fe4e is described below
commit a54fe4ee1ecf31a097a674615325f5938a815555
Author: Sara Souza <sa...@espressif.com>
AuthorDate: Tue Jun 1 10:07:27 2021 -0300
xtensa/esp32-s2: Add support for serial HW flow control.
---
arch/xtensa/src/esp32s2/Kconfig | 28 +++++-
arch/xtensa/src/esp32s2/esp32s2_cpuint.c | 2 +-
arch/xtensa/src/esp32s2/esp32s2_lowputc.c | 119 +++++++++++++++++++++++++
arch/xtensa/src/esp32s2/esp32s2_lowputc.h | 42 +++++++++
arch/xtensa/src/esp32s2/esp32s2_serial.c | 143 +++++++++++++++++++++++++++++-
5 files changed, 330 insertions(+), 4 deletions(-)
diff --git a/arch/xtensa/src/esp32s2/Kconfig b/arch/xtensa/src/esp32s2/Kconfig
index 2a5dbdc..e4ccd9a 100644
--- a/arch/xtensa/src/esp32s2/Kconfig
+++ b/arch/xtensa/src/esp32s2/Kconfig
@@ -448,18 +448,42 @@ config ESP32S2_UART0_RXPIN
default 44
range 0 46
+config ESP32S2_UART0_RTSPIN
+ int "UART0 RTS Pin"
+ depends on SERIAL_IFLOWCONTROL
+ default 16
+ range 0 46
+
+config ESP32S2_UART0_CTSPIN
+ int "UART0 CTS Pin"
+ depends on SERIAL_OFLOWCONTROL
+ default 15
+ range 0 46
+
endif # ESP32S2_UART0
if ESP32S2_UART1
config ESP32S2_UART1_TXPIN
int "UART1 Tx Pin"
- default 17
+ default 37
range 0 46
config ESP32S2_UART1_RXPIN
int "UART1 Rx Pin"
- default 18
+ default 38
+ range 0 46
+
+config ESP32S2_UART1_RTSPIN
+ int "UART1 RTS Pin"
+ depends on SERIAL_IFLOWCONTROL
+ default 35
+ range 0 46
+
+config ESP32S2_UART1_CTSPIN
+ int "UART1 CTS Pin"
+ depends on SERIAL_OFLOWCONTROL
+ default 36
range 0 46
endif # ESP32S2_UART1
diff --git a/arch/xtensa/src/esp32s2/esp32s2_cpuint.c b/arch/xtensa/src/esp32s2/esp32s2_cpuint.c
index 4a5db20..ce1c344 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_cpuint.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_cpuint.c
@@ -519,7 +519,7 @@ void esp32s2_free_cpuint(int cpuint)
* periphid - The peripheral number from irq.h to be assigned to
* a CPU interrupt.
* cpuint - The CPU interrupt to receive the peripheral interrupt
- * assignment. This value is returned by
+ * assignment. This value is returned by
* esp32s2_alloc_edgeint or esp32s2_alloc_levelint.
*
* Returned Value:
diff --git a/arch/xtensa/src/esp32s2/esp32s2_lowputc.c b/arch/xtensa/src/esp32s2/esp32s2_lowputc.c
index e6ac517..b1e2aa3 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_lowputc.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_lowputc.c
@@ -73,6 +73,24 @@ struct esp32s2_uart_s g_uart0_config =
.txsig = U0TXD_OUT_IDX,
.rxpin = CONFIG_ESP32S2_UART0_RXPIN,
.rxsig = U0RXD_IN_IDX,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ .rtspin = CONFIG_ESP32S2_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_ESP32S2_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_ESP32S2_UART0 */
@@ -94,6 +112,24 @@ struct esp32s2_uart_s g_uart1_config =
.txsig = U1TXD_OUT_IDX,
.rxpin = CONFIG_ESP32S2_UART1_RXPIN,
.rxsig = U1RXD_IN_IDX,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ .rtspin = CONFIG_ESP32S2_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_ESP32S2_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_ESP32S2_UART1 */
@@ -104,6 +140,72 @@ struct esp32s2_uart_s g_uart1_config =
****************************************************************************/
/****************************************************************************
+ * Name: esp32s2_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 esp32s2_lowputc_set_iflow(const struct esp32s2_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: esp32s2_lowputc_set_oflow
+ *
+ * Description:
+ * Configure the output hardware flow control.
+ *
+ * Parameters:
+ * priv - Pointer to the private driver struct.
+ * enable - true = enable, false = disable
+ *
+ ****************************************************************************/
+
+void esp32s2_lowputc_set_oflow(const struct esp32s2_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: esp32s2_lowputc_enable_sysclk
*
* Description:
@@ -601,6 +703,23 @@ void esp32s2_lowputc_config_pins(const struct esp32s2_uart_s *priv)
/* Route UART RX signal to the selected RX pin */
esp32s2_gpio_matrix_in(priv->rxpin, priv->rxsig, 0);
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ if (priv->iflow)
+ {
+ esp32s2_configgpio(priv->rtspin, OUTPUT_FUNCTION_1);
+ esp32s2_gpio_matrix_out(priv->rtspin, priv->rtssig,
+ 0, 0);
+ }
+
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ if (priv->oflow)
+ {
+ esp32s2_configgpio(priv->ctspin, INPUT_FUNCTION_1);
+ esp32s2_gpio_matrix_in(priv->ctspin, priv->ctssig, 0);
+ }
+#endif
}
/****************************************************************************
diff --git a/arch/xtensa/src/esp32s2/esp32s2_lowputc.h b/arch/xtensa/src/esp32s2/esp32s2_lowputc.h
index 1bf123d..bdf4919 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_lowputc.h
+++ b/arch/xtensa/src/esp32s2/esp32s2_lowputc.h
@@ -97,6 +97,16 @@ struct esp32s2_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 esp32s2_uart_s g_uart0_config;
@@ -107,6 +117,38 @@ extern struct esp32s2_uart_s g_uart1_config;
****************************************************************************/
/****************************************************************************
+ * Name: esp32s2_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 esp32s2_lowputc_set_iflow(const struct esp32s2_uart_s *priv,
+ uint8_t threshold, bool enable);
+
+/****************************************************************************
+ * Name: esp32s2_lowputc_set_oflow
+ *
+ * Description:
+ * Configure the output hardware flow control.
+ *
+ * Parameters:
+ * priv - Pointer to the private driver struct.
+ * enable - true = enable, false = disable
+ *
+ ****************************************************************************/
+
+void esp32s2_lowputc_set_oflow(const struct esp32s2_uart_s *priv,
+ bool enable);
+
+/****************************************************************************
* Name: esp32s2_lowputc_enable_sysclk
*
* Description:
diff --git a/arch/xtensa/src/esp32s2/esp32s2_serial.c b/arch/xtensa/src/esp32s2/esp32s2_serial.c
index 5110b1d..91be105 100644
--- a/arch/xtensa/src/esp32s2/esp32s2_serial.c
+++ b/arch/xtensa/src/esp32s2/esp32s2_serial.c
@@ -116,6 +116,10 @@ static bool esp32s2_txempty(struct uart_dev_s *dev);
static void esp32s2_send(struct uart_dev_s *dev, int ch);
static int esp32s2_receive(struct uart_dev_s *dev, unsigned int *status);
static int esp32s2_ioctl(struct file *filep, int cmd, unsigned long arg);
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+static bool esp32s2_rxflowcontrol(struct uart_dev_s *dev,
+ unsigned int nbuffered, bool upper);
+#endif
/****************************************************************************
* Private Data
@@ -138,7 +142,7 @@ static struct uart_ops_s g_uart_ops =
.receive = esp32s2_receive,
.ioctl = esp32s2_ioctl,
#ifdef CONFIG_SERIAL_IFLOWCONTROL
- .rxflowcontrol = NULL,
+ .rxflowcontrol = esp32s2_rxflowcontrol,
#endif
};
@@ -329,6 +333,44 @@ static int esp32s2_setup(struct uart_dev_s *dev)
esp32s2_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.
+ */
+
+ esp32s2_lowputc_set_iflow(priv, (uint8_t)(UART_RX_FIFO_SIZE / 2),
+ true);
+ }
+ else
+ {
+ /* Just disable input flow control, threshold parameter
+ * will be discarded.
+ */
+
+ esp32s2_lowputc_set_iflow(priv, 0 , false);
+ }
+
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ /* Configure the ouput flow control */
+
+ if (priv->oflow)
+ {
+ esp32s2_lowputc_set_oflow(priv, true);
+ }
+ else
+ {
+ esp32s2_lowputc_set_oflow(priv, false);
+ }
+#endif
+
/* Reset FIFOs */
esp32s2_lowputc_rst_txfifo(priv);
@@ -740,6 +782,13 @@ static int esp32s2_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 the termiosp using the
* cfsetispeed interface.
*/
@@ -779,6 +828,12 @@ static int esp32s2_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)
{
@@ -830,6 +885,13 @@ static int esp32s2_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.
*/
@@ -843,6 +905,13 @@ static int esp32s2_ioctl(struct file *filep, int cmd, unsigned long arg)
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.
* See nuttx/libs/libc/termios/lib_tcsetattr.c
@@ -868,6 +937,78 @@ static int esp32s2_ioctl(struct file *filep, int cmd, unsigned long arg)
}
/****************************************************************************
+ * Name: esp32s2_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-S2 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 esp32s2_rxflowcontrol(struct uart_dev_s *dev,
+ unsigned int nbuffered, bool upper)
+{
+ bool ret = false;
+ struct esp32s2_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.
+ */
+
+ esp32s2_lowputc_set_iflow(priv, (uint8_t)(UART_RX_FIFO_SIZE / 2),
+ true);
+ esp32s2_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.
+ */
+
+ esp32s2_lowputc_set_iflow(priv, 0 , true);
+ esp32s2_rxint(dev, false);
+ ret = true;
+ }
+ }
+
+ return ret;
+}
+#endif
+
+/****************************************************************************
* Public Functions
****************************************************************************/