risc-v/esp32-c3: Add support for HW flow control.

This commit is contained in:
Sara Souza 2021-05-28 14:42:24 -03:00 committed by Xiang Xiao
parent 24c206b3f8
commit b54be4e946
4 changed files with 332 additions and 7 deletions

View File

@ -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

View File

@ -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 */
@ -104,6 +140,72 @@ struct esp32c3_uart_s g_uart1_config =
* Public Functions
****************************************************************************/
/****************************************************************************
* 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
*
@ -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
}
/****************************************************************************

View File

@ -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;
@ -114,6 +124,38 @@ extern struct esp32c3_uart_s g_uart1_config;
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* 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
*

View File

@ -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.
@ -852,6 +920,78 @@ static int esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg)
return ret;
}
/****************************************************************************
* 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
****************************************************************************/