risc-v/esp32-c3: Fixes gargabe UART issue, refactors serial driver, changes default pins of UART 1 and fixes low baud rate issue.

This commit is contained in:
Sara Souza 2021-03-29 13:14:43 -03:00 committed by Alan Carvalho de Assis
parent 3c30c8b90b
commit 0926e7c578
5 changed files with 143 additions and 120 deletions

View File

@ -307,11 +307,11 @@ if ESP32C3_UART1
config ESP32C3_UART1_TXPIN
int "UART1 TX Pin"
default 18
default 6
config ESP32C3_UART1_RXPIN
int "UART1 RX Pin"
default 19
default 7
endif # ESP32C3_UART1

View File

@ -55,14 +55,15 @@
* Private Data
****************************************************************************/
#ifdef HAVE_SERIAL_CONSOLE
# if defined(CONFIG_UART0_SERIAL_CONSOLE)
#ifdef HAVE_UART_DEVICE
static const struct esp32c3_uart_s g_console_config =
#ifdef CONFIG_ESP32C3_UART0
struct esp32c3_uart_s g_uart0_config =
{
.periph = ESP32C3_PERIPH_UART0,
.cpuint = -ENOMEM,
.id = 0,
.cpuint = -ENOMEM,
.irq = ESP32C3_IRQ_UART0,
.baud = CONFIG_UART0_BAUD,
.bits = CONFIG_UART0_BITS,
@ -75,13 +76,15 @@ static const struct esp32c3_uart_s g_console_config =
.rxsig = U0RXD_IN_IDX,
};
# elif defined(CONFIG_UART1_SERIAL_CONSOLE)
#endif /* CONFIG_ESP32C3_UART0 */
static const struct esp32c3_uart_s g_console_config =
#ifdef CONFIG_ESP32C3_UART1
struct esp32c3_uart_s g_uart1_config =
{
.periph = ESP32C3_PERIPH_UART1,
.cpuint = -ENOMEM,
.id = 1,
.cpuint = -ENOMEM,
.irq = ESP32C3_IRQ_UART1,
.baud = CONFIG_UART1_BAUD,
.bits = CONFIG_UART1_BITS,
@ -93,8 +96,9 @@ static const struct esp32c3_uart_s g_console_config =
.rxpin = CONFIG_ESP32C3_UART1_RXPIN,
.rxsig = U1RXD_IN_IDX,
};
#endif /* CONFIG_UART0_SERIAL_CONSOLE */
#endif /* HAVE_SERIAL_CONSOLE */
#endif /* CONFIG_ESP32C3_UART1 */
#endif /* HAVE_UART_DEVICE */
/****************************************************************************
* Public Functions
@ -267,19 +271,51 @@ uint32_t esp32c3_lowputc_get_sclk(const struct esp32c3_uart_s * priv)
void esp32c3_lowputc_baud(const struct esp32c3_uart_s * priv)
{
const int sclk_div = 1;
uint32_t sclk_freq = esp32c3_lowputc_get_sclk(priv);
uint32_t clk_div = ((sclk_freq) << 4) / priv->baud;
uint32_t int_part = clk_div >> 4;
uint32_t frag_part = clk_div & 0xf;
int sclk_div;
uint32_t sclk_freq;
uint32_t clk_div;
uint32_t int_part;
uint32_t frag_part;
/* The baud rate configuration register is divided into
* an integer part and a fractional part.
/* Get serial clock */
sclk_freq = esp32c3_lowputc_get_sclk(priv);
/* Calculate integral part of the frequency divider factor.
* For low baud rates, the sclk must be less than half.
* For high baud rates, the sclk must be the higher.
*/
sclk_div = DIV_UP(sclk_freq, MAX_UART_CLKDIV * priv->baud);
/* Calculate the clock divisor to achieve the baud rate.
* baud = f/clk_div
* f = sclk_freq/sclk_div
* clk_div = 16*int_part + frag_part
* 16*int_part + frag_part = 16*(sclk_freq/sclk_div)/baud
*/
clk_div = ((sclk_freq) << 4) / (priv->baud * sclk_div);
/* Get the integer part of it. */
int_part = clk_div >> 4;
/* Get the frag part of it. */
frag_part = clk_div & 0xf;
/* Set integer part of the clock divisor for baud rate. */
modifyreg32(UART_CLKDIV_REG(priv->id), UART_CLKDIV_M, int_part);
/* Set decimal part of the clock divisor for baud rate. */
modifyreg32(UART_CLKDIV_REG(priv->id), UART_CLKDIV_FRAG_M,
frag_part << UART_CLKDIV_FRAG_S);
(frag_part & UART_CLKDIV_FRAG_V) << UART_CLKDIV_FRAG_S);
/* Set the the integral part of the frequency divider factor. */
modifyreg32(UART_CLK_CONF_REG(priv->id), UART_SCLK_DIV_NUM_M,
(sclk_div - 1) << UART_SCLK_DIV_NUM_S);
}
@ -601,8 +637,8 @@ void esp32c3_lowputc_config_pins(const struct esp32c3_uart_s *priv)
{
/* Configure the pins */
esp32c3_configgpio(priv->txpin, OUTPUT_FUNCTION_1);
esp32c3_gpio_matrix_out(priv->txpin, priv->txsig, 0, 0);
esp32c3_configgpio(priv->txpin, OUTPUT_FUNCTION_1);
esp32c3_configgpio(priv->rxpin, INPUT_FUNCTION_1);
esp32c3_gpio_matrix_in(priv->rxpin, priv->rxsig, 0);
@ -646,13 +682,19 @@ void riscv_lowputc(char ch)
{
#ifdef HAVE_SERIAL_CONSOLE
# if defined(CONFIG_UART0_SERIAL_CONSOLE)
struct esp32c3_uart_s *priv = &g_uart0_config;
#elif defined (CONFIG_UART1_SERIAL_CONSOLE)
struct esp32c3_uart_s *priv = &g_uart1_config;
#endif
/* Wait until the TX FIFO has space to insert new char */
while (esp32c3_lowputc_is_tx_fifo_full(&g_console_config));
while (esp32c3_lowputc_is_tx_fifo_full(priv));
/* Then send the character */
esp32c3_lowputc_send_byte(&g_console_config, ch);
esp32c3_lowputc_send_byte(priv, ch);
#endif /* HAVE_CONSOLE */
}
@ -661,51 +703,25 @@ void riscv_lowputc(char ch)
* Name: esp32c3_lowsetup
*
* Description:
* This performs basic initialization of the UART used for the serial
* console. Its purpose is to get the console output available as soon
* as possible.
* This performs only the basic configuration for UART pins.
*
****************************************************************************/
void esp32c3_lowsetup(void)
{
/* Enable and configure the selected console device */
#ifndef CONFIG_SUPPRESS_UART_CONFIG
#if defined(HAVE_SERIAL_CONSOLE) && !defined(CONFIG_SUPPRESS_UART_CONFIG)
#ifdef CONFIG_ESP32C3_UART0
/* Initialize UART module */
esp32c3_lowputc_config_pins(&g_uart0_config);
/* Configure the UART Baud Rate */
#endif
esp32c3_lowputc_baud(&g_console_config);
#ifdef CONFIG_ESP32C3_UART1
/* Set a mode */
esp32c3_lowputc_config_pins(&g_uart1_config);
esp32c3_lowputc_normal_mode(&g_console_config);
#endif
/* Parity */
esp32c3_lowputc_parity(&g_console_config);
/* Data Frame size */
esp32c3_lowputc_data_length(&g_console_config);
/* Stop bit */
esp32c3_lowputc_stop_length(&g_console_config);
/* No Tx idle interval */
esp32c3_lowputc_set_tx_idle_time(&g_console_config, 0);
/* Set pins */
esp32c3_lowputc_config_pins(&g_console_config);
/* Enable cores */
esp32c3_lowputc_enable_sclk(&g_console_config);
#endif /* HAVE_SERIAL_CONSOLE && !CONFIG_SUPPRESS_UART_CONFIG */
#endif /* !CONFIG_SUPPRESS_UART_CONFIG */
}

View File

@ -81,6 +81,11 @@ enum uart_stop_length
#define UART_TX_FIFO_SIZE 128
#define UART_RX_FIFO_SIZE 128
/* Maximum serial clock divisor for integer part */
#define MAX_UART_CLKDIV (BIT(12) - 1)
#define DIV_UP(a, b) (((a) + (b) - 1) / (b))
/* Struct used to store uart driver information and to
* manipulate uart driver
*/
@ -102,6 +107,9 @@ struct esp32c3_uart_s
uint8_t rxsig; /* RX signal */
};
extern struct esp32c3_uart_s g_uart0_config;
extern struct esp32c3_uart_s g_uart1_config;
/****************************************************************************
* Public Function Prototypes
****************************************************************************/

