esp32: Add support to RS485

This commit is contained in:
Alan C. Assis 2022-01-08 18:25:30 -03:00 committed by Xiang Xiao
parent 1fd51ccbe2
commit 2079cc0f6e
3 changed files with 163 additions and 1 deletions

View File

@ -566,6 +566,32 @@ menu "UART configuration"
if ESP32_UART0
config ESP32_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. Currently it cannot be
used with UART0_RXDMA.
config ESP32_UART0_RS485_DIR_PIN
int "UART0 RS-485 DIR pin"
default 4
range 1 39
depends on ESP32_UART0_RS485
---help---
DIR pin for RS-485 on UART0. This pin will control the RS485 enable
TX of the RS485 transceiver.
config ESP32_UART0_RS485_DIR_POLARITY
int "UART0 RS-485 DIR pin polarity"
default 1
range 0 1
depends on ESP32_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 ESP32_UART0_TXPIN
int "UART0 Tx Pin"
default 1
@ -606,6 +632,32 @@ endif # ESP32_UART0
if ESP32_UART1
config ESP32_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. Currently it cannot be
used with UART1_RXDMA.
config ESP32_UART1_RS485_DIR_PIN
int "UART1 RS-485 DIR pin"
default 14
range 1 39
depends on ESP32_UART1_RS485
---help---
DIR pin for RS-485 on UART1. This pin will control the RS485 enable
TX of the RS485 transceiver.
config ESP32_UART1_RS485_DIR_POLARITY
int "UART1 RS-485 DIR pin polarity"
default 1
range 0 1
depends on ESP32_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 ESP32_UART1_TXPIN
int "UART1 Tx Pin"
default 10
@ -646,6 +698,32 @@ endif # ESP32_UART1
if ESP32_UART2
config ESP32_UART2_RS485
bool "RS-485 on UART2"
default n
---help---
Enable RS-485 interface on UART2. Your board config will have to
provide GPIO_UART2_RS485_DIR pin definition. Currently it cannot be
used with UART2_RXDMA.
config ESP32_UART2_RS485_DIR_PIN
int "UART2 RS-485 DIR pin"
default 18
range 1 39
depends on ESP32_UART2_RS485
---help---
DIR pin for RS-485 on UART2. This pin will control the RS485 enable
TX of the RS485 transceiver.
config ESP32_UART2_RS485_DIR_POLARITY
int "UART2 RS-485 DIR pin polarity"
default 1
range 0 1
depends on ESP32_UART2_RS485
---help---
Polarity of DIR pin for RS-485 on UART2. Set to state on DIR pin which
enables TX (0 - low / nTXEN, 1 - high / TXEN).
config ESP32_UART2_TXPIN
int "UART2 Tx Pin"
default 19

View File

@ -59,6 +59,14 @@
# define HAVE_UART_DEVICE 1
#endif
/* Is RS-485 used? */
#if defined(CONFIG_ESP32_UART0_RS485) || \
defined(CONFIG_ESP32_UART1_RS485) || \
defined(CONFIG_ESP32_UART2_RS485)
# define HAVE_RS485 1
#endif
/* UART Flow Control ********************************************************/
#ifndef CONFIG_ESP32_UART0

View File

