xtensa/esp32-s2: Add support for serial HW flow control.
This commit is contained in:
parent
b54be4e946
commit
a54fe4ee1e
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
@ -103,6 +139,72 @@ struct esp32s2_uart_s g_uart1_config =
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
@ -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
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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;
|
||||
@ -106,6 +116,38 @@ extern struct esp32s2_uart_s g_uart1_config;
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
*
|
||||
|
@ -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
|
||||
@ -867,6 +936,78 @@ static int esp32s2_ioctl(struct file *filep, int cmd, unsigned long arg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
****************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user