diff --git a/cpu/esp32/include/periph_cpu.h b/cpu/esp32/include/periph_cpu.h index 3634d10c4c..13aab8f928 100644 --- a/cpu/esp32/include/periph_cpu.h +++ b/cpu/esp32/include/periph_cpu.h @@ -1014,6 +1014,7 @@ typedef enum { UART_PARITY_SPACE = UART_MODE_UNSUPPORTED | 1, } uart_parity_t; +#define UART_PARITY_DISABLE UART_PARITY_NONE #define HAVE_UART_PARITY_T #endif /* !DOXYGEN */ diff --git a/cpu/esp_common/periph/uart.c b/cpu/esp_common/periph/uart.c index e8087bb446..6583a1b3d7 100644 --- a/cpu/esp_common/periph/uart.c +++ b/cpu/esp_common/periph/uart.c @@ -47,7 +47,7 @@ #if defined(CPU_ESP8266) #include "esp/iomux_regs.h" -#include "esp8266/uart_struct.h" +#include "uart_ll.h" #ifdef MODULE_ESP_QEMU #include "esp/uart_regs.h" @@ -63,6 +63,8 @@ #include "esp_idf_api/uart.h" #include "esp_private/periph_ctrl.h" #include "esp_rom_gpio.h" +#include "hal/uart_ll.h" +#include "soc/clk_tree_defs.h" #include "soc/gpio_reg.h" #include "soc/gpio_sig_map.h" #include "soc/gpio_struct.h" @@ -70,9 +72,13 @@ #include "soc/rtc.h" #include "soc/soc_caps.h" #include "soc/uart_pins.h" -#include "soc/uart_reg.h" -#include "soc/uart_struct.h" +/* UART_CLK_FREQ corresponds to APB_CLK_FREQ for ESP32, ESP32-S2, ESP32-S3, + * ESP32-C2 and ESP32-C3, which is a fixed frequency of 80 MHz. However, + * this only applies to CPU clock frequencies of 80 MHz and above. + * For lower CPU clock frequencies, the APB clock corresponds to the CPU clock + * frequency. Therefore, we need to determine the actual UART clock frequency + * from the actual APB clock frequency. */ #undef UART_CLK_FREQ #define UART_CLK_FREQ rtc_clk_apb_freq_get() /* APB_CLK is used */ @@ -249,7 +255,7 @@ void uart_system_init(void) { for (unsigned uart = 0; uart < UART_NUMOF; uart++) { /* reset all UART interrupt status registers */ - _uarts[uart].regs->int_clr.val = ~0; + uart_ll_clr_intsts_mask(_uarts[uart].regs, UART_LL_INTR_MASK); } #ifndef CPU_ESP8266 /* reset the pin usage of the default UART0 pins to GPIO to allow @@ -284,14 +290,10 @@ static void IRAM _uart_intr_handler(void *arg) interrupt, so we have to use the status to distinguish interruptees */ for (unsigned uart = 0; uart < UART_NUMOF; uart++) { if (_uarts[uart].used) { - DEBUG("%s uart=%d int_st=%08x\n", __func__, - uart, (unsigned)_uarts[uart].regs->int_st.val); + uint32_t int_st = uart_ll_get_intsts_mask(_uarts[uart].regs); + DEBUG("%s uart=%d int_st=%08"PRIx32"\n", __func__, uart, int_st); -#ifdef CPU_FAM_ESP32S3 - if (_uarts[uart].used && _uarts[uart].regs->int_st.rxfifo_full_int_st) { -#else - if (_uarts[uart].used && _uarts[uart].regs->int_st.rxfifo_full) { -#endif + if (_uarts[uart].used && (int_st & UART_RXFIFO_FULL_INT_ST)) { /* read one byte of data */ uint8_t data = _uart_rx_one_char(uart); /* if registered, call the RX callback function */ @@ -299,28 +301,21 @@ static void IRAM _uart_intr_handler(void *arg) _uarts[uart].isr_ctx.rx_cb(_uarts[uart].isr_ctx.arg, data); } /* clear interrupt flag */ -#ifdef CPU_FAM_ESP32S3 - _uarts[uart].regs->int_clr.rxfifo_full_int_clr = 1; -#else - _uarts[uart].regs->int_clr.rxfifo_full = 1; -#endif + uart_ll_clr_intsts_mask(_uarts[uart].regs, UART_RXFIFO_FULL_INT_ST); } /* TODO handle other types of interrupts, for the moment just clear them */ - _uarts[uart].regs->int_clr.val = ~0x0; + uart_ll_clr_intsts_mask(_uarts[uart].regs, UART_LL_INTR_MASK); } } irq_isr_exit(); } -/* RX/TX FIFO capacity is 128 byte */ -#define UART_FIFO_MAX 128 - /* receive one data byte with wait */ static uint8_t IRAM _uart_rx_one_char(uart_t uart) { -#if defined(MODULE_ESP_QEMU) && defined(CPU_ESP8266) +#if defined(CPU_ESP8266) && defined(MODULE_ESP_QEMU) /* wait until at least von byte is in RX FIFO */ while (!FIELD2VAL(UART_STATUS_RXFIFO_COUNT, UART(uart).STATUS)) {} @@ -328,54 +323,37 @@ static uint8_t IRAM _uart_rx_one_char(uart_t uart) return UART(uart).FIFO & 0xff; /* only bit 0 ... 7 */ #else /* wait until at least von byte is in RX FIFO */ - while (!_uarts[uart].regs->status.rxfifo_cnt) {} + while (uart_ll_get_rxfifo_len(_uarts[uart].regs) == 0) {} -#if defined(CPU_FAM_ESP32) || defined(CPU_ESP8266) - /* read the lowest byte from RX FIFO register */ - return _uarts[uart].regs->fifo.rw_byte; -#elif defined(CPU_FAM_ESP32S3) - /* read the lowest byte from RX FIFO register */ - return _uarts[uart].regs->fifo.rxfifo_rd_byte; -#elif defined(CPU_FAM_ESP32S2) - return READ_PERI_REG(UART_FIFO_AHB_REG(uart)); -#else - /* read the lowest byte from RX FIFO register */ - return _uarts[uart].regs->ahb_fifo.rw_byte; -#endif -#endif + uint8_t data; + uart_ll_read_rxfifo(_uarts[uart].regs, &data, 1); + return data; +#endif } /* send one data byte with wait */ static void _uart_tx_one_char(uart_t uart, uint8_t data) { /* wait until at least one byte is available in the TX FIFO */ - while (_uarts[uart].regs->status.txfifo_cnt >= UART_FIFO_MAX) {} + while (!uart_ll_get_txfifo_len(_uarts[uart].regs)) {} /* send the byte by placing it in the TX FIFO using MPU */ -#ifdef CPU_ESP8266 -#ifdef MODULE_ESP_QEMU +#if defined(CPU_ESP8266) && defined(MODULE_ESP_QEMU) UART(uart).FIFO = data; -#else /* MODULE_ESP_QEMU */ - _uarts[uart].regs->fifo.rw_byte = data; -#endif /* MODULE_ESP_QEMU */ -#else /* CPU_ESP8266 */ - WRITE_PERI_REG(UART_FIFO_AHB_REG(uart), data); -#endif /* CPU_ESP8266 */ +#else + uart_ll_write_txfifo(_uarts[uart].regs, &data, 1); +#endif } static void _uart_intr_enable(uart_t uart) { -#ifdef CPU_FAM_ESP32S3 - _uarts[uart].regs->int_ena.rxfifo_full_int_ena = 1; - _uarts[uart].regs->int_clr.rxfifo_full_int_clr = 1; -#else - _uarts[uart].regs->int_ena.rxfifo_full = 1; - _uarts[uart].regs->int_clr.rxfifo_full = 1; -#endif + uart_ll_ena_intr_mask(_uarts[uart].regs, UART_RXFIFO_FULL_INT_RAW); + uart_ll_clr_intsts_mask(_uarts[uart].regs, UART_RXFIFO_FULL_INT_RAW); + _uarts[uart].used = true; - DEBUG("%s %08x\n", __func__, (unsigned)_uarts[uart].regs->int_ena.val); + DEBUG("%s %08"PRIx32"\n", __func__, uart_ll_get_intr_ena_status(_uarts[uart].regs)); } static void _uart_config(uart_t uart) @@ -394,15 +372,13 @@ static void _uart_config(uart_t uart) } /* reset the FIFOs */ - _uarts[uart].regs->conf0.rxfifo_rst = 1; - _uarts[uart].regs->conf0.rxfifo_rst = 0; - _uarts[uart].regs->conf0.txfifo_rst = 1; - _uarts[uart].regs->conf0.txfifo_rst = 0; + uart_ll_rxfifo_rst(_uarts[uart].regs); + uart_ll_txfifo_rst(_uarts[uart].regs); if (_uarts[uart].isr_ctx.rx_cb) { /* since reading can only be done byte by byte, we set UART_RXFIFO_FULL_THRHD interrupt level to 1 byte */ - _uarts[uart].regs->conf1.rxfifo_full_thrhd = 1; + uart_ll_set_rxfifo_full_thr(_uarts[uart].regs, 1); /* enable the RX FIFO FULL interrupt */ _uart_intr_enable(uart); @@ -432,39 +408,14 @@ static int _uart_set_baudrate(uart_t uart, uint32_t baudrate) assert(uart < UART_NUMOF); /* wait until TX FIFO is empty */ - while (_uarts[uart].regs->status.txfifo_cnt != 0) { } + while (uart_ll_get_txfifo_len(_uarts[uart].regs) < UART_LL_FIFO_DEF_LEN) { } critical_enter(); _uarts[uart].baudrate = baudrate; -#ifdef CPU_ESP8266 - - /* compute and set clock divider */ - uint32_t clk_div = UART_CLK_FREQ / _uarts[uart].baudrate; - _uarts[uart].regs->clk_div.val = clk_div & 0xFFFFF; - -#else - -/* TODO look for an HAL/LL API function */ -#ifdef CPU_FAM_ESP32 - /* use APB_CLK */ - _uarts[uart].regs->conf0.tick_ref_always_on = 1; -#endif -#if defined(CPU_FAM_ESP32C3) || defined(CPU_FAM_ESP32S3) - _uarts[uart].regs->clk_conf.sclk_sel = 1; /* APB clock used instead of XTAL */ -#endif - /* compute and set the integral and the decimal part */ - uint32_t clk_div = (UART_CLK_FREQ << 4) / _uarts[uart].baudrate; -#ifdef CPU_FAM_ESP32S3 - _uarts[uart].regs->clkdiv.clkdiv = clk_div >> 4; - _uarts[uart].regs->clkdiv.clkdiv_frag = clk_div & 0xf; -#else - _uarts[uart].regs->clk_div.div_int = clk_div >> 4; - _uarts[uart].regs->clk_div.div_frag = clk_div & 0xf; -#endif /* CPU_FAM_ESP32S3 */ - -#endif + uart_ll_set_sclk(_uarts[uart].regs, (soc_module_clk_t)UART_SCLK_DEFAULT); + uart_ll_set_baudrate(_uarts[uart].regs, _uarts[uart].baudrate, UART_CLK_FREQ); critical_exit(); @@ -483,58 +434,43 @@ static int _uart_set_mode(uart_t uart, uart_data_bits_t data_bits, /* 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; + case UART_DATA_BITS_5: break; + case UART_DATA_BITS_6: break; + case UART_DATA_BITS_7: break; + case UART_DATA_BITS_8: break; default: LOG_TAG_ERROR("uart", "invalid number of data bits\n"); critical_exit(); return UART_NOMODE; } + uart_ll_set_data_bit_num(_uarts[uart].regs, (uart_word_length_t)data_bits); + /* store changed number of data bits in configuration */ _uarts[uart].data = data_bits; /* set number of stop bits */ -#ifdef CPU_ESP8266 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; + case UART_STOP_BITS_1: break; + case UART_STOP_BITS_2: break; default: LOG_TAG_ERROR("uart", "invalid number of stop bits\n"); critical_exit(); return UART_NOMODE; } -#else - /* 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; - _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; - } -#endif + uart_ll_set_stop_bits(_uarts[uart].regs, stop_bits); /* 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; + case UART_PARITY_NONE: break; + case UART_PARITY_EVEN: break; + case UART_PARITY_ODD: break; default: LOG_TAG_ERROR("uart", "invalid or unsupported parity mode\n"); critical_exit(); return UART_NOMODE; } + uart_ll_set_parity(_uarts[uart].regs, parity); + /* store changed parity in configuration */ _uarts[uart].parity = parity;