xtensa/esp32: Replace serialout/in and fixes the fifo counter issue

This commit is contained in:
Sara Souza
2021-04-16 18:35:29 -03:00
committed by Xiang Xiao
parent f3a6d80c95
commit afd6b26232
3 changed files with 196 additions and 57 deletions
+166 -56
View File
@@ -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));
esp32_serialout(priv, UART_INT_CLR_OFFSET, 0xffffffff);
putreg32(UINT32_MAX, UART_INT_CLR_REG(priv->config->id));
/* 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,14 +1257,29 @@ 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);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* 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
*
@@ -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
+21 -1
View File
@@ -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)