xtensa/esp32s2: add UART RS485 support

This commit is contained in:
Eren Terzioglu
2023-09-28 16:41:21 +03:00
committed by Petro Karashchenko
parent 2ffb72917d
commit 071fb18501
5 changed files with 170 additions and 1 deletions
+50
View File
@@ -583,6 +583,31 @@ menu "UART Configuration"
if ESP32S2_UART0
config ESP32S2_UART0_RS485
bool "RS-485 on UART0"
default n
---help---
Enable RS-485 interface on UART0. Your board config will have to
provide GPIO_UART0_RS485_DIR pin definition.
config ESP32S2_UART0_RS485_DIR_PIN
int "UART0 RS-485 DIR pin"
default 25
range 0 46
depends on ESP32S2_UART0_RS485
---help---
DIR pin for RS-485 on UART0. This pin will control the RS485 enable
TX of the RS485 transceiver.
config ESP32S2_UART0_RS485_DIR_POLARITY
int "UART0 RS-485 DIR pin polarity"
default 1
range 0 1
depends on ESP32S2_UART0_RS485
---help---
Polarity of DIR pin for RS-485 on UART0. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config ESP32S2_UART0_TXPIN
int "UART0 Tx Pin"
default 43
@@ -609,6 +634,31 @@ endif # ESP32S2_UART0
if ESP32S2_UART1
config ESP32S2_UART1_RS485
bool "RS-485 on UART1"
default n
---help---
Enable RS-485 interface on UART1. Your board config will have to
provide GPIO_UART1_RS485_DIR pin definition.
config ESP32S2_UART1_RS485_DIR_PIN
int "UART1 RS-485 DIR pin"
default 14
range 0 46
depends on ESP32S2_UART1_RS485
---help---
DIR pin for RS-485 on UART1. This pin will control the RS485 enable
TX of the RS485 transceiver.
config ESP32S2_UART1_RS485_DIR_POLARITY
int "UART1 RS-485 DIR pin polarity"
default 1
range 0 1
depends on ESP32S2_UART1_RS485
---help---
Polarity of DIR pin for RS-485 on UART1. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config ESP32S2_UART1_TXPIN
int "UART1 Tx Pin"
default 17
+7
View File
@@ -43,6 +43,13 @@
# define HAVE_UART_DEVICE 1
#endif
/* Is RS-485 used? */
#if defined(CONFIG_ESP32S2_UART0_RS485) || \
defined(CONFIG_ESP32S2_UART1_RS485)
# define HAVE_RS485 1
#endif
/* Serial Console ***********************************************************/
/* Is there a serial console? There should be no more than one defined. It
+44
View File
@@ -90,6 +90,14 @@ struct esp32s2_uart_s g_uart0_config =
.oflow = false, /* output flow control (CTS) disabled */
#endif
#endif
#ifdef CONFIG_ESP32S2_UART0_RS485
.rs485_dir_gpio = CONFIG_ESP32S2_UART0_RS485_DIR_PIN,
#if (CONFIG_ESP32S2_UART0_RS485_DIR_POLARITY == 0)
.rs485_dir_polarity = false,
#else
.rs485_dir_polarity = true,
#endif
#endif
};
#endif /* CONFIG_ESP32S2_UART0 */
@@ -129,6 +137,14 @@ struct esp32s2_uart_s g_uart1_config =
.oflow = false, /* output flow control (CTS) disabled */
#endif
#endif
#ifdef CONFIG_ESP32S2_UART1_RS485
.rs485_dir_gpio = CONFIG_ESP32S2_UART1_RS485_DIR_PIN,
#if (CONFIG_ESP32S2_UART1_RS485_DIR_POLARITY == 0)
.rs485_dir_polarity = false,
#else
.rs485_dir_polarity = true,
#endif
#endif
};
#endif /* CONFIG_ESP32S2_UART1 */
@@ -501,6 +517,25 @@ void esp32s2_lowputc_stop_length(const struct esp32s2_uart_s *priv)
}
}
/****************************************************************************
* Name: esp32s2_lowputc_set_tx_idle_time
*
* Description:
* Set the idle time between transfers.
*
* Parameters:
* priv - Pointer to the private driver struct.
* time - Desired time interval between the transfers.
*
****************************************************************************/
void esp32s2_lowputc_set_tx_idle_time(const struct esp32s2_uart_s *priv,
uint32_t time)
{
modifyreg32(UART_IDLE_CONF_REG(priv->id), UART_TX_IDLE_NUM_M,
VALUE_TO_FIELD(time, UART_TX_IDLE_NUM));
}
/****************************************************************************
* Name: esp32s2_lowputc_send_byte
*
@@ -716,6 +751,15 @@ void esp32s2_lowputc_config_pins(const struct esp32s2_uart_s *priv)
esp32s2_gpio_matrix_in(priv->ctspin, priv->ctssig, 0);
}
#endif
#ifdef HAVE_RS485
if (priv->rs485_dir_gpio != 0)
{
esp32s2_configgpio(priv->rs485_dir_gpio, OUTPUT);
esp32s2_gpio_matrix_out(priv->rs485_dir_gpio, SIG_GPIO_OUT_IDX, 0, 0);
esp32s2_gpiowrite(priv->rs485_dir_gpio, !priv->rs485_dir_polarity);
}
#endif
}
/****************************************************************************
+19
View File
@@ -102,6 +102,10 @@ struct esp32s2_uart_s
uint8_t ctssig; /* CTS signal */
bool oflow; /* Output flow control (CTS) enabled */
#endif
#ifdef HAVE_RS485
uint8_t rs485_dir_gpio; /* UART RS-485 DIR GPIO pin cfg */
bool rs485_dir_polarity; /* UART RS-485 DIR TXEN polarity */
#endif
};
extern struct esp32s2_uart_s g_uart0_config;
@@ -297,6 +301,21 @@ int esp32s2_lowputc_data_length(const struct esp32s2_uart_s *priv);
void esp32s2_lowputc_stop_length(const struct esp32s2_uart_s *priv);
/****************************************************************************
* Name: esp32s2_lowputc_set_tx_idle_time
*
* Description:
* Set the idle time between transfers.
*
* Parameters:
* priv - Pointer to the private driver struct.
* time - Desired time interval between the transfers.
*
****************************************************************************/
void esp32s2_lowputc_set_tx_idle_time(const struct esp32s2_uart_s *priv,
uint32_t time);
/****************************************************************************
* Name: esp32s2_lowputc_send_byte
*
+50 -1
View File
@@ -45,6 +45,7 @@
#include "esp32s2_config.h"
#include "esp32s2_irq.h"
#include "esp32s2_lowputc.h"
#include "esp32s2_gpio.h"
#include "hardware/esp32s2_uart.h"
#include "hardware/esp32s2_system.h"
@@ -237,6 +238,18 @@ static int uart_handler(int irq, void *context, void *arg)
int_status = getreg32(UART_INT_ST_REG(priv->id));
#ifdef HAVE_RS485
if ((int_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) != 0 &&
esp32s2_txempty(dev))
{
if (dev->xmit.tail == dev->xmit.head)
{
esp32s2_gpiowrite(priv->rs485_dir_gpio,
!priv->rs485_dir_polarity);
}
}
#endif
/* TX FIFO empty interrupt or UART TX done int */
if (int_status & tx_mask)
@@ -369,6 +382,21 @@ static int esp32s2_setup(struct uart_dev_s *dev)
esp32s2_lowputc_set_oflow(priv, false);
}
#endif
#ifdef HAVE_RS485
/* Configure the idle time between transfers */
if (priv->rs485_dir_gpio != 0)
{
esp32s2_lowputc_set_tx_idle_time(priv, 1);
}
else
#endif
{
/* No Tx idle interval */
esp32s2_lowputc_set_tx_idle_time(priv, 0);
}
/* Reset FIFOs */
@@ -513,6 +541,18 @@ static void esp32s2_txint(struct uart_dev_s *dev, bool enable)
if (enable)
{
/* After all bytes physically transmitted in the RS485 bus
* the TX_BRK_IDLE will indicate we can disable the TX pin.
*/
#ifdef HAVE_RS485
if (priv->rs485_dir_gpio != 0)
{
modifyreg32(UART_INT_ENA_REG(priv->id),
0, UART_TX_BRK_IDLE_DONE_INT_ENA);
}
#endif
/* Set to receive an interrupt when the TX holding FIFO is empty or
* a transmission is done.
*/
@@ -658,7 +698,16 @@ static bool esp32s2_txempty(struct uart_dev_s *dev)
static void esp32s2_send(struct uart_dev_s *dev, int ch)
{
esp32s2_lowputc_send_byte(dev->priv, ch);
struct esp32s2_uart_s *priv = dev->priv;
#ifdef HAVE_RS485
if (priv->rs485_dir_gpio != 0)
{
esp32s2_gpiowrite(priv->rs485_dir_gpio, priv->rs485_dir_polarity);
}
#endif
esp32s2_lowputc_send_byte(priv, (char)ch);
}
/****************************************************************************