You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/05/05 08:30:14 UTC
[incubator-nuttx] 01/04: xtensa/esp32: Replace serialout/in and
fixes the fifo counter issue
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit afd6b262321cf6f97dac3f37a8b066c905a35d86
Author: Sara Souza <sa...@espressif.com>
AuthorDate: Fri Apr 16 18:35:29 2021 -0300
xtensa/esp32: Replace serialout/in and fixes the fifo counter issue
---
arch/xtensa/src/esp32/esp32_serial.c | 222 +++++++++++++++++++++-------
arch/xtensa/src/esp32/hardware/esp32_soc.h | 9 ++
arch/xtensa/src/esp32/hardware/esp32_uart.h | 22 ++-
3 files changed, 196 insertions(+), 57 deletions(-)
diff --git a/arch/xtensa/src/esp32/esp32_serial.c b/arch/xtensa/src/esp32/esp32_serial.c
index 623c19a..b211074 100644
--- a/arch/xtensa/src/esp32/esp32_serial.c
+++ b/arch/xtensa/src/esp32/esp32_serial.c
@@ -130,7 +130,7 @@
struct esp32_config_s
{
- const uint32_t uartbase; /* Base address of UART registers */
+ const uint8_t id; /* UART id */
uint8_t periph; /* UART peripheral ID */
uint8_t irq; /* IRQ number assigned to the peripheral */
uint8_t txpin; /* Tx pin number (0-39) */
@@ -183,6 +183,10 @@ static bool esp32_txempty(struct uart_dev_s *dev);
* Private Data
****************************************************************************/
+#define UART_TX_FIFO_SIZE 128
+#define UART_RX_FIFO_FULL_THRHD 112
+#define UART_RX_TOUT_THRHD_VALUE 0x02
+
static const struct uart_ops_s g_uart_ops =
{
.setup = esp32_setup,
@@ -222,7 +226,7 @@ static char g_uart2txbuffer[CONFIG_UART2_TXBUFSIZE];
#ifdef CONFIG_ESP32_UART0
static const struct esp32_config_s g_uart0config =
{
- .uartbase = DR_REG_UART_BASE,
+ .id = 0,
.periph = ESP32_PERIPH_UART,
.irq = ESP32_IRQ_UART,
.txpin = CONFIG_ESP32_UART0_TXPIN,
@@ -268,7 +272,7 @@ static uart_dev_t g_uart0port =
#ifdef CONFIG_ESP32_UART1
static const struct esp32_config_s g_uart1config =
{
- .uartbase = DR_REG_UART1_BASE,
+ .id = 1,
.periph = ESP32_PERIPH_UART1,
.irq = ESP32_IRQ_UART1,
.txpin = CONFIG_ESP32_UART1_TXPIN,
@@ -314,7 +318,7 @@ static uart_dev_t g_uart1port =
#ifdef CONFIG_ESP32_UART2
static const struct esp32_config_s g_uart2config =
{
- .uartbase = DR_REG_UART2_BASE,
+ .id = 2,
.periph = ESP32_PERIPH_UART2,
.irq = ESP32_IRQ_UART2,
.txpin = CONFIG_ESP32_UART2_TXPIN,
@@ -360,22 +364,106 @@ static uart_dev_t g_uart2port =
****************************************************************************/
/****************************************************************************
- * Name: esp32_serialin
+ * Name: esp32_reset_rx_fifo
+ *
+ * Description:
+ * Resets the RX FIFO.
+ * NOTE: We can not use rxfifo_rst to reset the hardware RX FIFO.
+ *
+ * Parameters:
+ * priv - Pointer to the serial driver struct.
+ *
****************************************************************************/
-static inline uint32_t esp32_serialin(struct esp32_dev_s *priv, int offset)
+static void esp32_reset_rx_fifo(struct esp32_dev_s *priv)
{
- return getreg32(priv->config->uartbase + offset);
+ uint32_t rx_status_reg = getreg32(UART_STATUS_REG(priv->config->id));
+ uint32_t fifo_cnt = REG_MASK(rx_status_reg, UART_RXFIFO_CNT);
+ uint32_t mem_rx_status_reg = getreg32(UART_MEM_RX_STATUS_REG
+ (priv->config->id));
+ uint32_t rd_address = REG_MASK(mem_rx_status_reg, UART_RD_ADDRESS);
+ uint32_t wr_address = REG_MASK(mem_rx_status_reg, UART_WR_ADDRESS);
+
+ while ((fifo_cnt != 0) || (rd_address != wr_address))
+ {
+ getreg32(DR_UART_FIFO_REG(priv->config->id));
+
+ rx_status_reg = getreg32(UART_STATUS_REG(priv->config->id));
+ fifo_cnt = REG_MASK(rx_status_reg, UART_RXFIFO_CNT);
+ mem_rx_status_reg = getreg32(UART_MEM_RX_STATUS_REG(priv->config->id));
+ rd_address = REG_MASK(mem_rx_status_reg, UART_RD_ADDRESS);
+ wr_address = REG_MASK(mem_rx_status_reg, UART_WR_ADDRESS);
+ }
}
/****************************************************************************
- * Name: esp32_serialout
+ * Name: esp32_reset_tx_fifo
+ *
+ * Description:
+ * Resets the TX FIFO.
+ *
+ * Parameters:
+ * priv - Pointer to the serial driver struct.
+ *
****************************************************************************/
-static inline void esp32_serialout(struct esp32_dev_s *priv, int offset,
- uint32_t value)
+static void esp32_reset_tx_fifo(struct esp32_dev_s *priv)
{
- putreg32(value, priv->config->uartbase + offset);
+ modifyreg32(UART_CONF0_REG(priv->config->id), 0, UART_TXFIFO_RST_M);
+ modifyreg32(UART_CONF0_REG(priv->config->id), UART_TXFIFO_RST_M, 0);
+}
+
+/****************************************************************************
+ * Name: esp32_get_rx_fifo_len
+ *
+ * Description:
+ * Get the real value on rx fixo.
+ * RX_FIFO_CNT shouldn't be used alone accordingly to:
+ * https://www.espressif.com/sites/default/files/documentation/eco_
+ * and_workarounds_for_bugs_in_esp32_en.pdf.
+ * So, some arithmetic with the read and write RX FIFO pointers are
+ * necessary.
+ *
+ * Parameters:
+ * priv - Pointer to the serial driver struct.
+ *
+ * Return:
+ * The number of bytes in RX fifo.
+ *
+ ****************************************************************************/
+
+static uint32_t esp32_get_rx_fifo_len(struct esp32_dev_s *priv)
+{
+ uint32_t rd_address;
+ uint32_t wr_address;
+ uint32_t fifo_cnt;
+ uint32_t mem_rx_status_reg;
+ uint32_t rx_status_reg;
+ uint32_t len;
+
+ mem_rx_status_reg = getreg32(UART_MEM_RX_STATUS_REG(priv->config->id));
+ rd_address = ((mem_rx_status_reg & UART_RD_ADDRESS_M)
+ >> UART_RD_ADDRESS_S);
+ wr_address = ((mem_rx_status_reg & UART_WR_ADDRESS_M)
+ >> UART_WR_ADDRESS_S);
+ rx_status_reg = getreg32(UART_STATUS_REG(priv->config->id));
+ fifo_cnt = ((rx_status_reg & UART_RXFIFO_CNT_M)
+ >> UART_RXFIFO_CNT_S);
+
+ if (wr_address > rd_address)
+ {
+ len = wr_address - rd_address;
+ }
+ else if (wr_address < rd_address)
+ {
+ len = (wr_address + 128) - rd_address;
+ }
+ else
+ {
+ len = fifo_cnt > 0 ? 128 : 0;
+ }
+
+ return len;
}
/****************************************************************************
@@ -389,7 +477,7 @@ static inline void esp32_restoreuartint(struct esp32_dev_s *priv,
* (assuming all interrupts disabled)
*/
- esp32_serialout(priv, UART_INT_ENA_OFFSET, intena);
+ putreg32(intena, UART_INT_ENA_REG(priv->config->id));
}
/****************************************************************************
@@ -408,12 +496,12 @@ static void esp32_disableallints(struct esp32_dev_s *priv, uint32_t *intena)
{
/* Return the current interrupt mask */
- *intena = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+ *intena = getreg32(UART_INT_ENA_REG(priv->config->id));
}
/* Disable all interrupts */
- esp32_serialout(priv, UART_INT_ENA_OFFSET, 0);
+ putreg32(0, UART_INT_ENA_REG(priv->config->id));
leave_critical_section(flags);
}
@@ -504,7 +592,7 @@ static int esp32_setup(struct uart_dev_s *dev)
regval = (clkdiv >> 4) << UART_CLKDIV_S;
regval |= (clkdiv & 15) << UART_CLKDIV_FRAG_S;
- esp32_serialout(priv, UART_CLKDIV_OFFSET, regval);
+ putreg32(regval, UART_CLKDIV_REG(priv->config->id));
/* Configure UART pins
*
@@ -530,17 +618,22 @@ static int esp32_setup(struct uart_dev_s *dev)
regval = UART_RXFIFO_FULL_INT_ENA | UART_FRM_ERR_INT_ENA |
UART_RXFIFO_TOUT_INT_ENA;
- esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+ putreg32(regval, UART_INT_ENA_REG(priv->config->id));
+
+ putreg32(UINT32_MAX, UART_INT_CLR_REG(priv->config->id));
- esp32_serialout(priv, UART_INT_CLR_OFFSET, 0xffffffff);
+ /* Reset the RX and TX FIFO */
+
+ esp32_reset_rx_fifo(priv);
+ esp32_reset_tx_fifo(priv);
/* Configure and enable the UART */
- esp32_serialout(priv, UART_CONF0_OFFSET, conf0);
- regval = (112 << UART_RXFIFO_FULL_THRHD_S) |
- (0x02 << UART_RX_TOUT_THRHD_S) |
- UART_RX_TOUT_EN;
- esp32_serialout(priv, UART_CONF1_OFFSET, regval);
+ putreg32(conf0, UART_CONF0_REG(priv->config->id));
+ regval = (UART_RX_FIFO_FULL_THRHD << UART_RXFIFO_FULL_THRHD_S) |
+ (UART_RX_TOUT_THRHD_VALUE << UART_RX_TOUT_THRHD_S) |
+ UART_RX_TOUT_EN;
+ putreg32(regval, UART_CONF1_REG(priv->config->id));
#endif
return OK;
@@ -569,7 +662,7 @@ static void esp32_shutdown(struct uart_dev_s *dev)
do
{
- status = esp32_serialin(priv, UART_STATUS_OFFSET);
+ status = getreg32(UART_STATUS_REG(priv->config->id));
}
while ((status & UART_TXFIFO_CNT_M) != 0);
@@ -598,11 +691,11 @@ static void esp32_shutdown(struct uart_dev_s *dev)
/* Unconfigure and disable the UART */
- esp32_serialout(priv, UART_CONF0_OFFSET, 0);
- esp32_serialout(priv, UART_CONF1_OFFSET, 0);
+ putreg32(0, UART_CONF0_REG(priv->config->id));
+ putreg32(0, UART_CONF1_REG(priv->config->id));
- esp32_serialout(priv, UART_INT_ENA_OFFSET, 0);
- esp32_serialout(priv, UART_INT_CLR_OFFSET, 0xffffffff);
+ putreg32(0, UART_INT_ENA_REG(priv->config->id));
+ putreg32(UINT32_MAX, UART_INT_CLR_REG(priv->config->id));
}
/****************************************************************************
@@ -734,16 +827,16 @@ static int esp32_interrupt(int cpuint, void *context, FAR void *arg)
for (passes = 0; passes < 256 && handled; passes++)
{
handled = false;
- priv->status = esp32_serialin(priv, UART_INT_RAW_OFFSET);
- status = esp32_serialin(priv, UART_STATUS_OFFSET);
- enabled = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+ priv->status = getreg32(UART_INT_RAW_REG(priv->config->id));
+ status = getreg32(UART_STATUS_REG(priv->config->id));
+ enabled = getreg32(UART_INT_ENA_REG(priv->config->id));
/* Clear pending interrupts */
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);
- esp32_serialout(priv, UART_INT_CLR_OFFSET, regval);
+ putreg32(regval, UART_INT_CLR_REG(priv->config->id));
/* 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
@@ -755,7 +848,7 @@ static int esp32_interrupt(int cpuint, void *context, FAR void *arg)
{
/* Is there any data waiting in the Rx FIFO? */
- nfifo = (status & UART_RXFIFO_CNT_M) >> UART_RXFIFO_CNT_S;
+ nfifo = esp32_get_rx_fifo_len(priv);
if (nfifo > 0)
{
/* Received data in the RXFIFO! ... Process incoming bytes */
@@ -1000,6 +1093,7 @@ static int esp32_ioctl(struct file *filep, int cmd, unsigned long arg)
static int esp32_receive(struct uart_dev_s *dev, unsigned int *status)
{
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
+ uint32_t rx_fifo;
/* Return the error information in the saved status */
@@ -1008,8 +1102,9 @@ static int esp32_receive(struct uart_dev_s *dev, unsigned int *status)
/* Then return the actual received byte */
- return (int)(esp32_serialin(priv, UART_FIFO_OFFSET) &
- UART_RXFIFO_RD_BYTE_M);
+ rx_fifo = getreg32(DR_UART_FIFO_REG(priv->config->id));
+
+ return (int)(rx_fifo & UART_RXFIFO_RD_BYTE_M);
}
/****************************************************************************
@@ -1035,20 +1130,20 @@ static void esp32_rxint(struct uart_dev_s *dev, bool enable)
*/
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
- regval = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+ regval = getreg32(UART_INT_ENA_REG(priv->config->id));
regval |= (UART_RXFIFO_FULL_INT_ENA | UART_FRM_ERR_INT_ENA |
UART_RXFIFO_TOUT_INT_ENA);
- esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+ putreg32(regval, UART_INT_ENA_REG(priv->config->id));
#endif
}
else
{
/* Disable the RX interrupts */
- regval = esp32_serialin(priv, UART_INT_ENA_OFFSET);
+ regval = getreg32(UART_INT_ENA_REG(priv->config->id));
regval &= ~(UART_RXFIFO_FULL_INT_ENA | UART_FRM_ERR_INT_ENA |
UART_RXFIFO_TOUT_INT_ENA);
- esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+ putreg32(regval, UART_INT_ENA_REG(priv->config->id));
}
leave_critical_section(flags);
@@ -1065,9 +1160,7 @@ static void esp32_rxint(struct uart_dev_s *dev, bool enable)
static bool esp32_rxavailable(struct uart_dev_s *dev)
{
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
-
- return ((esp32_serialin(priv, UART_STATUS_OFFSET)
- & UART_RXFIFO_CNT_M) > 0);
+ return esp32_get_rx_fifo_len(priv) > 0;
}
/****************************************************************************
@@ -1082,7 +1175,7 @@ static void esp32_send(struct uart_dev_s *dev, int ch)
{
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
- esp32_serialout(priv, UART_FIFO_OFFSET, (uint32_t)ch);
+ putreg32((uint32_t)ch, AHB_UART_FIFO_REG(priv->config->id));
}
/****************************************************************************
@@ -1097,20 +1190,16 @@ static void esp32_txint(struct uart_dev_s *dev, bool enable)
{
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
irqstate_t flags;
- int regval;
flags = enter_critical_section();
if (enable)
{
- /* Set to receive an interrupt when the TX holding register register
- * is empty
- */
+ /* Set to receive an interrupt when the TX holding register is empty */
#ifndef CONFIG_SUPPRESS_SERIAL_INTS
- regval = esp32_serialin(priv, UART_INT_ENA_OFFSET);
- regval |= (UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA);
- esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+ modifyreg32(UART_INT_ENA_REG(priv->config->id),
+ 0, (UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA));
/* Fake a TX interrupt here by just calling uart_xmitchars() with
* interrupts disabled (note this may recurse).
@@ -1123,9 +1212,8 @@ static void esp32_txint(struct uart_dev_s *dev, bool enable)
{
/* Disable the TX interrupt */
- regval = esp32_serialin(priv, UART_INT_ENA_OFFSET);
- regval &= ~(UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA);
- esp32_serialout(priv, UART_INT_ENA_OFFSET, regval);
+ modifyreg32(UART_INT_ENA_REG(priv->config->id),
+ (UART_TX_DONE_INT_ENA | UART_TXFIFO_EMPTY_INT_ENA), 0);
}
leave_critical_section(flags);
@@ -1144,10 +1232,17 @@ static bool esp32_txready(struct uart_dev_s *dev)
uint32_t txcnt;
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
- txcnt = (esp32_serialin(priv, UART_STATUS_OFFSET) >> UART_TXFIFO_CNT_S) &
+ txcnt = (getreg32(UART_STATUS_REG(priv->config->id)) >> UART_TXFIFO_CNT_S) &
UART_TXFIFO_CNT_V;
- return txcnt < 0x7f;
+ if (txcnt < (UART_TX_FIFO_SIZE -1))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
/****************************************************************************
@@ -1162,8 +1257,8 @@ static bool esp32_txempty(struct uart_dev_s *dev)
{
struct esp32_dev_s *priv = (struct esp32_dev_s *)dev->priv;
- return ((esp32_serialin(priv, UART_STATUS_OFFSET) & UART_TXFIFO_CNT_M)
- == 0);
+ return ((getreg32(UART_STATUS_REG(priv->config->id))
+ & UART_TXFIFO_CNT_M) == 0);
}
/****************************************************************************
@@ -1171,6 +1266,21 @@ static bool esp32_txempty(struct uart_dev_s *dev)
****************************************************************************/
/****************************************************************************
+ * Name: esp32_lowsetup
+ *
+ * Description:
+ * Performs the low level UART initialization early in debug so that the
+ * serial console will be available during bootup. This must be called
+ * before up_serialinit.
+ *
+ ****************************************************************************/
+
+void esp32_lowsetup(void)
+{
+
+}
+
+/****************************************************************************
* Name: xtensa_early_serial_initialize
*
* Description:
diff --git a/arch/xtensa/src/esp32/hardware/esp32_soc.h b/arch/xtensa/src/esp32/hardware/esp32_soc.h
index f208741..2d2b037 100644
--- a/arch/xtensa/src/esp32/hardware/esp32_soc.h
+++ b/arch/xtensa/src/esp32/hardware/esp32_soc.h
@@ -244,6 +244,15 @@
#define DR_REG_PWM3_BASE 0x3ff70000
#define PERIPHS_SPI_ENCRYPT_BASEADDR DR_REG_SPI_ENCRYPT_BASE
+/* Some AHB addresses can be used instead of DPORT addresses
+ * as a workaround for some HW bugs.
+ * This workaround is detailed at
+ * https://www.espressif.com/sites/default/files/documentation/
+ * eco_and_workarounds_for_bugs_in_esp32_en.pdf
+ */
+
+#define AHB_REG_UART_BASE 0x60000000
+
/* Overall memory map */
#define SOC_DROM_LOW 0x3f400000
diff --git a/arch/xtensa/src/esp32/hardware/esp32_uart.h b/arch/xtensa/src/esp32/hardware/esp32_uart.h
index 73cfd87..cba15cb 100644
--- a/arch/xtensa/src/esp32/hardware/esp32_uart.h
+++ b/arch/xtensa/src/esp32/hardware/esp32_uart.h
@@ -32,9 +32,11 @@
****************************************************************************/
#define REG_UART_BASE(i) (DR_REG_UART_BASE + (i) * 0x10000 + (i > 1 ? 0xe000 : 0))
+#define AHB_FIFO_BASE(i) (AHB_REG_UART_BASE + (i) * 0x10000 + (i > 1 ? 0xe000 : 0))
#define UART_FIFO_OFFSET 0x00
-#define UART_FIFO_REG(i) (REG_UART_BASE(i) + UART_FIFO_OFFSET)
+#define AHB_UART_FIFO_REG(i) (AHB_FIFO_BASE(i) + UART_FIFO_OFFSET)
+#define DR_UART_FIFO_REG(i) (REG_UART_BASE(i) + UART_FIFO_OFFSET)
/* UART_RXFIFO_RD_BYTE : RO ;bitpos:[7:0] ;default: 8'b0 ; */
@@ -1798,6 +1800,24 @@
#define UART_MEM_RX_STATUS_V 0xFFFFFF
#define UART_MEM_RX_STATUS_S 0
+/* UART_RD_ADDRESS : bitpos:[12:2] */
+
+/* Description: Read address of the UART RX FIFO. (a pointer) */
+
+#define UART_RD_ADDRESS 0x000007FF
+#define UART_RD_ADDRESS_M ((UART_RD_ADDRESS_V) << (UART_RD_ADDRESS_S))
+#define UART_RD_ADDRESS_V 0x7FF
+#define UART_RD_ADDRESS_S 2
+
+/* UART_WR_ADDRESS : bitpos:[23:13] */
+
+/* Description: Write address of the UART RX FIFO. (a pointer) */
+
+#define UART_WR_ADDRESS 0x000007FF
+#define UART_WR_ADDRESS_M ((UART_WR_ADDRESS_V) << (UART_WR_ADDRESS_S))
+#define UART_WR_ADDRESS_V 0x7FF
+#define UART_WR_ADDRESS_S 13
+
#define UART_MEM_CNT_STATUS_OFFSET 0x64
#define UART_MEM_CNT_STATUS_REG(i) (REG_UART_BASE(i) + UART_MEM_CNT_STATUS_OFFSET)