risc-v/esp32-c3: Add support for HW flow control.
This commit is contained in:
parent
24c206b3f8
commit
b54be4e946
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
****************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user