View File

@ -155,23 +155,6 @@ static struct uart_ops_s g_uart_ops =
static char g_uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
static char g_uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
static struct esp32c3_uart_s g_uart0_config =
{
.periph = ESP32C3_PERIPH_UART0,
.id = 0,
.cpuint = -ENOMEM,
.irq = ESP32C3_IRQ_UART0,
.baud = CONFIG_UART0_BAUD,
.bits = CONFIG_UART0_BITS,
.parity = CONFIG_UART0_PARITY,
.stop_b2 = CONFIG_UART0_2STOP,
.int_pri = ESP32C3_INT_PRIO_DEF,
.txpin = CONFIG_ESP32C3_UART0_TXPIN,
.txsig = U0TXD_OUT_IDX,
.rxpin = CONFIG_ESP32C3_UART0_RXPIN,
.rxsig = U0RXD_IN_IDX,
};
/* Fill only the requested fields */
static uart_dev_t g_uart0_dev =
@ -205,23 +188,6 @@ static uart_dev_t g_uart0_dev =
static char g_uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
static char g_uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
static struct esp32c3_uart_s g_uart1_config =
{
.periph = ESP32C3_PERIPH_UART1,
.id = 1,
.cpuint = -ENOMEM,
.irq = ESP32C3_IRQ_UART1,
.baud = CONFIG_UART1_BAUD,
.bits = CONFIG_UART1_BITS,
.parity = CONFIG_UART1_PARITY,
.stop_b2 = CONFIG_UART1_2STOP,
.int_pri = ESP32C3_INT_PRIO_DEF,
.txpin = CONFIG_ESP32C3_UART1_TXPIN,
.txsig = U1TXD_OUT_IDX,
.rxpin = CONFIG_ESP32C3_UART1_RXPIN,
.rxsig = U1RXD_IN_IDX,
};
/* Fill only the requested fields */
static uart_dev_t g_uart1_dev =
@ -319,6 +285,33 @@ static int esp32c3_setup(struct uart_dev_s *dev)
/* Initialize UART module */
/* Discard corrupt RX data and
* disable UART memory clock gate enable signal.
*/
modifyreg32(UART_CONF0_REG(priv->id), UART_ERR_WR_MASK_M |
UART_MEM_CLK_EN_M, UART_ERR_WR_MASK_M);
/* Define 0 as the threshold that means TX FIFO buffer is empty. */
modifyreg32(UART_CONF1_REG(priv->id), UART_TXFIFO_EMPTY_THRHD_M, 0);
/* Define a threshold to trigger an RX FIFO FULL interrupt.
* Define just one byte to read data immediately.
*/
modifyreg32(UART_CONF1_REG(priv->id), UART_RXFIFO_FULL_THRHD_M,
1 << UART_RXFIFO_FULL_THRHD_S);
/* Define the maximum FIFO size for RX and TX FIFO.
* That means, 1 block = 128 bytes.
* As a consequence, software serial FIFO can unload the bytes and
* not wait too much on polling activity.
*/
modifyreg32(UART_MEM_CONF_REG(priv->id), UART_TX_SIZE_M | UART_RX_SIZE_M,
(1 << UART_TX_SIZE_S) | (1 << UART_RX_SIZE_S));
/* Configure the UART Baud Rate */
esp32c3_lowputc_baud(priv);
@ -343,14 +336,15 @@ static int esp32c3_setup(struct uart_dev_s *dev)
esp32c3_lowputc_set_tx_idle_time(priv, 0);
/* Set pins */
esp32c3_lowputc_config_pins(priv);
/* Enable cores */
esp32c3_lowputc_enable_sclk(priv);
/* Clear FIFOs */
esp32c3_lowputc_rst_txfifo(priv);
esp32c3_lowputc_rst_rxfifo(priv);
return OK;
}
@ -371,18 +365,9 @@ static void esp32c3_shutdown(struct uart_dev_s *dev)
{
struct esp32c3_uart_s *priv = dev->priv;
/* Clear FIFOs */
esp32c3_lowputc_rst_txfifo(priv);
esp32c3_lowputc_rst_rxfifo(priv);
/* Disable ints */
esp32c3_lowputc_disable_all_uart_int(priv, NULL);
/* Back pins to normal */
esp32c3_lowputc_restore_pins(priv);
}
/****************************************************************************
@ -486,6 +471,7 @@ static void esp32c3_txint(struct uart_dev_s *dev, bool enable)
/* Set to receive an interrupt when the TX holding register register
* is empty
*/
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
modifyreg32(UART_INT_ENA_REG(priv->id), ints_mask, ints_mask);
#endif
@ -518,8 +504,9 @@ static void esp32c3_rxint(struct uart_dev_s *dev, bool enable)
if (enable)
{
/* Receive an interrupt when there is anything in the Rx data register
* (or an Rx timeout occurs).
/* Receive an interrupt when there is anything in the RX data register
* (or an RX timeout occurs).
* NOTE: RX timeout feature needs to be enabled.
*/
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
modifyreg32(UART_CONF1_REG(priv->id), UART_RX_TOUT_EN_M,
@ -883,15 +870,27 @@ static int esp32c3_ioctl(struct file *filep, int cmd, unsigned long arg)
*
****************************************************************************/
/* TODO */
void riscv_earlyserialinit(void)
{
/* I've been looking at others chips/arches and I noticed
* that <chips>_lowsetup performs almost the same of this func and it's
* called earlier than this one in <chip>_start
* So, I am not sure what to do here
/* NOTE: All GPIO configuration for the UARTs was performed in
* esp32c3_lowsetup
*/
/* Disable all UARTS interrupts */
esp32c3_lowputc_disable_all_uart_int(TTYS0_DEV.priv, NULL);
#ifdef TTYS1_DEV
esp32c3_lowputc_disable_all_uart_int(TTYS1_DEV.priv, NULL);
#endif
/* Configure console in early step.
* Setup for other serials will be perfomed when the serial driver is
* open.
*/
#ifdef HAVE_SERIAL_CONSOLE
esp32c3_setup(&CONSOLE_DEV);
#endif
}
#endif /* USE_EARLYSERIALINIT */
@ -956,7 +955,7 @@ int up_putc(int ch)
* Name: riscv_earlyserialinit, riscv_serialinit, and up_putc
*
* Description:
* stubs that may be needed. These stubs will be used if all UARTs are
* Stubs that may be needed. These stubs will be used if all UARTs are
* disabled. In that case, the logic in common/up_initialize() is not
* smart enough to know that there are not UARTs and will still expect
* these interfaces to be provided.
@ -979,12 +978,6 @@ int up_putc(int ch)
#endif /* HAVE_UART_DEVICE */
#else /* USE_SERIALDRIVER */
/* Common initialization logic will not not know that the all of the UARTs
* have been disabled. So, as a result, we may still have to provide
* stub implementations of riscv_earlyserialinit(), riscv_serialinit(), and
* up_putc().
*/
/****************************************************************************
* Name: up_putc
*

View File

@ -75,6 +75,12 @@ void __esp32c3_start(void)
esp32c3_lowsetup();
#ifdef USE_EARLYSERIALINIT
/* Perform early serial initialization */
riscv_earlyserialinit();
#endif
showprogress('A');
/* Clear .bss. We'll do this inline (vs. calling memset) just to be