@ -246,6 +246,10 @@ struct esp32_config_s
uint8_t dma_chan; /* DMA instance 0-1 */
sem_t * dma_sem; /* DMA semaphore */
#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
};
/* Current state of the UART */
@ -380,6 +384,14 @@ static const struct esp32_config_s g_uart0config =
#endif
#endif
#endif
#ifdef CONFIG_ESP32_UART0_RS485
.rs485_dir_gpio = CONFIG_ESP32_UART0_RS485_DIR_PIN,
#if (CONFIG_ESP32_UART0_RS485_DIR_POLARITY == 0)
.rs485_dir_polarity = false,
#else
.rs485_dir_polarity = true,
#endif
#endif
};
static struct esp32_dev_s g_uart0priv =
@ -459,6 +471,14 @@ static const struct esp32_config_s g_uart1config =
#endif
#endif
#endif
#ifdef CONFIG_ESP32_UART1_RS485
.rs485_dir_gpio = CONFIG_ESP32_UART1_RS485_DIR_PIN,
#if (CONFIG_ESP32_UART1_RS485_DIR_POLARITY == 0)
.rs485_dir_polarity = false,
#else
.rs485_dir_polarity = true,
#endif
#endif
};
static struct esp32_dev_s g_uart1priv =
@ -538,6 +558,14 @@ static const struct esp32_config_s g_uart2config =
#endif
#endif
#endif
#ifdef CONFIG_ESP32_UART2_RS485
.rs485_dir_gpio = CONFIG_ESP32_UART2_RS485_DIR_PIN,
#if (CONFIG_ESP32_UART2_RS485_DIR_POLARITY == 0)
.rs485_dir_polarity = false,
#else
.rs485_dir_polarity = true,
#endif
#endif
};
static struct esp32_dev_s g_uart2priv =
@ -1345,9 +1373,26 @@ static int esp32_interrupt(int cpuint, void *context, void *arg)
regval = (UART_RXFIFO_FULL_INT_CLR | UART_FRM_ERR_INT_CLR |
UART_RXFIFO_TOUT_INT_CLR | UART_TX_DONE_INT_CLR |
UART_TXFIFO_EMPTY_INT_CLR);
UART_TXFIFO_EMPTY_INT_CLR | UART_TX_BRK_IDLE_DONE_INT_CLR);
putreg32(regval, UART_INT_CLR_REG(priv->config->id));
#ifdef HAVE_RS485
if ((enabled & UART_TX_BRK_IDLE_DONE_INT_ENA) != 0 &&
(status & UART_TX_DONE_INT_ST) != 0)
{
/* If al bytes were transmited, then we can disable the RS485
* transmit (TX/nTX) pin.
*/
nfifo = REG_MASK(status, UART_TXFIFO_CNT);
if (nfifo == 0)
{
esp32_gpiowrite(priv->config->rs485_dir_gpio,
!priv->config->rs485_dir_polarity);
}
}
#endif
/* Are Rx interrupts enabled? The upper layer may hold off Rx input
* by disabling the Rx interrupts if there is no place to saved the
* data, possibly resulting in an overrun error.
@ -1697,6 +1742,14 @@ static void esp32_send(struct uart_dev_s *dev, int ch)
{
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
#ifdef HAVE_RS485
if (priv->config->rs485_dir_gpio != 0)
{
esp32_gpiowrite(priv->config->rs485_dir_gpio,
priv->config->rs485_dir_polarity);
}
#endif
putreg32((uint32_t)ch, AHB_UART_FIFO_REG(priv->config->id));
}
@ -1720,6 +1773,18 @@ static void esp32_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->config->rs485_dir_gpio != 0)
{
modifyreg32(UART_INT_ENA_REG(priv->config->id),
0, UART_TX_BRK_IDLE_DONE_INT_ENA);
}
#endif
/* Set to receive an interrupt when the TX holding register
* is empty.
*/
@ -1829,6 +1894,17 @@ static void esp32_config_pins(struct esp32_dev_s *priv)
esp32_gpio_matrix_in(priv->config->ctspin, priv->config->ctssig, 0);
}
#endif
#ifdef HAVE_RS485
if (priv->config->rs485_dir_gpio != 0)
{
esp32_configgpio(priv->config->rs485_dir_gpio, OUTPUT_FUNCTION_3);
esp32_gpio_matrix_out(priv->config->rs485_dir_gpio,
SIG_GPIO_OUT_IDX, 0, 0);
esp32_gpiowrite(priv->config->rs485_dir_gpio,
!priv->config->rs485_dir_polarity);
}
#endif
}
/****************************************************************************