Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/common/esp32/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include $(RIOTCPU)/esp32/Makefile.features
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_gpio_irq
FEATURES_PROVIDED += periph_uart
FEATURES_PROVIDED += periph_uart_modecfg

# other features provided by all boards
FEATURES_PROVIDED += esp_spiffs
Expand Down
117 changes: 108 additions & 9 deletions cpu/esp32/periph/uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,15 @@ struct uart_hw_t {
uart_dev_t* regs; /* pointer to register data struct of the UART device */
uint8_t pin_txd; /* TxD pin */
uint8_t pin_rxd; /* RxD pin */
bool used; /* indicates whether UART is used */
uint32_t baudrate; /* used baudrate */
uart_data_bits_t data; /* used data bits */
uart_stop_bits_t stop; /* used stop bits */
uart_parity_t parity; /* used parity bits */
uart_isr_ctx_t isr_ctx; /* callback functions */
uint8_t signal_txd; /* TxD signal from the controller */
uint8_t signal_rxd; /* RxD signal to the controller */
uint32_t baudrate; /* used baudrate */
bool used; /* indicates whether UART is used */
uint8_t int_src; /* peripheral interrupt source used by the UART device */
uart_isr_ctx_t isr_ctx; /* callback functions */
};

/* hardware ressources */
Expand All @@ -66,31 +69,40 @@ static struct uart_hw_t _uarts[] = {
.regs = &UART0,
.pin_txd = GPIO1,
.pin_rxd = GPIO3,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.signal_txd = U0TXD_OUT_IDX,
.signal_rxd = U0RXD_IN_IDX,
.baudrate = STDIO_UART_BAUDRATE,
.used = false,
.int_src = ETS_UART0_INTR_SOURCE
},
#if defined(UART1_TXD) && defined(UART1_RXD)
{ .regs = &UART1,
.pin_txd = UART1_TXD,
.pin_rxd = UART1_RXD,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.signal_txd = U1TXD_OUT_IDX,
.signal_rxd = U1RXD_IN_IDX,
.baudrate = STDIO_UART_BAUDRATE,
.used = false,
.int_src = ETS_UART1_INTR_SOURCE
},
#endif
#if defined(UART2_TXD) && defined(UART2_RXD)
{ .regs = &UART2,
.pin_txd = UART2_TXD,
.pin_rxd = UART2_RXD,
.used = false,
.baudrate = STDIO_UART_BAUDRATE,
.data = UART_DATA_BITS_8,
.stop = UART_STOP_BITS_1,
.parity = UART_PARITY_NONE,
.signal_txd = U2TXD_OUT_IDX,
.signal_rxd = U2RXD_IN_IDX,
.baudrate = STDIO_UART_BAUDRATE,
.used = false,
.int_src = ETS_UART2_INTR_SOURCE
}
#endif
Expand All @@ -101,6 +113,8 @@ extern void uart_div_modify(uint8_t uart_no, uint32_t div);

/* forward declaration of internal functions */
static int _uart_set_baudrate(uart_t uart, uint32_t baudrate);
static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
uart_parity_t parity, uart_stop_bits_t stop_bits);
static uint8_t IRAM _uart_rx_one_char (uart_t uart);
static void _uart_tx_one_char(uart_t uart, uint8_t data);
static void _uart_intr_enable (uart_t uart);
Expand Down Expand Up @@ -154,6 +168,14 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
return UART_OK;
}

#if MODULE_PERIPH_UART_MODECFG
int uart_mode(uart_t uart, uart_data_bits_t data_bits, uart_parity_t parity,
uart_stop_bits_t stop_bits)
{
return _uart_set_mode(uart, data_bits, parity, stop_bits);
}
#endif

void uart_write(uart_t uart, const uint8_t *data, size_t len)
{
CHECK_PARAM (uart < UART_NUMOF);
Expand Down Expand Up @@ -296,6 +318,12 @@ static void _uart_config (uart_t uart)
return;
}

/* set number of data bits, stop bits and parity mode */
if (_uart_set_mode(uart, _uarts[uart].data, _uarts[uart].stop,
_uarts[uart].parity) != UART_OK) {
return;
}

/* reset the FIFOs */
_uarts[uart].regs->conf0.rxfifo_rst = 1;
_uarts[uart].regs->conf0.rxfifo_rst = 0;
Expand Down Expand Up @@ -342,3 +370,74 @@ static int _uart_set_baudrate(uart_t uart, uint32_t baudrate)
critical_exit();
return UART_OK;
}

static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits,
uart_parity_t parity, uart_stop_bits_t stop_bits)
{
DEBUG("%s uart=%d, data_bits=%d parity=%d stop_bits=%d\n", __func__,
uart, data_bits, parity, stop_bits);

CHECK_PARAM_RET (uart < UART_NUMOF, UART_NODEV);

critical_enter();

/* set number of data bits */
switch (data_bits) {
case UART_DATA_BITS_5: _uarts[uart].regs->conf0.bit_num = 0; break;
case UART_DATA_BITS_6: _uarts[uart].regs->conf0.bit_num = 1; break;
case UART_DATA_BITS_7: _uarts[uart].regs->conf0.bit_num = 2; break;
case UART_DATA_BITS_8: _uarts[uart].regs->conf0.bit_num = 3; break;
default: LOG_TAG_ERROR("uart", "invalid number of data bits\n");
critical_exit();
return UART_NOMODE;
}
/* store changed number of data bits in configuration */
_uarts[uart].data = data_bits;

/* set number of stop bits */
#ifdef MCU_ESP32
/* workaround for hardware bug when stop bits are set to 2-bit mode. */
switch (stop_bits) {
case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1;
_uarts[uart].regs->rs485_conf.dl1_en = 0;
break;
case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be 2? Either that or say not implemented.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it is a known hardware bug. _uarts[uart].regs->conf0.stop_bit_num has to be set to 1 if there is any stop bit. With _uarts[uart].regs->rs485_conf.dl1_en it is decided whether there are 1 or 2 stop bits.

_uarts[uart].regs->rs485_conf.dl1_en = 1;
break;
default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n");
critical_exit();
return UART_NOMODE;
}
#else
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the ifdef needed here since they are all MCU_ESP32 that use this file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at the moment. But, the UART source code is already compatible with that of the complete ESP8266 reimplemenation in PR #11108 (https://github.com/RIOT-OS/RIOT/blob/2f008018200c180a96f6457e7d0ec655b2209510/cpu/esp8266/periph/uart.c). To make planned deduplication easier, I'm already adapting the ESP32 code if I make changes.

switch (stop_bits) {
case UART_STOP_BITS_1: _uarts[uart].regs->conf0.stop_bit_num = 1; break;
case UART_STOP_BITS_2: _uarts[uart].regs->conf0.stop_bit_num = 3; break;
default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n");
critical_exit();
return UART_NOMODE;
}
#endif

/* store changed number of stop bits in configuration */
_uarts[uart].stop = stop_bits;

/* set parity mode */
switch (parity) {
case UART_PARITY_NONE: _uarts[uart].regs->conf0.parity_en = 0;
break;
case UART_PARITY_EVEN: _uarts[uart].regs->conf0.parity = 0;
_uarts[uart].regs->conf0.parity_en = 1;
break;
case UART_PARITY_ODD: _uarts[uart].regs->conf0.parity = 1;
_uarts[uart].regs->conf0.parity_en = 1;
break;
default: LOG_TAG_ERROR("uart", "invalid or unsupported parity mode\n");
critical_exit();
return UART_NOMODE;
}
/* store changed parity in configuration */
_uarts[uart].parity = parity;

critical_exit();
return UART_OK;
}