From f27ae9b0e226ac17732d882f7450e9c78583efe7 Mon Sep 17 00:00:00 2001 From: houwenxiang Date: Wed, 17 Apr 2019 20:19:44 +0800 Subject: [PATCH] feature: Add uart hal support. --- components/driver/include/driver/uart.h | 294 ++-- components/driver/test/test_uart.c | 6 +- components/driver/uart.c | 1235 +++++++---------- .../esp32s2beta/ld/esp32s2beta.peripherals.ld | 1 - components/freemodbus/port/portserial.c | 1 + components/freemodbus/port/portserial_m.c | 1 + components/soc/CMakeLists.txt | 2 + components/soc/esp32/include/hal/uart_ll.h | 793 +++++++++++ components/soc/esp32/include/soc/uart_caps.h | 14 +- components/soc/esp32/sources.cmake | 4 +- components/soc/esp32/uart_periph.c | 45 + .../soc/esp32s2beta/include/hal/uart_ll.h | 757 ++++++++++ .../soc/esp32s2beta/include/soc/uart_caps.h | 13 +- components/soc/esp32s2beta/sources.cmake | 4 +- components/soc/esp32s2beta/uart_periph.c | 37 + components/soc/include/hal/uart_hal.h | 426 ++++++ components/soc/include/hal/uart_types.h | 145 ++ components/soc/include/soc/uart_periph.h | 17 +- components/soc/include/soc/uhci_periph.h | 18 + components/soc/linker.lf | 4 + components/soc/src/hal/uart_hal.c | 156 +++ components/soc/src/hal/uart_hal_iram.c | 48 + components/vfs/test/test_vfs_select.c | 9 +- components/vfs/test/test_vfs_uart.c | 6 +- components/vfs/vfs_uart.c | 1 + docs/Doxyfile | 1 + .../ble/ble_spp_client/main/spp_client_demo.c | 5 +- .../ble_spp_server/main/ble_spp_server_demo.c | 5 +- .../main/controller_hci_uart_demo.c | 2 + .../ble_mesh_client_model/main/board.c | 115 ++ .../iperf/main/ethernet_example_main.c | 5 +- .../i2c_tools/main/i2ctools_example_main.c | 5 +- .../uart/nmea0183_parser/main/nmea_parser.c | 13 +- .../main/uart_async_rxtxtasks_main.c | 7 +- .../uart_echo/main/uart_echo_example_main.c | 5 +- .../uart/uart_echo_rs485/main/rs485_example.c | 8 +- .../main/uart_events_example_main.c | 7 +- .../main/uart_select_example_main.c | 5 +- .../icmp_echo/main/echo_example_main.c | 5 +- .../components/modem/src/esp_modem.c | 10 +- .../components/cmd_system/cmd_system.c | 6 +- .../console/main/console_example_main.c | 5 +- .../main/light_sleep_example_main.c | 3 +- examples/system/select/main/select_example.c | 8 +- 44 files changed, 3281 insertions(+), 976 deletions(-) create mode 100644 components/soc/esp32/include/hal/uart_ll.h create mode 100644 components/soc/esp32/uart_periph.c create mode 100644 components/soc/esp32s2beta/include/hal/uart_ll.h create mode 100644 components/soc/esp32s2beta/uart_periph.c create mode 100644 components/soc/include/hal/uart_hal.h create mode 100644 components/soc/include/hal/uart_types.h create mode 100644 components/soc/include/soc/uhci_periph.h create mode 100644 components/soc/src/hal/uart_hal.c create mode 100644 components/soc/src/hal/uart_hal_iram.c create mode 100644 examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.c diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index 0e1f6c0b1..764b03a6e 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -18,107 +18,26 @@ extern "C" { #endif -#include "soc/uart_periph.h" -#include "soc/uart_caps.h" #include "esp_err.h" #include "esp_intr_alloc.h" -#include "driver/periph_ctrl.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/xtensa_api.h" #include "freertos/task.h" #include "freertos/queue.h" #include "freertos/ringbuf.h" -#include +#include "hal/uart_types.h" +#include "soc/uart_caps.h" -#define UART_FIFO_LEN (128) /*!< Length of the hardware FIFO buffers */ -#define UART_INTR_MASK 0x1ff /*!< Mask of all UART interrupts */ -#define UART_LINE_INV_MASK (0x3f << 19) /*!< TBD */ -#define UART_BITRATE_MAX 5000000 /*!< Max bit rate supported by UART */ -#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */ - -#define UART_INVERSE_DISABLE (0x0) /*!< Disable UART signal inverse*/ -#define UART_INVERSE_RXD (UART_RXD_INV_M) /*!< UART RXD input inverse*/ -#define UART_INVERSE_CTS (UART_CTS_INV_M) /*!< UART CTS input inverse*/ -#define UART_INVERSE_TXD (UART_TXD_INV_M) /*!< UART TXD output inverse*/ -#define UART_INVERSE_RTS (UART_RTS_INV_M) /*!< UART RTS output inverse*/ - -/** - * @brief UART mode selection - */ -typedef enum { - UART_MODE_UART = 0x00, /*!< mode: regular UART mode*/ - UART_MODE_RS485_HALF_DUPLEX = 0x01, /*!< mode: half duplex RS485 UART mode control by RTS pin */ - UART_MODE_IRDA = 0x02, /*!< mode: IRDA UART mode*/ - UART_MODE_RS485_COLLISION_DETECT = 0x03, /*!< mode: RS485 collision detection UART mode (used for test purposes)*/ - UART_MODE_RS485_APP_CTRL = 0x04, /*!< mode: application control RS485 UART mode (used for test purposes)*/ -} uart_mode_t; - -/** - * @brief UART word length constants - */ -typedef enum { - UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/ - UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/ - UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/ - UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/ - UART_DATA_BITS_MAX = 0x4, -} uart_word_length_t; - -/** - * @brief UART stop bits number - */ -typedef enum { - UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/ - UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/ - UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/ - UART_STOP_BITS_MAX = 0x4, -} uart_stop_bits_t; - -/** - * @brief UART peripheral number - */ -typedef enum { - UART_NUM_0 = 0x0, /*!< UART base address 0x3ff40000*/ - UART_NUM_1 = 0x1, /*!< UART base address 0x3ff50000*/ +// Valid UART port number +#define UART_NUM_0 (0) /*!< UART port 0 */ +#define UART_NUM_1 (1) /*!< UART port 1 */ #if SOC_UART_NUM > 2 - UART_NUM_2 = 0x2, /*!< UART base address 0x3ff6e000*/ +#define UART_NUM_2 (2) /*!< UART port 2 */ #endif - UART_NUM_MAX, -} uart_port_t; +#define UART_NUM_MAX (SOC_UART_NUM) /*!< UART port max */ -/** - * @brief UART parity constants - */ -typedef enum { - UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/ - UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/ - UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/ -} uart_parity_t; - -/** - * @brief UART hardware flow control modes - */ -typedef enum { - UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/ - UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/ - UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/ - UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/ - UART_HW_FLOWCTRL_MAX = 0x4, -} uart_hw_flowcontrol_t; - -/** - * @brief UART configuration parameters for uart_param_config function - */ -typedef struct { - int baud_rate; /*!< UART baud rate*/ - uart_word_length_t data_bits; /*!< UART byte size*/ - uart_parity_t parity; /*!< UART parity mode*/ - uart_stop_bits_t stop_bits; /*!< UART stop bits*/ - uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts)*/ - uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold*/ - bool use_ref_tick; /*!< Set to true if UART should be clocked from REF_TICK */ -} uart_config_t; +#define UART_PIN_NO_CHANGE (-1) /*!< Constant for uart_set_pin function which indicates that UART pin should not be changed */ /** * @brief UART interrupt configuration parameters for uart_intr_config function @@ -155,10 +74,45 @@ typedef struct { typedef intr_handle_t uart_isr_handle_t; +/** + * @brief Install UART driver and set the UART to the default configuration. + * + * UART ISR handler will be attached to the same CPU core that this function is running on. + * + * @note Rx_buffer_size should be greater than UART_FIFO_LEN. Tx_buffer_size should be either zero or greater than UART_FIFO_LEN. + * + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). + * @param rx_buffer_size UART RX ring buffer size. + * @param tx_buffer_size UART TX ring buffer size. + * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out. + * @param queue_size UART event queue size/depth. + * @param uart_queue UART event queue handle (out param). On success, a new queue handle is written here to provide + * access to UART events. If set to NULL, driver will not use an event queue. + * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) + * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. Do not set ESP_INTR_FLAG_IRAM here + * (the driver's ISR handler is not located in IRAM) + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t* uart_queue, int intr_alloc_flags); + +/** + * @brief Uninstall UART driver. + * + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). + * + * @return + * - ESP_OK Success + * - ESP_FAIL Parameter error + */ +esp_err_t uart_driver_delete(uart_port_t uart_num); + /** * @brief Set UART data bits. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param data_bit UART data bits * * @return @@ -168,9 +122,9 @@ typedef intr_handle_t uart_isr_handle_t; esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit); /** - * @brief Get UART data bits. + * @brief Get the UART data bit configuration. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param data_bit Pointer to accept value of UART data bits. * * @return @@ -182,7 +136,7 @@ esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bi /** * @brief Set UART stop bits. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param stop_bits UART stop bits * * @return @@ -192,9 +146,9 @@ esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bi esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bits); /** - * @brief Get UART stop bits. + * @brief Get the UART stop bit configuration. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param stop_bits Pointer to accept value of UART stop bits. * * @return @@ -206,7 +160,7 @@ esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits); /** * @brief Set UART parity mode. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param parity_mode the enum of uart parity configuration * * @return @@ -216,9 +170,9 @@ esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bits); esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode); /** - * @brief Get UART parity mode. + * @brief Get the UART parity mode configuration. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param parity_mode Pointer to accept value of UART parity mode. * * @return @@ -231,7 +185,7 @@ esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode); /** * @brief Set UART baud rate. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param baudrate UART baud rate. * * @return @@ -241,9 +195,9 @@ esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode); esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate); /** - * @brief Get UART baud rate. + * @brief Get the UART baud rate configuration. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param baudrate Pointer to accept value of UART baud rate * * @return @@ -256,11 +210,8 @@ esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t* baudrate); /** * @brief Set UART line inverse mode * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * @param inverse_mask Choose the wires that need to be inverted. - * Inverse_mask should be chosen from - * UART_INVERSE_RXD / UART_INVERSE_TXD / UART_INVERSE_RTS / UART_INVERSE_CTS, - * combined with OR operation. + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). + * @param inverse_mask Choose the wires that need to be inverted. Using the ORred mask of `uart_signal_inv_t` * * @return * - ESP_OK Success @@ -271,7 +222,7 @@ esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask); /** * @brief Set hardware flow control. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param flow_ctrl Hardware flow control mode * @param rx_thresh Threshold of Hardware RX flow control (0 ~ UART_FIFO_LEN). * Only when UART_HW_FLOWCTRL_RTS is set, will the rx_thresh value be set. @@ -294,12 +245,12 @@ esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow * - ESP_OK Success * - ESP_FAIL Parameter error */ - esp_err_t uart_set_sw_flow_ctrl(uart_port_t uart_num, bool enable, uint8_t rx_thresh_xon, uint8_t rx_thresh_xoff); + esp_err_t uart_set_sw_flow_ctrl(uart_port_t uart_num, bool enable, uint8_t rx_thresh_xon, uint8_t rx_thresh_xoff); /** - * @brief Get hardware flow control mode + * @brief Get the UART hardware flow control configuration. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param flow_ctrl Option for different flow control mode. * * @return @@ -311,9 +262,8 @@ esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flo /** * @brief Clear UART interrupt status * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param clr_mask Bit mask of the interrupt status to be cleared. - * The bit mask should be composed from the fields of register UART_INT_CLR_REG. * * @return * - ESP_OK Success @@ -324,9 +274,8 @@ esp_err_t uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask); /** * @brief Set UART interrupt enable * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param enable_mask Bit mask of the enable bits. - * The bit mask should be composed from the fields of register UART_INT_ENA_REG. * * @return * - ESP_OK Success @@ -337,9 +286,8 @@ esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask); /** * @brief Clear UART interrupt enable bits * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param disable_mask Bit mask of the disable bits. - * The bit mask should be composed from the fields of register UART_INT_ENA_REG. * * @return * - ESP_OK Success @@ -350,7 +298,7 @@ esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask); /** * @brief Enable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT) * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * * @return * - ESP_OK Success @@ -361,7 +309,7 @@ esp_err_t uart_enable_rx_intr(uart_port_t uart_num); /** * @brief Disable UART RX interrupt (RX_FULL & RX_TIMEOUT INTERRUPT) * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * * @return * - ESP_OK Success @@ -372,7 +320,7 @@ esp_err_t uart_disable_rx_intr(uart_port_t uart_num); /** * @brief Disable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT) * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number * * @return * - ESP_OK Success @@ -383,7 +331,7 @@ esp_err_t uart_disable_tx_intr(uart_port_t uart_num); /** * @brief Enable UART TX interrupt (TX_FULL & TX_TIMEOUT INTERRUPT) * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param enable 1: enable; 0: disable * @param thresh Threshold of TX interrupt, 0 ~ UART_FIFO_LEN * @@ -398,7 +346,7 @@ esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh); * * @note UART ISR handler will be attached to the same CPU core that this function is running on. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param fn Interrupt handler function. * @param arg parameter for handler function * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) @@ -416,7 +364,7 @@ esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, * @brief Free UART interrupt handler registered by uart_isr_register. Must be called on the same core as * uart_isr_register was called. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * * @return * - ESP_OK Success @@ -433,7 +381,7 @@ esp_err_t uart_isr_free(uart_port_t uart_num); * @note Instead of GPIO number a macro 'UART_PIN_NO_CHANGE' may be provided to keep the currently allocated pin. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param tx_io_num UART TX pin GPIO number. * @param rx_io_num UART RX pin GPIO number. * @param rts_io_num UART RTS pin GPIO number. @@ -449,7 +397,7 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r * @brief Manually set the UART RTS pin level. * @note UART must be configured with hardware flow control disabled. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param level 1: RTS output low (active); 0: RTS output high (block) * * @return @@ -461,7 +409,7 @@ esp_err_t uart_set_rts(uart_port_t uart_num, int level); /** * @brief Manually set the UART DTR pin level. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param level 1: DTR output low; 0: DTR output high * * @return @@ -473,7 +421,7 @@ esp_err_t uart_set_dtr(uart_port_t uart_num, int level); /** * @brief Set UART idle interval after tx FIFO is empty * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param idle_num idle interval after tx FIFO is empty(unit: the time it takes to send one bit * under current baudrate) * @@ -486,7 +434,7 @@ esp_err_t uart_set_tx_idle_num(uart_port_t uart_num, uint16_t idle_num); /** * @brief Set UART configuration parameters. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param uart_config UART parameter settings * * @return @@ -498,7 +446,7 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf /** * @brief Configure UART interrupts. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param intr_conf UART interrupt settings * * @return @@ -507,45 +455,10 @@ esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_conf */ esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf); -/** - * @brief Install UART driver. - * - * UART ISR handler will be attached to the same CPU core that this function is running on. - * - * @note Rx_buffer_size should be greater than UART_FIFO_LEN. Tx_buffer_size should be either zero or greater than UART_FIFO_LEN. - * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * @param rx_buffer_size UART RX ring buffer size. - * @param tx_buffer_size UART TX ring buffer size. - * If set to zero, driver will not use TX buffer, TX function will block task until all data have been sent out. - * @param queue_size UART event queue size/depth. - * @param uart_queue UART event queue handle (out param). On success, a new queue handle is written here to provide - * access to UART events. If set to NULL, driver will not use an event queue. - * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) - * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. No need to set ESP_INTR_FLAG_IRAM here, as this flag - * will be enabled based on CONFIG_UART_ISR_IN_IRAM (i.e. if the handler located in IRAM or not) - * - * @return - * - ESP_OK Success - * - ESP_FAIL Parameter error - */ -esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t* uart_queue, int intr_alloc_flags); - -/** - * @brief Uninstall UART driver. - * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 - * - * @return - * - ESP_OK Success - * - ESP_FAIL Parameter error - */ -esp_err_t uart_driver_delete(uart_port_t uart_num); - /** * @brief Wait until UART TX FIFO is empty. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param ticks_to_wait Timeout, count in RTOS ticks * * @return @@ -561,7 +474,7 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait); * This function will not wait for enough space in TX FIFO. It will just fill the available TX FIFO and return when the FIFO is full. * @note This function should only be used when UART TX buffer is not enabled. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param buffer data buffer address * @param len data length to send * @@ -580,7 +493,7 @@ int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len); * Otherwise, if the 'tx_buffer_size' > 0, this function will return after copying all the data to tx ring buffer, * UART ISR will then move data from the ring buffer to TX FIFO gradually. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param src data buffer address * @param size data length to send * @@ -601,7 +514,7 @@ int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size); * UART ISR will then move data from the ring buffer to TX FIFO gradually. * After all data sent out, send a break signal. * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param src data buffer address * @param size data length to send * @param brk_len break signal duration(unit: the time it takes to send one bit at current baudrate) @@ -615,7 +528,7 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t si /** * @brief UART read bytes from UART buffer * - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param buf pointer to the buffer. * @param length data length * @param ticks_to_wait sTimeout, count in RTOS ticks @@ -631,7 +544,7 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickTyp * UART ring buffer flush. This will discard all data in the UART RX buffer. * @note Instead of waiting the data sent out, this function will clear UART rx buffer. * In order to send all the data in tx FIFO, we can use uart_wait_tx_done function. - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * * @return * - ESP_OK Success @@ -642,7 +555,7 @@ esp_err_t uart_flush(uart_port_t uart_num); /** * @brief Clear input buffer, discard all the data is in the ring-buffer. * @note In order to send all the data in tx FIFO, we can use uart_wait_tx_done function. - * @param uart_num UART_NUM_0, UART_NUM_1 or UART_NUM_2 + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * * @return * - ESP_OK Success @@ -653,7 +566,7 @@ esp_err_t uart_flush_input(uart_port_t uart_num); /** * @brief UART get RX ring buffer cached data length * - * @param uart_num UART port number. + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param size Pointer of size_t to accept cached data length * * @return @@ -667,7 +580,7 @@ esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size); * Designed for applications like 'AT commands'. * When the hardware detects a series of one same character, the interrupt will be triggered. * - * @param uart_num UART port number. + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * * @return * - ESP_OK Success @@ -733,7 +646,7 @@ esp_err_t uart_enable_pattern_det_baud_intr(uart_port_t uart_num, char pattern_c * It is the application's responsibility to ensure atomic access to the pattern queue and the rx data buffer * when using pattern detect feature. * - * @param uart_num UART port number + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @return * - (-1) No pattern found for current index or parameter error * - others the pattern position in rx buffer. @@ -752,7 +665,7 @@ int uart_pattern_pop_pos(uart_port_t uart_num); * It is the application's responsibility to ensure atomic access to the pattern queue and the rx data buffer * when using pattern detect feature. * - * @param uart_num UART port number + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @return * - (-1) No pattern found for current index or parameter error * - others the pattern position in rx buffer. @@ -761,7 +674,8 @@ int uart_pattern_get_pos(uart_port_t uart_num); /** * @brief Allocate a new memory with the given length to save record the detected pattern position in rx buffer. - * @param uart_num UART port number + * + * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param queue_length Max queue length for the detected pattern. * If the queue length is not large enough, some pattern positions might be lost. * Set this value to the maximum number of patterns that could be saved in data buffer at the same time. @@ -775,8 +689,9 @@ esp_err_t uart_pattern_queue_reset(uart_port_t uart_num, int queue_length); /** * @brief UART set communication mode + * * @note This function must be executed after uart_driver_install(), when the driver object is initialized. - * @param uart_num Uart number to configure + * @param uart_num Uart number to configure, the max port number is (UART_NUM_MAX -1). * @param mode UART UART mode to set * * @return @@ -788,7 +703,7 @@ esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode); /** * @brief UART set threshold timeout for TOUT feature * - * @param uart_num Uart number to configure + * @param uart_num Uart number to configure, the max port number is (UART_NUM_MAX -1). * @param tout_thresh This parameter defines timeout threshold in uart symbol periods. The maximum value of threshold is 126. * tout_thresh = 1, defines TOUT interrupt timeout equal to transmission time of one symbol (~11 bit) on current baudrate. * If the time is expired the UART_RXFIFO_TOUT_INT interrupt is triggered. If tout_thresh == 0, @@ -807,7 +722,7 @@ esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh); * *collision_flag = true, if collision detected else it is equal to false. * This function should be executed when actual transmission is completed (after uart_write_bytes()). * - * @param uart_num Uart number to configure + * @param uart_num Uart number to configure the max port number is (UART_NUM_MAX -1). * @param collision_flag Pointer to variable of type bool to return collision flag. * * @return @@ -842,7 +757,7 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag); * GPIO9 should be configured as function_5 to wake up UART1), UART2 * does not support light sleep wakeup feature. * - * @param uart_num UART number + * @param uart_num UART number, the max port number is (UART_NUM_MAX -1). * @param wakeup_threshold number of RX edges for light sleep wakeup, value is 3 .. 0x3ff. * @return * - ESP_OK on success @@ -857,7 +772,7 @@ esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold); * See description of uart_set_wakeup_threshold for the explanation of UART * wakeup feature. * - * @param uart_num UART number + * @param uart_num UART number, the max port number is (UART_NUM_MAX -1). * @param[out] out_wakeup_threshold output, set to the current value of wakeup * threshold for the given UART. * @return @@ -871,8 +786,25 @@ esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_thresh * * @param uart_num UART number * + * * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Driver not installed */ -void uart_wait_tx_idle_polling(uart_port_t uart_num); +esp_err_t uart_wait_tx_idle_polling(uart_port_t uart_num); + +/** + * @brief Configure TX signal loop back to RX module, just for the test usage. + * + * @param uart_num UART number + * @param loop_back_en Set ture to enable the loop back function, else set it false. + * + * * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Driver not installed + */ +esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en); #ifdef __cplusplus } diff --git a/components/driver/test/test_uart.c b/components/driver/test/test_uart.c index 3283b9f6f..6ead25b13 100644 --- a/components/driver/test/test_uart.c +++ b/components/driver/test/test_uart.c @@ -34,11 +34,11 @@ static void uart_config(uint32_t baud_rate, bool use_ref_tick) .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, - .use_ref_tick = use_ref_tick, }; + uart_config.source_clk = use_ref_tick ? UART_SCLK_REF_TICK : UART_SCLK_APB; + uart_driver_install(UART_NUM1, BUF_SIZE * 2, BUF_SIZE * 2, 20, NULL, 0); uart_param_config(UART_NUM1, &uart_config); uart_set_pin(UART_NUM1, UART1_TX_PIN, UART1_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - uart_driver_install(UART_NUM1, BUF_SIZE * 2, BUF_SIZE * 2, 20, NULL, 0); } static volatile bool exit_flag; @@ -64,7 +64,7 @@ static void test_task2(void *pvParameters) while (exit_flag == false) { // This task obstruct a setting tx_done_sem semaphore in the UART interrupt. // It leads to waiting the ticks_to_wait time in uart_wait_tx_done() function. - uart_disable_intr_mask(UART_NUM1, UART_TX_DONE_INT_ENA_M); + uart_disable_tx_intr(UART_NUM1); } vTaskDelete(NULL); } diff --git a/components/driver/uart.c b/components/driver/uart.c index 4fc5d00e0..1ec17fd7c 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -21,12 +21,13 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" #include "freertos/xtensa_api.h" -#include "freertos/task.h" #include "freertos/ringbuf.h" +#include "hal/uart_hal.h" #include "soc/uart_periph.h" #include "driver/uart.h" #include "driver/gpio.h" #include "driver/uart_select.h" +#include "driver/periph_ctrl.h" #include "sdkconfig.h" #if CONFIG_IDF_TARGET_ESP32 @@ -35,18 +36,16 @@ #include "esp32s2beta/clk.h" #endif -#define UART_NUM SOC_UART_NUM - #ifdef CONFIG_UART_ISR_IN_IRAM #define UART_ISR_ATTR IRAM_ATTR #else #define UART_ISR_ATTR #endif -#define XOFF (char)0x13 -#define XON (char)0x11 +#define XOFF (0x13) +#define XON (0x11) -static const char *UART_TAG = "uart"; +static const char* UART_TAG = "uart"; #define UART_CHECK(a, str, ret_val) \ if (!(a)) { \ ESP_LOGE(UART_TAG,"%s(%d): %s", __FUNCTION__, __LINE__, str); \ @@ -57,19 +56,25 @@ static const char *UART_TAG = "uart"; #define UART_FULL_THRESH_DEFAULT (120) #define UART_TOUT_THRESH_DEFAULT (10) #define UART_CLKDIV_FRAG_BIT_WIDTH (3) -#define UART_TOUT_REF_FACTOR_DEFAULT (UART_CLK_FREQ/(REF_CLK_FREQ<uart_mode == mode)) +#define UART_CONTEX_INIT_DEF(uart_num) {\ + .hal.dev = UART_LL_GET_HW(uart_num),\ + .spinlock = portMUX_INITIALIZER_UNLOCKED,\ + .hw_enabled = false,\ +} + typedef struct { uart_event_type_t type; /*!< UART TX data type */ struct { @@ -83,7 +88,7 @@ typedef struct { int wr; int rd; int len; - int *data; + int* data; } uart_pat_rb_t; typedef struct { @@ -101,8 +106,8 @@ typedef struct { RingbufHandle_t rx_ring_buf; /*!< RX ring buffer handler*/ bool rx_buffer_full_flg; /*!< RX ring buffer full flag. */ int rx_cur_remain; /*!< Data number that waiting to be read out in ring buffer item*/ - uint8_t *rx_ptr; /*!< pointer to the current data in ring buffer*/ - uint8_t *rx_head_ptr; /*!< pointer to the head of RX item*/ + uint8_t* rx_ptr; /*!< pointer to the current data in ring buffer*/ + uint8_t* rx_head_ptr; /*!< pointer to the head of RX item*/ uint8_t rx_data_buf[UART_FIFO_LEN]; /*!< Data buffer to stash FIFO data*/ uint8_t rx_stash_len; /*!< stashed data length.(When using flow control, after reading out FIFO data, if we fail to push to buffer, we can just stash them.) */ uart_pat_rb_t rx_pattern_pos; @@ -115,8 +120,8 @@ typedef struct { int tx_buf_size; /*!< TX ring buffer size */ RingbufHandle_t tx_ring_buf; /*!< TX ring buffer handler*/ bool tx_waiting_fifo; /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/ - uint8_t *tx_ptr; /*!< TX data pointer to push to FIFO in TX buffer mode*/ - uart_tx_data_t *tx_head; /*!< TX data pointer to head of the current buffer in TX ring buffer*/ + uint8_t* tx_ptr; /*!< TX data pointer to push to FIFO in TX buffer mode*/ + uart_tx_data_t* tx_head; /*!< TX data pointer to head of the current buffer in TX ring buffer*/ uint32_t tx_len_tot; /*!< Total length of current item in ring buffer*/ uint32_t tx_len_cur; uint8_t tx_brk_flg; /*!< Flag to indicate to send a break signal in the end of the item sending procedure */ @@ -125,38 +130,63 @@ typedef struct { uart_select_notif_callback_t uart_select_notif_callback; /*!< Notification about select() events */ } uart_obj_t; +typedef struct { + uart_hal_context_t hal; /*!< UART hal context*/ + portMUX_TYPE spinlock; + bool hw_enabled; +} uart_context_t; + static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; -/* DRAM_ATTR is required to avoid UART array placed in flash, due to accessed from ISR */ -static DRAM_ATTR uart_dev_t *const UART[UART_NUM_MAX] = { - &UART0, - &UART1, -#if UART_NUM > 2 - &UART2 -#endif -}; -static portMUX_TYPE uart_spinlock[UART_NUM_MAX] = { - portMUX_INITIALIZER_UNLOCKED, - portMUX_INITIALIZER_UNLOCKED, -#if UART_NUM > 2 - portMUX_INITIALIZER_UNLOCKED + +static uart_context_t uart_context[UART_NUM_MAX] = { + UART_CONTEX_INIT_DEF(UART_NUM_0), + UART_CONTEX_INIT_DEF(UART_NUM_1), +#if UART_NUM_MAX > 2 + UART_CONTEX_INIT_DEF(UART_NUM_2), #endif }; + static portMUX_TYPE uart_selectlock = portMUX_INITIALIZER_UNLOCKED; +static void uart_module_enable(uart_port_t uart_num) +{ + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + if (uart_context[uart_num].hw_enabled != true) { + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) { + periph_module_reset(uart_periph_signal[uart_num].module); + } + periph_module_enable(uart_periph_signal[uart_num].module); + uart_context[uart_num].hw_enabled = true; + } + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); +} + +static void uart_module_disable(uart_port_t uart_num) +{ + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + if (uart_context[uart_num].hw_enabled != false) { + if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM ) { + periph_module_disable(uart_periph_signal[uart_num].module); + } + uart_context[uart_num].hw_enabled = false; + } + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); +} + esp_err_t uart_set_word_length(uart_port_t uart_num, uart_word_length_t data_bit) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((data_bit < UART_DATA_BITS_MAX), "data bit error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->conf0.bit_num = data_bit; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_data_bit_num(&(uart_context[uart_num].hal), data_bit); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t *data_bit) +esp_err_t uart_get_word_length(uart_port_t uart_num, uart_word_length_t* data_bit) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - *(data_bit) = UART[uart_num]->conf0.bit_num; + uart_hal_get_data_bit_num(&(uart_context[uart_num].hal), data_bit); return ESP_OK; } @@ -164,110 +194,61 @@ esp_err_t uart_set_stop_bits(uart_port_t uart_num, uart_stop_bits_t stop_bit) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((stop_bit < UART_STOP_BITS_MAX), "stop bit error", ESP_FAIL); - - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); -#if CONFIG_IDF_TARGET_ESP32 - //workaround for hardware bug, when uart stop bit set as 2-bit mode. - if (stop_bit == UART_STOP_BITS_2) { - stop_bit = UART_STOP_BITS_1; - UART[uart_num]->rs485_conf.dl1_en = 1; - } else { - UART[uart_num]->rs485_conf.dl1_en = 0; - } -#endif - UART[uart_num]->conf0.stop_bit_num = stop_bit; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_stop_bits(&(uart_context[uart_num].hal), stop_bit); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t *stop_bit) +esp_err_t uart_get_stop_bits(uart_port_t uart_num, uart_stop_bits_t* stop_bit) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); -#if CONFIG_IDF_TARGET_ESP32 - //workaround for hardware bug, when uart stop bit set as 2-bit mode. - if (UART[uart_num]->rs485_conf.dl1_en == 1 && UART[uart_num]->conf0.stop_bit_num == UART_STOP_BITS_1) { - (*stop_bit) = UART_STOP_BITS_2; - } else { - (*stop_bit) = UART[uart_num]->conf0.stop_bit_num; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - (*stop_bit) = UART[uart_num]->conf0.stop_bit_num; -#endif + uart_hal_get_stop_bits(&(uart_context[uart_num].hal), stop_bit); return ESP_OK; } esp_err_t uart_set_parity(uart_port_t uart_num, uart_parity_t parity_mode) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->conf0.parity = parity_mode & 0x1; - UART[uart_num]->conf0.parity_en = (parity_mode >> 1) & 0x1; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_parity(&(uart_context[uart_num].hal), parity_mode); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t *parity_mode) +esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - int val = UART[uart_num]->conf0.val; - if (val & UART_PARITY_EN_M) { - if (val & UART_PARITY_M) { - (*parity_mode) = UART_PARITY_ODD; - } else { - (*parity_mode) = UART_PARITY_EVEN; - } - } else { - (*parity_mode) = UART_PARITY_DISABLE; - } + uart_hal_get_parity(&(uart_context[uart_num].hal), parity_mode); return ESP_OK; } esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baud_rate) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - esp_err_t ret = ESP_OK; - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - int uart_clk_freq; - if (UART[uart_num]->conf0.tick_ref_always_on == 0) { - /* this UART has been configured to use REF_TICK */ - uart_clk_freq = REF_CLK_FREQ; - } else { - uart_clk_freq = esp_clk_apb_freq(); - } - uint32_t clk_div = (((uart_clk_freq) << 4) / baud_rate); - if (clk_div < 16) { - /* baud rate is too high for this clock frequency */ - ret = ESP_ERR_INVALID_ARG; - } else { - UART[uart_num]->clk_div.div_int = clk_div >> 4; - UART[uart_num]->clk_div.div_frag = clk_div & 0xf; - } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); - return ret; + uart_sclk_t source_clk = 0; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_get_sclk(&(uart_context[uart_num].hal), &source_clk); + uart_hal_set_baudrate(&(uart_context[uart_num].hal), source_clk, baud_rate); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + return ESP_OK; } esp_err_t uart_get_baudrate(uart_port_t uart_num, uint32_t *baudrate) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - uint32_t clk_div = (UART[uart_num]->clk_div.div_int << 4) | UART[uart_num]->clk_div.div_frag; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); - uint32_t uart_clk_freq = esp_clk_apb_freq(); - if (UART[uart_num]->conf0.tick_ref_always_on == 0) { - uart_clk_freq = REF_CLK_FREQ; - } - (*baudrate) = ((uart_clk_freq) << 4) / clk_div; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_get_baudrate(&(uart_context[uart_num].hal), baudrate); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } esp_err_t uart_set_line_inverse(uart_port_t uart_num, uint32_t inverse_mask) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_CHECK((((inverse_mask & ~UART_LINE_INV_MASK) == 0) || (inverse_mask == 0)), "inverse_mask error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - CLEAR_PERI_REG_MASK(UART_CONF0_REG(uart_num), UART_LINE_INV_MASK); - SET_PERI_REG_MASK(UART_CONF0_REG(uart_num), inverse_mask); - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_inverse_signal(&(uart_context[uart_num].hal), inverse_mask); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } @@ -276,134 +257,73 @@ esp_err_t uart_set_sw_flow_ctrl(uart_port_t uart_num, bool enable, uint8_t rx_t UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((rx_thresh_xon < UART_FIFO_LEN), "rx flow xon thresh error", ESP_FAIL); UART_CHECK((rx_thresh_xoff < UART_FIFO_LEN), "rx flow xon thresh error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->flow_conf.sw_flow_con_en = enable ? 1 : 0; - UART[uart_num]->flow_conf.xonoff_del = enable ? 1 : 0; -#if CONFIG_IDF_TARGET_ESP32 - UART[uart_num]->swfc_conf.xon_threshold = rx_thresh_xon; - UART[uart_num]->swfc_conf.xoff_threshold = rx_thresh_xoff; - UART[uart_num]->swfc_conf.xon_char = XON; - UART[uart_num]->swfc_conf.xoff_char = XOFF; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - UART[uart_num]->swfc_conf1.xon_threshold = rx_thresh_xon; - UART[uart_num]->swfc_conf0.xoff_threshold = rx_thresh_xoff; - UART[uart_num]->swfc_conf1.xon_char = XON; - UART[uart_num]->swfc_conf0.xoff_char = XOFF; -#endif - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + uart_sw_flowctrl_t sw_flow_ctl = { + .xon_char = XON, + .xoff_char = XOFF, + .xon_thrd = rx_thresh_xon, + .xoff_thrd = rx_thresh_xoff, + }; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_sw_flow_ctrl(&(uart_context[uart_num].hal), &sw_flow_ctl, enable); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -//only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set. esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((rx_thresh < UART_FIFO_LEN), "rx flow thresh error", ESP_FAIL); UART_CHECK((flow_ctrl < UART_HW_FLOWCTRL_MAX), "hw_flowctrl mode error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - if (flow_ctrl & UART_HW_FLOWCTRL_RTS) { -#if CONFIG_IDF_TARGET_ESP32 - UART[uart_num]->conf1.rx_flow_thrhd = rx_thresh; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - UART[uart_num]->mem_conf.rx_flow_thrhd = rx_thresh; -#endif - UART[uart_num]->conf1.rx_flow_en = 1; - } else { - UART[uart_num]->conf1.rx_flow_en = 0; - } - if (flow_ctrl & UART_HW_FLOWCTRL_CTS) { - UART[uart_num]->conf0.tx_flow_en = 1; - } else { - UART[uart_num]->conf0.tx_flow_en = 0; - } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_hw_flow_ctrl(&(uart_context[uart_num].hal), flow_ctrl, rx_thresh); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t *flow_ctrl) +esp_err_t uart_get_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t* flow_ctrl) { - UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - uart_hw_flowcontrol_t val = UART_HW_FLOWCTRL_DISABLE; - if (UART[uart_num]->conf1.rx_flow_en) { - val |= UART_HW_FLOWCTRL_RTS; - } - if (UART[uart_num]->conf0.tx_flow_en) { - val |= UART_HW_FLOWCTRL_CTS; - } - (*flow_ctrl) = val; - return ESP_OK; -} - -static esp_err_t UART_ISR_ATTR uart_reset_rx_fifo(uart_port_t uart_num) -{ - UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); -#if CONFIG_IDF_TARGET_ESP32 - //Due to hardware issue, we can not use fifo_rst to reset uart fifo. - //See description about UART_TXFIFO_RST and UART_RXFIFO_RST in <> v2.6 or later. - - // we read the data out and make `fifo_len == 0 && rd_addr == wr_addr`. - while (UART[uart_num]->status.rxfifo_cnt != 0 || (UART[uart_num]->mem_rx_status.wr_addr != UART[uart_num]->mem_rx_status.rd_addr)) { - READ_PERI_REG(UART_FIFO_REG(uart_num)); - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - UART[uart_num]->conf0.rxfifo_rst = 1; - UART[uart_num]->conf0.rxfifo_rst = 0; -#endif + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL) + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_get_hw_flow_ctrl(&(uart_context[uart_num].hal), flow_ctrl); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } esp_err_t UART_ISR_ATTR uart_clear_intr_status(uart_port_t uart_num, uint32_t clr_mask) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - //intr_clr register is write-only - UART[uart_num]->int_clr.val = clr_mask; + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), clr_mask); return ESP_OK; } esp_err_t uart_enable_intr_mask(uart_port_t uart_num, uint32_t enable_mask) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask); - SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask); - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), enable_mask); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), enable_mask); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } esp_err_t uart_disable_intr_mask(uart_port_t uart_num, uint32_t disable_mask) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask); - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), disable_mask); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -static void UART_ISR_ATTR uart_disable_intr_mask_from_isr(uart_port_t uart_num, uint32_t disable_mask) -{ - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - CLEAR_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), disable_mask); - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); -} - -static void UART_ISR_ATTR uart_enable_intr_mask_from_isr(uart_port_t uart_num, uint32_t enable_mask) -{ - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - SET_PERI_REG_MASK(UART_INT_CLR_REG(uart_num), enable_mask); - SET_PERI_REG_MASK(UART_INT_ENA_REG(uart_num), enable_mask); - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); -} - static esp_err_t uart_pattern_link_free(uart_port_t uart_num) { - UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); if (p_uart_obj[uart_num]->rx_pattern_pos.data != NULL) { - int *pdata = p_uart_obj[uart_num]->rx_pattern_pos.data; - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + int* pdata = p_uart_obj[uart_num]->rx_pattern_pos.data; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_pattern_pos.data = NULL; p_uart_obj[uart_num]->rx_pattern_pos.wr = 0; p_uart_obj[uart_num]->rx_pattern_pos.rd = 0; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); free(pdata); } return ESP_OK; @@ -411,10 +331,8 @@ static esp_err_t uart_pattern_link_free(uart_port_t uart_num) static esp_err_t UART_ISR_ATTR uart_pattern_enqueue(uart_port_t uart_num, int pos) { - UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); esp_err_t ret = ESP_OK; - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - uart_pat_rb_t *p_pos = &p_uart_obj[uart_num]->rx_pattern_pos; + uart_pat_rb_t* p_pos = &p_uart_obj[uart_num]->rx_pattern_pos; int next = p_pos->wr + 1; if (next >= p_pos->len) { next = 0; @@ -427,19 +345,16 @@ static esp_err_t UART_ISR_ATTR uart_pattern_enqueue(uart_port_t uart_num, int po p_pos->wr = next; ret = ESP_OK; } - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); return ret; } static esp_err_t uart_pattern_dequeue(uart_port_t uart_num) { - UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); - if (p_uart_obj[uart_num]->rx_pattern_pos.data == NULL) { + if(p_uart_obj[uart_num]->rx_pattern_pos.data == NULL) { return ESP_ERR_INVALID_STATE; } else { esp_err_t ret = ESP_OK; - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - uart_pat_rb_t *p_pos = &p_uart_obj[uart_num]->rx_pattern_pos; + uart_pat_rb_t* p_pos = &p_uart_obj[uart_num]->rx_pattern_pos; if (p_pos->rd == p_pos->wr) { ret = ESP_FAIL; } else { @@ -448,18 +363,15 @@ static esp_err_t uart_pattern_dequeue(uart_port_t uart_num) if (p_pos->rd >= p_pos->len) { p_pos->rd = 0; } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); return ret; } } static esp_err_t uart_pattern_queue_update(uart_port_t uart_num, int diff_len) { - UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - uart_pat_rb_t *p_pos = &p_uart_obj[uart_num]->rx_pattern_pos; + uart_pat_rb_t* p_pos = &p_uart_obj[uart_num]->rx_pattern_pos; int rd = p_pos->rd; - while (rd != p_pos->wr) { + while(rd != p_pos->wr) { p_pos->data[rd] -= diff_len; int rd_rec = rd; rd ++; @@ -470,34 +382,33 @@ static esp_err_t uart_pattern_queue_update(uart_port_t uart_num, int diff_len) p_pos->rd = rd; } } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); return ESP_OK; } int uart_pattern_pop_pos(uart_port_t uart_num) { UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - uart_pat_rb_t *pat_pos = &p_uart_obj[uart_num]->rx_pattern_pos; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_pat_rb_t* pat_pos = &p_uart_obj[uart_num]->rx_pattern_pos; int pos = -1; if (pat_pos != NULL && pat_pos->rd != pat_pos->wr) { pos = pat_pos->data[pat_pos->rd]; uart_pattern_dequeue(uart_num); } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return pos; } int uart_pattern_get_pos(uart_port_t uart_num) { UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - uart_pat_rb_t *pat_pos = &p_uart_obj[uart_num]->rx_pattern_pos; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_pat_rb_t* pat_pos = &p_uart_obj[uart_num]->rx_pattern_pos; int pos = -1; if (pat_pos != NULL && pat_pos->rd != pat_pos->wr) { pos = pat_pos->data[pat_pos->rd]; } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return pos; } @@ -506,17 +417,17 @@ esp_err_t uart_pattern_queue_reset(uart_port_t uart_num, int queue_length) UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_STATE); - int *pdata = (int *) malloc(queue_length * sizeof(int)); - if (pdata == NULL) { + int* pdata = (int*) malloc(queue_length * sizeof(int)); + if(pdata == NULL) { return ESP_ERR_NO_MEM; } - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - int *ptmp = p_uart_obj[uart_num]->rx_pattern_pos.data; + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + int* ptmp = p_uart_obj[uart_num]->rx_pattern_pos.data; p_uart_obj[uart_num]->rx_pattern_pos.data = pdata; p_uart_obj[uart_num]->rx_pattern_pos.len = queue_length; p_uart_obj[uart_num]->rx_pattern_pos.rd = 0; p_uart_obj[uart_num]->rx_pattern_pos.wr = 0; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); free(ptmp); return ESP_OK; } @@ -524,17 +435,22 @@ esp_err_t uart_pattern_queue_reset(uart_port_t uart_num, int queue_length) #if CONFIG_IDF_TARGET_ESP32 esp_err_t uart_enable_pattern_det_intr(uart_port_t uart_num, char pattern_chr, uint8_t chr_num, int chr_tout, int post_idle, int pre_idle) { - //This function is deprecated, please use uart_enable_pattern_det_baud_intr instead. UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK(chr_tout >= 0 && chr_tout <= UART_RX_GAP_TOUT_V, "uart pattern set error\n", ESP_FAIL); UART_CHECK(post_idle >= 0 && post_idle <= UART_POST_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL); UART_CHECK(pre_idle >= 0 && pre_idle <= UART_PRE_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL); - UART[uart_num]->at_cmd_char.data = pattern_chr; - UART[uart_num]->at_cmd_char.char_num = chr_num; - UART[uart_num]->at_cmd_gaptout.rx_gap_tout = chr_tout; - UART[uart_num]->at_cmd_postcnt.post_idle_num = post_idle; - UART[uart_num]->at_cmd_precnt.pre_idle_num = pre_idle; - return uart_enable_intr_mask(uart_num, UART_AT_CMD_CHAR_DET_INT_ENA_M); + uart_at_cmd_t at_cmd = {0}; + at_cmd.cmd_char = pattern_chr; + at_cmd.char_num = chr_num; + at_cmd.gap_tout = chr_tout; + at_cmd.pre_idle = pre_idle; + at_cmd.post_idle = post_idle; + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_at_cmd_char(&(uart_context[uart_num].hal), &at_cmd); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + return ESP_OK; } #endif @@ -544,97 +460,87 @@ esp_err_t uart_enable_pattern_det_baud_intr(uart_port_t uart_num, char pattern_c UART_CHECK(chr_tout >= 0 && chr_tout <= UART_RX_GAP_TOUT_V, "uart pattern set error\n", ESP_FAIL); UART_CHECK(post_idle >= 0 && post_idle <= UART_POST_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL); UART_CHECK(pre_idle >= 0 && pre_idle <= UART_PRE_IDLE_NUM_V, "uart pattern set error\n", ESP_FAIL); - UART[uart_num]->at_cmd_char.data = pattern_chr; - UART[uart_num]->at_cmd_char.char_num = chr_num; + uart_at_cmd_t at_cmd = {0}; + at_cmd.cmd_char = pattern_chr; + at_cmd.char_num = chr_num; #if CONFIG_IDF_TARGET_ESP32 int apb_clk_freq = 0; uint32_t uart_baud = 0; uint32_t uart_div = 0; - uart_get_baudrate(uart_num, &uart_baud); apb_clk_freq = esp_clk_apb_freq(); uart_div = apb_clk_freq / uart_baud; - UART[uart_num]->at_cmd_gaptout.rx_gap_tout = chr_tout * uart_div; - UART[uart_num]->at_cmd_postcnt.post_idle_num = post_idle * uart_div; - UART[uart_num]->at_cmd_precnt.pre_idle_num = pre_idle * uart_div; + at_cmd.gap_tout = chr_tout * uart_div; + at_cmd.pre_idle = pre_idle * uart_div; + at_cmd.post_idle = post_idle * uart_div; #elif CONFIG_IDF_TARGET_ESP32S2BETA - UART[uart_num]->at_cmd_gaptout.rx_gap_tout = chr_tout; - UART[uart_num]->at_cmd_postcnt.post_idle_num = post_idle; - UART[uart_num]->at_cmd_precnt.pre_idle_num = pre_idle; + at_cmd.gap_tout = chr_tout; + at_cmd.pre_idle = pre_idle; + at_cmd.post_idle = post_idle; #endif - - return uart_enable_intr_mask(uart_num, UART_AT_CMD_CHAR_DET_INT_ENA_M); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_at_cmd_char(&(uart_context[uart_num].hal), &at_cmd); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + return ESP_OK; } + esp_err_t uart_disable_pattern_det_intr(uart_port_t uart_num) { - return uart_disable_intr_mask(uart_num, UART_AT_CMD_CHAR_DET_INT_ENA_M); + return uart_disable_intr_mask(uart_num, UART_INTR_CMD_CHAR_DET); } esp_err_t uart_enable_rx_intr(uart_port_t uart_num) { - return uart_enable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA); + return uart_enable_intr_mask(uart_num, UART_INTR_RXFIFO_FULL|UART_INTR_RXFIFO_TOUT); } esp_err_t uart_disable_rx_intr(uart_port_t uart_num) { - return uart_disable_intr_mask(uart_num, UART_RXFIFO_FULL_INT_ENA | UART_RXFIFO_TOUT_INT_ENA); + return uart_disable_intr_mask(uart_num, UART_INTR_RXFIFO_FULL|UART_INTR_RXFIFO_TOUT); } esp_err_t uart_disable_tx_intr(uart_port_t uart_num) { - return uart_disable_intr_mask(uart_num, UART_TXFIFO_EMPTY_INT_ENA); + return uart_disable_intr_mask(uart_num, UART_INTR_TXFIFO_EMPTY); } esp_err_t uart_enable_tx_intr(uart_port_t uart_num, int enable, int thresh) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((thresh < UART_FIFO_LEN), "empty intr threshold error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->int_clr.txfifo_empty = 1; - UART[uart_num]->conf1.txfifo_empty_thrhd = thresh & UART_TXFIFO_EMPTY_THRHD_V; - UART[uart_num]->int_ena.txfifo_empty = enable & 0x1; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_txfifo_empty_thr(&(uart_context[uart_num].hal), thresh); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void *), void *arg, int intr_alloc_flags, uart_isr_handle_t *handle) +esp_err_t uart_isr_register(uart_port_t uart_num, void (*fn)(void*), void * arg, int intr_alloc_flags, uart_isr_handle_t *handle) { int ret; UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - switch(uart_num) { - case UART_NUM_1: - ret=esp_intr_alloc(ETS_UART1_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; -#if UART_NUM > 2 - case UART_NUM_2: - ret=esp_intr_alloc(ETS_UART2_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; -#endif - case UART_NUM_0: - default: - ret=esp_intr_alloc(ETS_UART0_INTR_SOURCE, intr_alloc_flags, fn, arg, handle); - break; - } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + ret=esp_intr_alloc(uart_periph_signal[uart_num].irq, intr_alloc_flags, fn, arg, handle); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ret; } - esp_err_t uart_isr_free(uart_port_t uart_num) { esp_err_t ret; UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - if (p_uart_obj[uart_num]->intr_handle == NULL) { - return ESP_ERR_INVALID_ARG; - } - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - ret = esp_intr_free(p_uart_obj[uart_num]->intr_handle); - p_uart_obj[uart_num]->intr_handle = NULL; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); + UART_CHECK((p_uart_obj[uart_num]->intr_handle != NULL), "uart driver error", ESP_ERR_INVALID_ARG); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + ret=esp_intr_free(p_uart_obj[uart_num]->intr_handle); + p_uart_obj[uart_num]->intr_handle=NULL; + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ret; } @@ -648,58 +554,27 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r UART_CHECK((rts_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(rts_io_num))), "rts_io_num error", ESP_FAIL); UART_CHECK((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), "cts_io_num error", ESP_FAIL); - int tx_sig, rx_sig, rts_sig, cts_sig; - switch(uart_num) { - case UART_NUM_0: - tx_sig = U0TXD_OUT_IDX; - rx_sig = U0RXD_IN_IDX; - rts_sig = U0RTS_OUT_IDX; - cts_sig = U0CTS_IN_IDX; - break; - case UART_NUM_1: - tx_sig = U1TXD_OUT_IDX; - rx_sig = U1RXD_IN_IDX; - rts_sig = U1RTS_OUT_IDX; - cts_sig = U1CTS_IN_IDX; - break; -#if UART_NUM > 2 - case UART_NUM_2: - tx_sig = U2TXD_OUT_IDX; - rx_sig = U2RXD_IN_IDX; - rts_sig = U2RTS_OUT_IDX; - cts_sig = U2CTS_IN_IDX; - break; -#endif - case UART_NUM_MAX: - default: - tx_sig = U0TXD_OUT_IDX; - rx_sig = U0RXD_IN_IDX; - rts_sig = U0RTS_OUT_IDX; - cts_sig = U0CTS_IN_IDX; - break; - } - if (tx_io_num >= 0) { + if(tx_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); gpio_set_level(tx_io_num, 1); - gpio_matrix_out(tx_io_num, tx_sig, 0, 0); + gpio_matrix_out(tx_io_num, uart_periph_signal[uart_num].tx_sig, 0, 0); } - - if (rx_io_num >= 0) { + if(rx_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO); gpio_set_pull_mode(rx_io_num, GPIO_PULLUP_ONLY); gpio_set_direction(rx_io_num, GPIO_MODE_INPUT); - gpio_matrix_in(rx_io_num, rx_sig, 0); + gpio_matrix_in(rx_io_num, uart_periph_signal[uart_num].rx_sig, 0); } - if (rts_io_num >= 0) { + if(rts_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[rts_io_num], PIN_FUNC_GPIO); gpio_set_direction(rts_io_num, GPIO_MODE_OUTPUT); - gpio_matrix_out(rts_io_num, rts_sig, 0, 0); + gpio_matrix_out(rts_io_num, uart_periph_signal[uart_num].rts_sig, 0, 0); } - if (cts_io_num >= 0) { + if(cts_io_num >= 0) { PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO); gpio_set_pull_mode(cts_io_num, GPIO_PULLUP_ONLY); gpio_set_direction(cts_io_num, GPIO_MODE_INPUT); - gpio_matrix_in(cts_io_num, cts_sig, 0); + gpio_matrix_in(cts_io_num, uart_periph_signal[uart_num].cts_sig, 0); } return ESP_OK; } @@ -707,19 +582,19 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r esp_err_t uart_set_rts(uart_port_t uart_num, int level) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), "disable hw flowctrl before using sw control", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->conf0.sw_rts = level & 0x1; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_CHECK((!uart_hal_is_hw_rts_en(&(uart_context[uart_num].hal))), "disable hw flowctrl before using sw control", ESP_FAIL); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_rts(&(uart_context[uart_num].hal), level); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } esp_err_t uart_set_dtr(uart_port_t uart_num, int level) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->conf0.sw_dtr = level & 0x1; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_dtr(&(uart_context[uart_num].hal), level); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } @@ -727,102 +602,57 @@ esp_err_t uart_set_tx_idle_num(uart_port_t uart_num, uint16_t idle_num) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((idle_num <= UART_TX_IDLE_NUM_V), "uart idle num error", ESP_FAIL); - - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->idle_conf.tx_idle_num = idle_num; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_tx_idle_num(&(uart_context[uart_num].hal), idle_num); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -static periph_module_t get_periph_module(uart_port_t uart_num) -{ - periph_module_t periph_module = PERIPH_UART0_MODULE; - if (uart_num == UART_NUM_0) { - periph_module = PERIPH_UART0_MODULE; - } else if (uart_num == UART_NUM_1) { - periph_module = PERIPH_UART1_MODULE; - } -#if SOC_UART_NUM > 2 - else if (uart_num == UART_NUM_2) { - periph_module = PERIPH_UART2_MODULE; - } -#endif - else { - assert(0 && "uart_num error"); - } - return periph_module; -} - esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config) { - esp_err_t r; UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((uart_config), "param null", ESP_FAIL); - periph_module_t periph_module = get_periph_module(uart_num); - if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) { - periph_module_reset(periph_module); - } - periph_module_enable(periph_module); - r = uart_set_hw_flow_ctrl(uart_num, uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh); - if (r != ESP_OK) { - return r; - } - - UART[uart_num]->conf0.val = - (uart_config->parity << UART_PARITY_S) - | (uart_config->data_bits << UART_BIT_NUM_S) - | ((uart_config->flow_ctrl & UART_HW_FLOWCTRL_CTS) ? UART_TX_FLOW_EN : 0x0) - | (uart_config->use_ref_tick ? 0 : UART_TICK_REF_ALWAYS_ON_M); - - r = uart_set_baudrate(uart_num, uart_config->baud_rate); - if (r != ESP_OK) { - return r; - } - r = uart_set_tx_idle_num(uart_num, UART_TX_IDLE_NUM_DEFAULT); - if (r != ESP_OK) { - return r; - } - r = uart_set_stop_bits(uart_num, uart_config->stop_bits); - //A hardware reset does not reset the fifo, - //so we need to reset the fifo manually. - uart_reset_rx_fifo(uart_num); - return r; + UART_CHECK((uart_config->rx_flow_ctrl_thresh < UART_FIFO_LEN), "rx flow thresh error", ESP_FAIL); + UART_CHECK((uart_config->flow_ctrl < UART_HW_FLOWCTRL_MAX), "hw_flowctrl mode error", ESP_FAIL); + UART_CHECK((uart_config->data_bits < UART_DATA_BITS_MAX), "data bit error", ESP_FAIL); + uart_module_enable(uart_num); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_init(&(uart_context[uart_num].hal), uart_num); + uart_hal_set_baudrate(&(uart_context[uart_num].hal), uart_config->source_clk, uart_config->baud_rate); + uart_hal_set_parity(&(uart_context[uart_num].hal), uart_config->parity); + uart_hal_set_data_bit_num(&(uart_context[uart_num].hal), uart_config->data_bits); + uart_hal_set_stop_bits(&(uart_context[uart_num].hal), uart_config->stop_bits); + uart_hal_set_tx_idle_num(&(uart_context[uart_num].hal), UART_TX_IDLE_NUM_DEFAULT); + uart_hal_set_hw_flow_ctrl(&(uart_context[uart_num].hal), uart_config->flow_ctrl, uart_config->rx_flow_ctrl_thresh); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_rxfifo_rst(&(uart_context[uart_num].hal)); + return ESP_OK; } esp_err_t uart_intr_config(uart_port_t uart_num, const uart_intr_config_t *intr_conf) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((intr_conf), "param null", ESP_FAIL); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->int_clr.val = UART_INTR_MASK; - if (intr_conf->intr_enable_mask & UART_RXFIFO_TOUT_INT_ENA_M) { -#if CONFIG_IDF_TARGET_ESP32 - //Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. - //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) - if(UART[uart_num]->conf0.tick_ref_always_on == 0) { - UART[uart_num]->conf1.rx_tout_thrhd = (intr_conf->rx_timeout_thresh * UART_TOUT_REF_FACTOR_DEFAULT); - } else { - UART[uart_num]->conf1.rx_tout_thrhd = intr_conf->rx_timeout_thresh; - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - UART[uart_num]->mem_conf.rx_tout_thrhd = ((intr_conf->rx_timeout_thresh) & UART_RX_TOUT_THRHD_V); -#endif - UART[uart_num]->conf1.rx_tout_en = 1; + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_MASK); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + if(intr_conf->intr_enable_mask & UART_INTR_RXFIFO_TOUT) { + uart_hal_set_rx_timeout(&(uart_context[uart_num].hal), intr_conf->rx_timeout_thresh); } else { - UART[uart_num]->conf1.rx_tout_en = 0; + //Disable rx_tout intr + uart_hal_set_rx_timeout(&(uart_context[uart_num].hal), 0); } - if (intr_conf->intr_enable_mask & UART_RXFIFO_FULL_INT_ENA_M) { - UART[uart_num]->conf1.rxfifo_full_thrhd = intr_conf->rxfifo_full_thresh; + if(intr_conf->intr_enable_mask & UART_INTR_RXFIFO_FULL) { + uart_hal_set_rxfifo_full_thr(&(uart_context[uart_num].hal), intr_conf->rxfifo_full_thresh); } - if (intr_conf->intr_enable_mask & UART_TXFIFO_EMPTY_INT_ENA_M) { - UART[uart_num]->conf1.txfifo_empty_thrhd = intr_conf->txfifo_empty_intr_thresh; + if(intr_conf->intr_enable_mask & UART_INTR_TXFIFO_EMPTY) { + uart_hal_set_txfifo_empty_thr(&(uart_context[uart_num].hal), intr_conf->txfifo_empty_intr_thresh); } - UART[uart_num]->int_ena.val = intr_conf->intr_enable_mask; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), intr_conf->intr_enable_mask); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -static int UART_ISR_ATTR uart_find_pattern_from_last(uint8_t* buf, int length, uint8_t pat_chr, int pat_num) +static int UART_ISR_ATTR uart_find_pattern_from_last(uint8_t* buf, int length, uint8_t pat_chr, uint8_t pat_num) { int cnt = 0; int len = length; @@ -843,62 +673,63 @@ static int UART_ISR_ATTR uart_find_pattern_from_last(uint8_t* buf, int length, u //internal isr handler for default driver code. static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) { - uart_obj_t *p_uart = (uart_obj_t *) param; + uart_obj_t *p_uart = (uart_obj_t*) param; uint8_t uart_num = p_uart->uart_num; - uart_dev_t *uart_reg = UART[uart_num]; int rx_fifo_len = 0; - uint8_t buf_idx = 0; uint32_t uart_intr_status = 0; uart_event_t uart_event; portBASE_TYPE HPTaskAwoken = 0; static uint8_t pat_flg = 0; while(1) { - uart_intr_status = uart_reg->int_st.val; // The `continue statement` may cause the interrupt to loop infinitely // we exit the interrupt here - if(uart_intr_status == 0) { + uart_intr_status = uart_hal_get_intsts_mask(&(uart_context[uart_num].hal)); + //Exit form while loop + if(uart_intr_status == 0){ break; } uart_event.type = UART_EVENT_MAX; - if (uart_intr_status & UART_TXFIFO_EMPTY_INT_ST_M) { - uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M); - uart_disable_intr_mask_from_isr(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M); - if (p_uart->tx_waiting_brk) { + if(uart_intr_status & UART_INTR_TXFIFO_EMPTY) { + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); + if(p_uart->tx_waiting_brk) { continue; } //TX semaphore will only be used when tx_buf_size is zero. - if (p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) { + if(p_uart->tx_waiting_fifo == true && p_uart->tx_buf_size == 0) { p_uart->tx_waiting_fifo = false; xSemaphoreGiveFromISR(p_uart->tx_fifo_sem, &HPTaskAwoken); } else { //We don't use TX ring buffer, because the size is zero. - if (p_uart->tx_buf_size == 0) { + if(p_uart->tx_buf_size == 0) { continue; } - int tx_fifo_rem = UART_FIFO_LEN - uart_reg->status.txfifo_cnt; bool en_tx_flg = false; + int tx_fifo_rem = uart_hal_get_txfifo_len(&(uart_context[uart_num].hal)); //We need to put a loop here, in case all the buffer items are very short. //That would cause a watch_dog reset because empty interrupt happens so often. //Although this is a loop in ISR, this loop will execute at most 128 turns. - while (tx_fifo_rem) { - if (p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) { + while(tx_fifo_rem) { + if(p_uart->tx_len_tot == 0 || p_uart->tx_ptr == NULL || p_uart->tx_len_cur == 0) { size_t size; - p_uart->tx_head = (uart_tx_data_t *) xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size); - if (p_uart->tx_head) { + p_uart->tx_head = (uart_tx_data_t*) xRingbufferReceiveFromISR(p_uart->tx_ring_buf, &size); + if(p_uart->tx_head) { //The first item is the data description //Get the first item to get the data information - if (p_uart->tx_len_tot == 0) { + if(p_uart->tx_len_tot == 0) { p_uart->tx_ptr = NULL; p_uart->tx_len_tot = p_uart->tx_head->tx_data.size; - if (p_uart->tx_head->type == UART_DATA_BREAK) { + if(p_uart->tx_head->type == UART_DATA_BREAK) { p_uart->tx_brk_flg = 1; p_uart->tx_brk_len = p_uart->tx_head->tx_data.brk_len; } //We have saved the data description from the 1st item, return buffer. vRingbufferReturnItemFromISR(p_uart->tx_ring_buf, p_uart->tx_head, &HPTaskAwoken); - }else if(p_uart->tx_ptr == NULL) { + } else if(p_uart->tx_ptr == NULL) { //Update the TX item pointer, we will need this to return item to buffer. - p_uart->tx_ptr = (uint8_t *) p_uart->tx_head; + p_uart->tx_ptr = (uint8_t*)p_uart->tx_head; en_tx_flg = true; p_uart->tx_len_cur = size; } @@ -909,18 +740,19 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) } if (p_uart->tx_len_tot > 0 && p_uart->tx_ptr && p_uart->tx_len_cur > 0) { //To fill the TX FIFO. - int send_len = p_uart->tx_len_cur > tx_fifo_rem ? tx_fifo_rem : p_uart->tx_len_cur; + uint32_t send_len = 0; // Set RS485 RTS pin before transmission if the half duplex mode is enabled if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - uart_reg->conf0.sw_rts = 0; - uart_reg->int_ena.tx_done = 1; - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); - } - for (buf_idx = 0; buf_idx < send_len; buf_idx++) { - WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), - *(p_uart->tx_ptr++) & 0xff); + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_set_rts(&(uart_context[uart_num].hal), 0); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); } + uart_hal_write_txfifo(&(uart_context[uart_num].hal), + (const uint8_t *)p_uart->tx_ptr, + (p_uart->tx_len_cur > tx_fifo_rem) ? tx_fifo_rem : p_uart->tx_len_cur, + &send_len); + p_uart->tx_ptr += send_len; p_uart->tx_len_tot -= send_len; p_uart->tx_len_cur -= send_len; tx_fifo_rem -= send_len; @@ -931,14 +763,12 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) p_uart->tx_ptr = NULL; //Sending item done, now we need to send break if there is a record. //Set TX break signal after FIFO is empty - if (p_uart->tx_len_tot == 0 && p_uart->tx_brk_flg == 1) { - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - uart_reg->int_ena.tx_brk_done = 0; - uart_reg->idle_conf.tx_brk_num = p_uart->tx_brk_len; - uart_reg->conf0.txd_brk = 1; - uart_reg->int_clr.tx_brk_done = 1; - uart_reg->int_ena.tx_brk_done = 1; - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + if(p_uart->tx_len_tot == 0 && p_uart->tx_brk_flg == 1) { + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE); + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_tx_break(&(uart_context[uart_num].hal), p_uart->tx_brk_len); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); p_uart->tx_waiting_brk = 1; //do not enable TX empty interrupt en_tx_flg = false; @@ -953,41 +783,37 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) } } if (en_tx_flg) { - uart_clear_intr_status(uart_num, UART_TXFIFO_EMPTY_INT_CLR_M); - uart_enable_intr_mask_from_isr(uart_num, UART_TXFIFO_EMPTY_INT_ENA_M); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); } } - } else if ((uart_intr_status & UART_RXFIFO_TOUT_INT_ST_M) - || (uart_intr_status & UART_RXFIFO_FULL_INT_ST_M) - || (uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) - ) { - rx_fifo_len = uart_reg->status.rxfifo_cnt; - if (pat_flg == 1) { - uart_intr_status |= UART_AT_CMD_CHAR_DET_INT_ST_M; + } + else if ((uart_intr_status & UART_INTR_RXFIFO_TOUT) + || (uart_intr_status & UART_INTR_RXFIFO_FULL) + || (uart_intr_status & UART_INTR_CMD_CHAR_DET) + ) { + if(pat_flg == 1) { + uart_intr_status |= UART_INTR_CMD_CHAR_DET; pat_flg = 0; } if (p_uart->rx_buffer_full_flg == false) { - //We have to read out all data in RX FIFO to clear the interrupt signal - for(buf_idx = 0; buf_idx < rx_fifo_len; buf_idx++) { -#if CONFIG_IDF_TARGET_ESP32 - p_uart->rx_data_buf[buf_idx] = uart_reg->fifo.rw_byte; -#elif CONFIG_IDF_TARGET_ESP32S2BETA - p_uart->rx_data_buf[buf_idx] = READ_PERI_REG(UART_FIFO_AHB_REG(uart_num)); -#endif - } - uint8_t pat_chr = uart_reg->at_cmd_char.data; - int pat_num = uart_reg->at_cmd_char.char_num; + uart_hal_read_rxfifo(&(uart_context[uart_num].hal), p_uart->rx_data_buf, &rx_fifo_len); + uint8_t pat_chr = 0; + uint8_t pat_num = 0; int pat_idx = -1; + uart_hal_get_at_cmd_char(&(uart_context[uart_num].hal), &pat_chr, &pat_num); //Get the buffer from the FIFO - if (uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) { - uart_clear_intr_status(uart_num, UART_AT_CMD_CHAR_DET_INT_CLR_M); + if (uart_intr_status & UART_INTR_CMD_CHAR_DET) { + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET); uart_event.type = UART_PATTERN_DET; uart_event.size = rx_fifo_len; pat_idx = uart_find_pattern_from_last(p_uart->rx_data_buf, rx_fifo_len - 1, pat_chr, pat_num); } else { //After Copying the Data From FIFO ,Clear intr_status - uart_clear_intr_status(uart_num, UART_RXFIFO_TOUT_INT_CLR_M | UART_RXFIFO_FULL_INT_CLR_M); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_FULL); uart_event.type = UART_DATA; uart_event.size = rx_fifo_len; UART_ENTER_CRITICAL_ISR(&uart_selectlock); @@ -999,131 +825,144 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) p_uart->rx_stash_len = rx_fifo_len; //If we fail to push data to ring buffer, we will have to stash the data, and send next time. //Mainly for applications that uses flow control or small ring buffer. - if (pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) { + if(pdFALSE == xRingbufferSendFromISR(p_uart->rx_ring_buf, p_uart->rx_data_buf, p_uart->rx_stash_len, &HPTaskAwoken)) { p_uart->rx_buffer_full_flg = true; - uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_TOUT_INT_ENA_M | UART_RXFIFO_FULL_INT_ENA_M); + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_FULL); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); if (uart_event.type == UART_PATTERN_DET) { + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); if (rx_fifo_len < pat_num) { //some of the characters are read out in last interrupt uart_pattern_enqueue(uart_num, p_uart->rx_buffered_len - (pat_num - rx_fifo_len)); } else { uart_pattern_enqueue(uart_num, - pat_idx <= -1 ? - //can not find the pattern in buffer, - p_uart->rx_buffered_len + p_uart->rx_stash_len : - // find the pattern in buffer - p_uart->rx_buffered_len + pat_idx); + pat_idx <= -1 ? + //can not find the pattern in buffer, + p_uart->rx_buffered_len + p_uart->rx_stash_len : + // find the pattern in buffer + p_uart->rx_buffered_len + pat_idx); } + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); if ((p_uart->xQueueUart != NULL) && (pdFALSE == xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken))) { ESP_EARLY_LOGV(UART_TAG, "UART event queue full"); } } uart_event.type = UART_BUFFER_FULL; } else { - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - if (uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) { + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + if (uart_intr_status & UART_INTR_CMD_CHAR_DET) { if (rx_fifo_len < pat_num) { //some of the characters are read out in last interrupt uart_pattern_enqueue(uart_num, p_uart->rx_buffered_len - (pat_num - rx_fifo_len)); - } else if (pat_idx >= 0) { - // find pattern in statsh buffer. + } else if(pat_idx >= 0) { + // find the pattern in stash buffer. uart_pattern_enqueue(uart_num, p_uart->rx_buffered_len + pat_idx); } } p_uart->rx_buffered_len += p_uart->rx_stash_len; - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); } } else { - uart_disable_intr_mask_from_isr(uart_num, UART_RXFIFO_FULL_INT_ENA_M | UART_RXFIFO_TOUT_INT_ENA_M); - uart_clear_intr_status(uart_num, UART_RXFIFO_FULL_INT_CLR_M | UART_RXFIFO_TOUT_INT_CLR_M); - if (uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) { - uart_reg->int_clr.at_cmd_char_det = 1; + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT); + if(uart_intr_status & UART_INTR_CMD_CHAR_DET) { + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET); uart_event.type = UART_PATTERN_DET; uart_event.size = rx_fifo_len; pat_flg = 1; } } - } else if (uart_intr_status & UART_RXFIFO_OVF_INT_ST_M) { + } else if(uart_intr_status & UART_INTR_RXFIFO_OVF) { // When fifo overflows, we reset the fifo. - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - uart_reset_rx_fifo(uart_num); - uart_reg->int_clr.rxfifo_ovf = 1; - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_rxfifo_rst(&(uart_context[uart_num].hal)); + if (p_uart->uart_select_notif_callback) { + p_uart->uart_select_notif_callback(uart_num, UART_SELECT_ERROR_NOTIF, &HPTaskAwoken); + } + UART_EXIT_CRITICAL_ISR(&uart_selectlock); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_OVF); uart_event.type = UART_FIFO_OVF; - UART_ENTER_CRITICAL_ISR(&uart_selectlock); - if (p_uart->uart_select_notif_callback) { - p_uart->uart_select_notif_callback(uart_num, UART_SELECT_ERROR_NOTIF, &HPTaskAwoken); - } - UART_EXIT_CRITICAL_ISR(&uart_selectlock); - } else if (uart_intr_status & UART_BRK_DET_INT_ST_M) { - uart_reg->int_clr.brk_det = 1; + } else if(uart_intr_status & UART_INTR_BRK_DET) { + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_BRK_DET); uart_event.type = UART_BREAK; - } else if (uart_intr_status & UART_FRM_ERR_INT_ST_M) { - uart_reg->int_clr.frm_err = 1; + } else if(uart_intr_status & UART_INTR_FRAM_ERR) { + UART_ENTER_CRITICAL_ISR(&uart_selectlock); + if (p_uart->uart_select_notif_callback) { + p_uart->uart_select_notif_callback(uart_num, UART_SELECT_ERROR_NOTIF, &HPTaskAwoken); + } + UART_EXIT_CRITICAL_ISR(&uart_selectlock); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_FRAM_ERR); uart_event.type = UART_FRAME_ERR; + } else if(uart_intr_status & UART_INTR_PARITY_ERR) { UART_ENTER_CRITICAL_ISR(&uart_selectlock); if (p_uart->uart_select_notif_callback) { p_uart->uart_select_notif_callback(uart_num, UART_SELECT_ERROR_NOTIF, &HPTaskAwoken); } UART_EXIT_CRITICAL_ISR(&uart_selectlock); - } else if (uart_intr_status & UART_PARITY_ERR_INT_ST_M) { - uart_reg->int_clr.parity_err = 1; + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_PARITY_ERR); uart_event.type = UART_PARITY_ERR; - UART_ENTER_CRITICAL_ISR(&uart_selectlock); - if (p_uart->uart_select_notif_callback) { - p_uart->uart_select_notif_callback(uart_num, UART_SELECT_ERROR_NOTIF, &HPTaskAwoken); + } else if(uart_intr_status & UART_INTR_TX_BRK_DONE) { + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_tx_break(&(uart_context[uart_num].hal), 0); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE); + if(p_uart->tx_brk_flg == 1) { + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TXFIFO_EMPTY); } - UART_EXIT_CRITICAL_ISR(&uart_selectlock); - } else if (uart_intr_status & UART_TX_BRK_DONE_INT_ST_M) { - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - uart_reg->conf0.txd_brk = 0; - uart_reg->int_ena.tx_brk_done = 0; - uart_reg->int_clr.tx_brk_done = 1; - if (p_uart->tx_brk_flg == 1) { - uart_reg->int_ena.txfifo_empty = 1; - } - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); - if (p_uart->tx_brk_flg == 1) { + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE); + if(p_uart->tx_brk_flg == 1) { p_uart->tx_brk_flg = 0; p_uart->tx_waiting_brk = 0; } else { xSemaphoreGiveFromISR(p_uart->tx_brk_sem, &HPTaskAwoken); } - } else if (uart_intr_status & UART_TX_BRK_IDLE_DONE_INT_ST_M) { - uart_disable_intr_mask_from_isr(uart_num, UART_TX_BRK_IDLE_DONE_INT_ENA_M); - uart_clear_intr_status(uart_num, UART_TX_BRK_IDLE_DONE_INT_CLR_M); - } else if (uart_intr_status & UART_AT_CMD_CHAR_DET_INT_ST_M) { - uart_reg->int_clr.at_cmd_char_det = 1; + } else if(uart_intr_status & UART_INTR_TX_BRK_IDLE) { + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_IDLE); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_IDLE); + } else if(uart_intr_status & UART_INTR_CMD_CHAR_DET) { + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_CMD_CHAR_DET); uart_event.type = UART_PATTERN_DET; - } else if ((uart_intr_status & UART_RS485_CLASH_INT_ST_M) - || (uart_intr_status & UART_RS485_FRM_ERR_INT_ENA) - || (uart_intr_status & UART_RS485_PARITY_ERR_INT_ENA)) { + } else if ((uart_intr_status & UART_INTR_RS485_PARITY_ERR) + || (uart_intr_status & UART_INTR_RS485_FRM_ERR) + || (uart_intr_status & UART_INTR_RS485_CLASH)) { // RS485 collision or frame error interrupt triggered - uart_clear_intr_status(uart_num, UART_RS485_CLASH_INT_CLR_M); - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - uart_reset_rx_fifo(uart_num); + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_rxfifo_rst(&(uart_context[uart_num].hal)); // Set collision detection flag p_uart_obj[uart_num]->coll_det_flg = true; - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_RS485_CLASH | UART_INTR_RS485_FRM_ERR | UART_INTR_RS485_PARITY_ERR); uart_event.type = UART_EVENT_MAX; - } else if (uart_intr_status & UART_TX_DONE_INT_ST_M) { - uart_disable_intr_mask_from_isr(uart_num, UART_TX_DONE_INT_ENA_M); - uart_clear_intr_status(uart_num, UART_TX_DONE_INT_CLR_M); - // If RS485 half duplex mode is enable then reset FIFO and - // reset RTS pin to start receiver driver - if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART_ENTER_CRITICAL_ISR(&uart_spinlock[uart_num]); - uart_reset_rx_fifo(uart_num); // Allows to avoid hardware issue with the RXFIFO reset - uart_reg->conf0.sw_rts = 1; - UART_EXIT_CRITICAL_ISR(&uart_spinlock[uart_num]); + } else if(uart_intr_status & UART_INTR_TX_DONE) { + if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX) && uart_hal_is_tx_idle(&(uart_context[uart_num].hal)) != true) { + // The TX_DONE interrupt is triggered but transmit is active + // then postpone interrupt processing for next interrupt + uart_event.type = UART_EVENT_MAX; + } else { + // Workaround for RS485: If the RS485 half duplex mode is active + // and transmitter is in idle state then reset received buffer and reset RTS pin + // skip this behavior for other UART modes + UART_ENTER_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { + uart_hal_rxfifo_rst(&(uart_context[uart_num].hal)); + uart_hal_set_rts(&(uart_context[uart_num].hal), 1); + } + UART_EXIT_CRITICAL_ISR(&(uart_context[uart_num].spinlock)); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); } - xSemaphoreGiveFromISR(p_uart_obj[uart_num]->tx_done_sem, &HPTaskAwoken); } else { - uart_reg->int_clr.val = uart_intr_status; /*simply clear all other intr status*/ + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), uart_intr_status); /*simply clear all other intr status*/ uart_event.type = UART_EVENT_MAX; } - if (uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) { + if(uart_event.type != UART_EVENT_MAX && p_uart->xQueueUart) { if (pdFALSE == xQueueSendFromISR(p_uart->xQueueUart, (void * )&uart_event, &HPTaskAwoken)) { ESP_EARLY_LOGV(UART_TAG, "UART event queue full"); } @@ -1143,21 +982,18 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) portTickType ticks_start = xTaskGetTickCount(); //Take tx_mux res = xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)ticks_to_wait); - if (res == pdFALSE) { + if(res == pdFALSE) { return ESP_ERR_TIMEOUT; } xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, 0); - typeof(UART0.status) status = UART[uart_num]->status; - //Wait txfifo_cnt = 0, and the transmitter state machine is in idle state. -#ifdef CONFIG_IDF_TARGET_ESP32 - if (status.txfifo_cnt == 0 && status.st_utx_out == 0) { -#else /* TODO: check transmitter state machine on ESP32S2Beta */ - if (status.txfifo_cnt == 0) { -#endif + if(uart_hal_is_tx_idle(&(uart_context[uart_num].hal))) { xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); return ESP_OK; } - uart_enable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); TickType_t ticks_end = xTaskGetTickCount(); if (ticks_end - ticks_start > ticks_to_wait) { @@ -1167,62 +1003,40 @@ esp_err_t uart_wait_tx_done(uart_port_t uart_num, TickType_t ticks_to_wait) } //take 2nd tx_done_sem, wait given from ISR res = xSemaphoreTake(p_uart_obj[uart_num]->tx_done_sem, (portTickType)ticks_to_wait); - if (res == pdFALSE) { - uart_disable_intr_mask(uart_num, UART_TX_DONE_INT_ENA_M); + if(res == pdFALSE) { + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); - return ESP_ERR_TIMEOUT; } xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); return ESP_OK; } -static esp_err_t uart_set_break(uart_port_t uart_num, int break_num) -{ - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->idle_conf.tx_brk_num = break_num; - UART[uart_num]->conf0.txd_brk = 1; - UART[uart_num]->int_clr.tx_brk_done = 1; - UART[uart_num]->int_ena.tx_brk_done = 1; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); - return ESP_OK; -} - -//Fill UART tx_fifo and return a number, -//This function by itself is not thread-safe, always call from within a muxed section. -static int uart_fill_fifo(uart_port_t uart_num, const char *buffer, uint32_t len) -{ - uint8_t i = 0; - uint8_t tx_fifo_cnt = UART[uart_num]->status.txfifo_cnt; - uint8_t tx_remain_fifo_cnt = (UART_FIFO_LEN - tx_fifo_cnt); - uint8_t copy_cnt = (len >= tx_remain_fifo_cnt ? tx_remain_fifo_cnt : len); - // Set the RTS pin if RS485 mode is enabled - if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { - UART[uart_num]->conf0.sw_rts = 0; - UART[uart_num]->int_ena.tx_done = 1; - } - for (i = 0; i < copy_cnt; i++) { - WRITE_PERI_REG(UART_FIFO_AHB_REG(uart_num), buffer[i]); - } - return copy_cnt; -} - -int uart_tx_chars(uart_port_t uart_num, const char *buffer, uint32_t len) +int uart_tx_chars(uart_port_t uart_num, const char* buffer, uint32_t len) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); UART_CHECK(buffer, "buffer null", (-1)); - if (len == 0) { + if(len == 0) { return 0; } + int tx_len = 0; xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY); - int tx_len = uart_fill_fifo(uart_num, (const char *) buffer, len); + if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_rts(&(uart_context[uart_num].hal), 0); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + } + uart_hal_write_txfifo(&(uart_context[uart_num].hal), (const uint8_t*) buffer, len, (uint32_t *)&tx_len); xSemaphoreGive(p_uart_obj[uart_num]->tx_mux); return tx_len; } -static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool brk_en, int brk_len) +static int uart_tx_all(uart_port_t uart_num, const char* src, size_t size, bool brk_en, int brk_len) { - if (size == 0) { + if(size == 0) { return 0; } size_t original_size = size; @@ -1230,31 +1044,38 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool //lock for uart_tx xSemaphoreTake(p_uart_obj[uart_num]->tx_mux, (portTickType)portMAX_DELAY); p_uart_obj[uart_num]->coll_det_flg = false; - if (p_uart_obj[uart_num]->tx_buf_size > 0) { + if(p_uart_obj[uart_num]->tx_buf_size > 0) { int max_size = xRingbufferGetMaxItemSize(p_uart_obj[uart_num]->tx_ring_buf); int offset = 0; uart_tx_data_t evt; evt.tx_data.size = size; evt.tx_data.brk_len = brk_len; - if (brk_en) { + if(brk_en) { evt.type = UART_DATA_BREAK; } else { evt.type = UART_DATA; } - xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void *) &evt, sizeof(uart_tx_data_t), portMAX_DELAY); - while (size > 0) { + xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) &evt, sizeof(uart_tx_data_t), portMAX_DELAY); + while(size > 0) { int send_size = size > max_size / 2 ? max_size / 2 : size; - xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void *) (src + offset), send_size, portMAX_DELAY); + xRingbufferSend(p_uart_obj[uart_num]->tx_ring_buf, (void*) (src + offset), send_size, portMAX_DELAY); size -= send_size; offset += send_size; uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT); } } else { - while (size) { + while(size) { //semaphore for tx_fifo available - if (pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) { - size_t sent = uart_fill_fifo(uart_num, (char *) src, size); - if (sent < size) { + if(pdTRUE == xSemaphoreTake(p_uart_obj[uart_num]->tx_fifo_sem, (portTickType)portMAX_DELAY)) { + uint32_t sent = 0; + if (UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX)) { + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_rts(&(uart_context[uart_num].hal), 0); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_DONE); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); + } + uart_hal_write_txfifo(&(uart_context[uart_num].hal), (const uint8_t*)src, size, &sent); + if(sent < size) { p_uart_obj[uart_num]->tx_waiting_fifo = true; uart_enable_tx_intr(uart_num, 1, UART_EMPTY_THRESH_DEFAULT); } @@ -1262,8 +1083,12 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool src += sent; } } - if (brk_en) { - uart_set_break(uart_num, brk_len); + if(brk_en) { + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_tx_break(&(uart_context[uart_num].hal), brk_len); + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_TX_BRK_DONE); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); xSemaphoreTake(p_uart_obj[uart_num]->tx_brk_sem, (portTickType)portMAX_DELAY); } xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem); @@ -1272,7 +1097,7 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool return original_size; } -int uart_write_bytes(uart_port_t uart_num, const char *src, size_t size) +int uart_write_bytes(uart_port_t uart_num, const char* src, size_t size) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); UART_CHECK((p_uart_obj[uart_num] != NULL), "uart driver error", (-1)); @@ -1280,7 +1105,7 @@ int uart_write_bytes(uart_port_t uart_num, const char *src, size_t size) return uart_tx_all(uart_num, src, size, 0, 0); } -int uart_write_bytes_with_break(uart_port_t uart_num, const char *src, size_t size, int brk_len) +int uart_write_bytes_with_break(uart_port_t uart_num, const char* src, size_t size, int brk_len) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); @@ -1292,13 +1117,13 @@ int uart_write_bytes_with_break(uart_port_t uart_num, const char *src, size_t si static bool uart_check_buf_full(uart_port_t uart_num) { - if (p_uart_obj[uart_num]->rx_buffer_full_flg) { + if(p_uart_obj[uart_num]->rx_buffer_full_flg) { BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1); - if (res == pdTRUE) { - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + if(res == pdTRUE) { + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len; p_uart_obj[uart_num]->rx_buffer_full_flg = false; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num); return true; } @@ -1306,22 +1131,22 @@ static bool uart_check_buf_full(uart_port_t uart_num) return false; } -int uart_read_bytes(uart_port_t uart_num, uint8_t *buf, uint32_t length, TickType_t ticks_to_wait) +int uart_read_bytes(uart_port_t uart_num, uint8_t* buf, uint32_t length, TickType_t ticks_to_wait) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", (-1)); UART_CHECK((buf), "uart data null", (-1)); UART_CHECK((p_uart_obj[uart_num]), "uart driver error", (-1)); - uint8_t *data = NULL; + uint8_t* data = NULL; size_t size; size_t copy_len = 0; int len_tmp; - if (xSemaphoreTake(p_uart_obj[uart_num]->rx_mux, (portTickType)ticks_to_wait) != pdTRUE) { + if(xSemaphoreTake(p_uart_obj[uart_num]->rx_mux,(portTickType)ticks_to_wait) != pdTRUE) { return -1; } - while (length) { - if (p_uart_obj[uart_num]->rx_cur_remain == 0) { - data = (uint8_t *) xRingbufferReceive(p_uart_obj[uart_num]->rx_ring_buf, &size, (portTickType) ticks_to_wait); - if (data) { + while(length) { + if(p_uart_obj[uart_num]->rx_cur_remain == 0) { + data = (uint8_t*) xRingbufferReceive(p_uart_obj[uart_num]->rx_ring_buf, &size, (portTickType) ticks_to_wait); + if(data) { p_uart_obj[uart_num]->rx_head_ptr = data; p_uart_obj[uart_num]->rx_ptr = data; p_uart_obj[uart_num]->rx_cur_remain = size; @@ -1329,7 +1154,7 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t *buf, uint32_t length, TickTyp //When using dual cores, `rx_buffer_full_flg` may read and write on different cores at same time, //which may lose synchronization. So we also need to call `uart_check_buf_full` once when ringbuffer is empty //to solve the possible asynchronous issues. - if (uart_check_buf_full(uart_num)) { + if(uart_check_buf_full(uart_num)) { //This condition will never be true if `uart_read_bytes` //and `uart_rx_intr_handler_default` are scheduled on the same core. continue; @@ -1339,21 +1164,21 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t *buf, uint32_t length, TickTyp } } } - if (p_uart_obj[uart_num]->rx_cur_remain > length) { + if(p_uart_obj[uart_num]->rx_cur_remain > length) { len_tmp = length; } else { len_tmp = p_uart_obj[uart_num]->rx_cur_remain; } memcpy(buf + copy_len, p_uart_obj[uart_num]->rx_ptr, len_tmp); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffered_len -= len_tmp; uart_pattern_queue_update(uart_num, len_tmp); p_uart_obj[uart_num]->rx_ptr += len_tmp; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_cur_remain -= len_tmp; copy_len += len_tmp; length -= len_tmp; - if (p_uart_obj[uart_num]->rx_cur_remain == 0) { + if(p_uart_obj[uart_num]->rx_cur_remain == 0) { vRingbufferReturnItem(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_head_ptr); p_uart_obj[uart_num]->rx_head_ptr = NULL; p_uart_obj[uart_num]->rx_ptr = NULL; @@ -1365,7 +1190,7 @@ int uart_read_bytes(uart_port_t uart_num, uint8_t *buf, uint32_t length, TickTyp return copy_len; } -esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t *size) +esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t* size) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); @@ -1379,55 +1204,55 @@ esp_err_t uart_flush_input(uart_port_t uart_num) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); - uart_obj_t *p_uart = p_uart_obj[uart_num]; - uint8_t *data; + uart_obj_t* p_uart = p_uart_obj[uart_num]; + uint8_t* data; size_t size; //rx sem protect the ring buffer read related functions xSemaphoreTake(p_uart->rx_mux, (portTickType)portMAX_DELAY); uart_disable_rx_intr(p_uart_obj[uart_num]->uart_num); - while (true) { - if (p_uart->rx_head_ptr) { + while(true) { + if(p_uart->rx_head_ptr) { vRingbufferReturnItem(p_uart->rx_ring_buf, p_uart->rx_head_ptr); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffered_len -= p_uart->rx_cur_remain; uart_pattern_queue_update(uart_num, p_uart->rx_cur_remain); - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart->rx_ptr = NULL; p_uart->rx_cur_remain = 0; p_uart->rx_head_ptr = NULL; } - data = (uint8_t *) xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType) 0); - if (data == NULL) { - if ( p_uart_obj[uart_num]->rx_buffered_len != 0 ) { + data = (uint8_t*) xRingbufferReceive(p_uart->rx_ring_buf, &size, (portTickType) 0); + if(data == NULL) { + if( p_uart_obj[uart_num]->rx_buffered_len != 0 ) { ESP_LOGE(UART_TAG, "rx_buffered_len error"); p_uart_obj[uart_num]->rx_buffered_len = 0; } //We also need to clear the `rx_buffer_full_flg` here. - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffer_full_flg = false; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); break; } - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffered_len -= size; uart_pattern_queue_update(uart_num, size); - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); vRingbufferReturnItem(p_uart->rx_ring_buf, data); - if (p_uart_obj[uart_num]->rx_buffer_full_flg) { + if(p_uart_obj[uart_num]->rx_buffer_full_flg) { BaseType_t res = xRingbufferSend(p_uart_obj[uart_num]->rx_ring_buf, p_uart_obj[uart_num]->rx_data_buf, p_uart_obj[uart_num]->rx_stash_len, 1); - if (res == pdTRUE) { - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); + if(res == pdTRUE) { + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); p_uart_obj[uart_num]->rx_buffered_len += p_uart_obj[uart_num]->rx_stash_len; p_uart_obj[uart_num]->rx_buffer_full_flg = false; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); } } } p_uart->rx_ptr = NULL; p_uart->rx_cur_remain = 0; p_uart->rx_head_ptr = NULL; - uart_reset_rx_fifo(uart_num); + uart_hal_rxfifo_rst(&(uart_context[uart_num].hal)); uart_enable_rx_intr(p_uart_obj[uart_num]->uart_num); xSemaphoreGive(p_uart->rx_mux); return ESP_OK; @@ -1451,9 +1276,9 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b } #endif - if (p_uart_obj[uart_num] == NULL) { - p_uart_obj[uart_num] = (uart_obj_t *) calloc(1, sizeof(uart_obj_t)); - if (p_uart_obj[uart_num] == NULL) { + if(p_uart_obj[uart_num] == NULL) { + p_uart_obj[uart_num] = (uart_obj_t*) heap_caps_calloc(1, sizeof(uart_obj_t), MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + if(p_uart_obj[uart_num] == NULL) { ESP_LOGE(UART_TAG, "UART driver malloc error"); return ESP_FAIL; } @@ -1476,7 +1301,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b p_uart_obj[uart_num]->rx_buffered_len = 0; uart_pattern_queue_reset(uart_num, UART_PATTERN_DET_QLEN_DEFAULT); - if (uart_queue) { + if(uart_queue) { p_uart_obj[uart_num]->xQueueUart = xQueueCreate(queue_size, sizeof(uart_event_t)); *uart_queue = p_uart_obj[uart_num]->xQueueUart; ESP_LOGI(UART_TAG, "queue free spaces: %d", uxQueueSpacesAvailable(p_uart_obj[uart_num]->xQueueUart)); @@ -1489,7 +1314,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b p_uart_obj[uart_num]->rx_cur_remain = 0; p_uart_obj[uart_num]->rx_head_ptr = NULL; p_uart_obj[uart_num]->rx_ring_buf = xRingbufferCreate(rx_buffer_size, RINGBUF_TYPE_BYTEBUF); - if (tx_buffer_size > 0) { + if(tx_buffer_size > 0) { p_uart_obj[uart_num]->tx_ring_buf = xRingbufferCreate(tx_buffer_size, RINGBUF_TYPE_NOSPLIT); p_uart_obj[uart_num]->tx_buf_size = tx_buffer_size; } else { @@ -1502,25 +1327,24 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b return ESP_FAIL; } - r = uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags, &p_uart_obj[uart_num]->intr_handle); - if (r != ESP_OK) { - goto err; - } uart_intr_config_t uart_intr = { - .intr_enable_mask = UART_RXFIFO_FULL_INT_ENA_M - | UART_RXFIFO_TOUT_INT_ENA_M - | UART_FRM_ERR_INT_ENA_M - | UART_RXFIFO_OVF_INT_ENA_M - | UART_BRK_DET_INT_ENA_M - | UART_PARITY_ERR_INT_ENA_M, + .intr_enable_mask = UART_INTR_RXFIFO_FULL + | UART_INTR_RXFIFO_TOUT + | UART_INTR_PARITY_ERR + | UART_INTR_RXFIFO_OVF + | UART_INTR_BRK_DET + | UART_INTR_PARITY_ERR, .rxfifo_full_thresh = UART_FULL_THRESH_DEFAULT, .rx_timeout_thresh = UART_TOUT_THRESH_DEFAULT, .txfifo_empty_intr_thresh = UART_EMPTY_THRESH_DEFAULT }; - r = uart_intr_config(uart_num, &uart_intr); - if (r != ESP_OK) { - goto err; - } + uart_module_enable(uart_num); + uart_hal_disable_intr_mask(&(uart_context[uart_num].hal), UART_INTR_MASK); + uart_hal_clr_intsts_mask(&(uart_context[uart_num].hal), UART_INTR_MASK); + r=uart_isr_register(uart_num, uart_rx_intr_handler_default, p_uart_obj[uart_num], intr_alloc_flags, &p_uart_obj[uart_num]->intr_handle); + if (r!=ESP_OK) goto err; + r=uart_intr_config(uart_num, &uart_intr); + if (r!=ESP_OK) goto err; return r; err: @@ -1528,11 +1352,13 @@ err: return r; } +int a = 0; + //Make sure no other tasks are still using UART before you call this function esp_err_t uart_driver_delete(uart_port_t uart_num) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_FAIL); - if (p_uart_obj[uart_num] == NULL) { + if(p_uart_obj[uart_num] == NULL) { ESP_LOGI(UART_TAG, "ALREADY NULL"); return ESP_OK; } @@ -1541,46 +1367,43 @@ esp_err_t uart_driver_delete(uart_port_t uart_num) uart_disable_tx_intr(uart_num); uart_pattern_link_free(uart_num); - if (p_uart_obj[uart_num]->tx_fifo_sem) { + if(p_uart_obj[uart_num]->tx_fifo_sem) { vSemaphoreDelete(p_uart_obj[uart_num]->tx_fifo_sem); p_uart_obj[uart_num]->tx_fifo_sem = NULL; } - if (p_uart_obj[uart_num]->tx_done_sem) { + if(p_uart_obj[uart_num]->tx_done_sem) { vSemaphoreDelete(p_uart_obj[uart_num]->tx_done_sem); p_uart_obj[uart_num]->tx_done_sem = NULL; } - if (p_uart_obj[uart_num]->tx_brk_sem) { + if(p_uart_obj[uart_num]->tx_brk_sem) { vSemaphoreDelete(p_uart_obj[uart_num]->tx_brk_sem); p_uart_obj[uart_num]->tx_brk_sem = NULL; } - if (p_uart_obj[uart_num]->tx_mux) { + if(p_uart_obj[uart_num]->tx_mux) { vSemaphoreDelete(p_uart_obj[uart_num]->tx_mux); p_uart_obj[uart_num]->tx_mux = NULL; } - if (p_uart_obj[uart_num]->rx_mux) { + if(p_uart_obj[uart_num]->rx_mux) { vSemaphoreDelete(p_uart_obj[uart_num]->rx_mux); p_uart_obj[uart_num]->rx_mux = NULL; } - if (p_uart_obj[uart_num]->xQueueUart) { + if(p_uart_obj[uart_num]->xQueueUart) { vQueueDelete(p_uart_obj[uart_num]->xQueueUart); p_uart_obj[uart_num]->xQueueUart = NULL; } - if (p_uart_obj[uart_num]->rx_ring_buf) { + if(p_uart_obj[uart_num]->rx_ring_buf) { vRingbufferDelete(p_uart_obj[uart_num]->rx_ring_buf); p_uart_obj[uart_num]->rx_ring_buf = NULL; } - if (p_uart_obj[uart_num]->tx_ring_buf) { + if(p_uart_obj[uart_num]->tx_ring_buf) { vRingbufferDelete(p_uart_obj[uart_num]->tx_ring_buf); p_uart_obj[uart_num]->tx_ring_buf = NULL; } - free(p_uart_obj[uart_num]); + heap_caps_free(p_uart_obj[uart_num]); p_uart_obj[uart_num] = NULL; - if (uart_num != CONFIG_ESP_CONSOLE_UART_NUM) { - periph_module_t periph_module = get_periph_module(uart_num); - periph_module_disable(periph_module); - } + uart_module_disable(uart_num); return ESP_OK; } @@ -1599,60 +1422,27 @@ portMUX_TYPE *uart_get_selectlock(void) // Set UART mode esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode) { - UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_STATE); UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_ERR_INVALID_STATE); if ((mode == UART_MODE_RS485_COLLISION_DETECT) || (mode == UART_MODE_RS485_APP_CTRL) || (mode == UART_MODE_RS485_HALF_DUPLEX)) { - UART_CHECK((UART[uart_num]->conf1.rx_flow_en != 1), - "disable hw flowctrl before using RS485 mode", ESP_ERR_INVALID_ARG); + UART_CHECK((!uart_hal_is_hw_rts_en(&(uart_context[uart_num].hal))), + "disable hw flowctrl before using RS485 mode", ESP_ERR_INVALID_ARG); } - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - UART[uart_num]->rs485_conf.en = 0; - UART[uart_num]->rs485_conf.tx_rx_en = 0; - UART[uart_num]->rs485_conf.rx_busy_tx_en = 0; - UART[uart_num]->conf0.irda_en = 0; - UART[uart_num]->conf0.sw_rts = 0; - switch (mode) { - case UART_MODE_UART: - break; - case UART_MODE_RS485_COLLISION_DETECT: + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_mode(&(uart_context[uart_num].hal), mode); + if(mode == UART_MODE_RS485_COLLISION_DETECT) { // This mode allows read while transmitting that allows collision detection p_uart_obj[uart_num]->coll_det_flg = false; - // TransmitterÂ’s output signal loop back to the receiverÂ’s input signal - UART[uart_num]->rs485_conf.tx_rx_en = 0 ; - // Transmitter should send data when its receiver is busy - UART[uart_num]->rs485_conf.rx_busy_tx_en = 1; - UART[uart_num]->rs485_conf.en = 1; // Enable collision detection interrupts - uart_enable_intr_mask(uart_num, UART_RXFIFO_TOUT_INT_ENA - | UART_RXFIFO_FULL_INT_ENA - | UART_RS485_CLASH_INT_ENA - | UART_RS485_FRM_ERR_INT_ENA - | UART_RS485_PARITY_ERR_INT_ENA); - break; - case UART_MODE_RS485_APP_CTRL: - // Application software control, remove echo - UART[uart_num]->rs485_conf.rx_busy_tx_en = 1; - UART[uart_num]->rs485_conf.en = 1; - break; - case UART_MODE_RS485_HALF_DUPLEX: - // Enable receiver, sw_rts = 1 generates low level on RTS pin - UART[uart_num]->conf0.sw_rts = 1; - UART[uart_num]->rs485_conf.en = 1; - // Must be set to 0 to automatically remove echo - UART[uart_num]->rs485_conf.tx_rx_en = 0; - // This is to void collision - UART[uart_num]->rs485_conf.rx_busy_tx_en = 1; - break; - case UART_MODE_IRDA: - UART[uart_num]->conf0.irda_en = 1; - break; - default: - UART_CHECK(1, "unsupported uart mode", ESP_ERR_INVALID_ARG); - break; + uart_hal_ena_intr_mask(&(uart_context[uart_num].hal), UART_INTR_RXFIFO_TOUT + | UART_INTR_RXFIFO_FULL + | UART_INTR_RS485_CLASH + | UART_INTR_RS485_FRM_ERR + | UART_INTR_RS485_PARITY_ERR); } p_uart_obj[uart_num]->uart_mode = mode; - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } @@ -1660,32 +1450,17 @@ esp_err_t uart_set_rx_timeout(uart_port_t uart_num, const uint8_t tout_thresh) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); UART_CHECK((tout_thresh < 127), "tout_thresh max value is 126", ESP_ERR_INVALID_ARG); - UART_ENTER_CRITICAL(&uart_spinlock[uart_num]); - // The tout_thresh = 1, defines TOUT interrupt timeout equal to - // transmission time of one symbol (~11 bit) on current baudrate - if (tout_thresh > 0) { -#if CONFIG_IDF_TARGET_ESP32 - //ESP32 hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. - //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) - if (UART[uart_num]->conf0.tick_ref_always_on == 0) { - UART[uart_num]->conf1.rx_tout_thrhd = ((tout_thresh * UART_TOUT_REF_FACTOR_DEFAULT) & UART_RX_TOUT_THRHD_V); - } else { - UART[uart_num]->conf1.rx_tout_thrhd = ((tout_thresh) & UART_RX_TOUT_THRHD_V); - } -#elif CONFIG_IDF_TARGET_ESP32S2BETA - UART[uart_num]->mem_conf.rx_tout_thrhd = ((tout_thresh) & UART_RX_TOUT_THRHD_V); -#endif - UART[uart_num]->conf1.rx_tout_en = 1; - } else { - UART[uart_num]->conf1.rx_tout_en = 0; - } - UART_EXIT_CRITICAL(&uart_spinlock[uart_num]); + + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_rx_timeout(&(uart_context[uart_num].hal), tout_thresh); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool *collision_flag) +esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool* collision_flag) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); UART_CHECK((collision_flag != NULL), "wrong parameter pointer", ESP_ERR_INVALID_ARG); UART_CHECK((UART_IS_MODE_SET(uart_num, UART_MODE_RS485_HALF_DUPLEX) || UART_IS_MODE_SET(uart_num, UART_MODE_RS485_COLLISION_DETECT)), @@ -1697,28 +1472,34 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool *collision_flag) esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + UART_CHECK((p_uart_obj[uart_num]), "uart driver error", ESP_FAIL); UART_CHECK((wakeup_threshold <= UART_ACTIVE_THRESHOLD_V && wakeup_threshold > UART_MIN_WAKEUP_THRESH), - "wakeup_threshold out of bounds", ESP_ERR_INVALID_ARG); - - UART[uart_num]->sleep_conf.active_threshold = wakeup_threshold - UART_MIN_WAKEUP_THRESH; + "wakeup_threshold out of bounds", ESP_ERR_INVALID_ARG); + UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); + uart_hal_set_wakeup_thrd(&(uart_context[uart_num].hal), wakeup_threshold); + UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } -esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int *out_wakeup_threshold) +esp_err_t uart_get_wakeup_threshold(uart_port_t uart_num, int* out_wakeup_threshold) { UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); UART_CHECK((out_wakeup_threshold != NULL), "argument is NULL", ESP_ERR_INVALID_ARG); - - *out_wakeup_threshold = UART[uart_num]->sleep_conf.active_threshold + UART_MIN_WAKEUP_THRESH; + uart_hal_get_wakeup_thrd(&(uart_context[uart_num].hal), (uint32_t *)out_wakeup_threshold); return ESP_OK; } -void uart_wait_tx_idle_polling(uart_port_t uart_num) +esp_err_t uart_wait_tx_idle_polling(uart_port_t uart_num) { - uint32_t status; - do { - status = READ_PERI_REG(UART_STATUS_REG(uart_num)); - /* either tx count or state is non-zero */ - } while ((status & (UART_ST_UTX_OUT_M | UART_TXFIFO_CNT_M)) != 0); + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + while(!uart_hal_is_tx_idle(&(uart_context[uart_num].hal))); + return ESP_OK; } + +esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en) +{ + UART_CHECK((uart_num < UART_NUM_MAX), "uart_num error", ESP_ERR_INVALID_ARG); + uart_hal_set_loop_back(&(uart_context[uart_num].hal), loop_back_en); + return ESP_OK; +} \ No newline at end of file diff --git a/components/esp32s2beta/ld/esp32s2beta.peripherals.ld b/components/esp32s2beta/ld/esp32s2beta.peripherals.ld index a7c71e769..cb0ffaf36 100644 --- a/components/esp32s2beta/ld/esp32s2beta.peripherals.ld +++ b/components/esp32s2beta/ld/esp32s2beta.peripherals.ld @@ -26,4 +26,3 @@ PROVIDE ( I2C1 = 0x3f427000 ); PROVIDE ( GPSPI4 = 0x3f437000 ); PROVIDE ( ToBeCleanedUpBelow = 0x00000000 ); -PROVIDE ( UART2 = 0x3f410000 ); diff --git a/components/freemodbus/port/portserial.c b/components/freemodbus/port/portserial.c index ce808e816..57d107d47 100644 --- a/components/freemodbus/port/portserial.c +++ b/components/freemodbus/port/portserial.c @@ -238,6 +238,7 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .rx_flow_ctrl_thresh = 2, + .use_ref_tick = UART_SCLK_APB, }; // Set UART config xErr = uart_param_config(ucUartNumber, &xUartConfig); diff --git a/components/freemodbus/port/portserial_m.c b/components/freemodbus/port/portserial_m.c index 175d2a6b4..e6566bedc 100644 --- a/components/freemodbus/port/portserial_m.c +++ b/components/freemodbus/port/portserial_m.c @@ -227,6 +227,7 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .rx_flow_ctrl_thresh = 2, + .source_clk = UART_SCLK_APB, }; // Set UART config xErr = uart_param_config(ucUartNumber, &xUartConfig); diff --git a/components/soc/CMakeLists.txt b/components/soc/CMakeLists.txt index 790978cf5..9d59143be 100644 --- a/components/soc/CMakeLists.txt +++ b/components/soc/CMakeLists.txt @@ -30,6 +30,8 @@ list(APPEND srcs "src/hal/i2c_hal.c" "src/hal/i2c_hal_iram.c" "src/hal/gpio_hal.c" + "src/hal/uart_hal.c" + "src/hal/uart_hal_iram.c" ) # TODO: SPI Flash HAL for ESP32S2Beta also diff --git a/components/soc/esp32/include/hal/uart_ll.h b/components/soc/esp32/include/hal/uart_ll.h new file mode 100644 index 000000000..01218ef40 --- /dev/null +++ b/components/soc/esp32/include/hal/uart_ll.h @@ -0,0 +1,793 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for UART register operations. +// Note that most of the register operations in this layer are non-atomic operations. + + +#pragma once +#include "hal/uart_types.h" +#include "soc/uart_periph.h" + +// The default fifo depth +#define UART_LL_FIFO_DEF_LEN (UART_FIFO_LEN) +// Get UART hardware instance with giving uart num +#define UART_LL_GET_HW(num) (((num) == 0) ? (&UART0) : (((num) == 1) ? (&UART1) : (&UART2))) + +// The timeout calibration factor when using ref_tick +#define UART_LL_TOUT_REF_FACTOR_DEFAULT (8) + +// Define UART interrupts +typedef enum { + UART_INTR_RXFIFO_FULL = (0x1<<0), + UART_INTR_TXFIFO_EMPTY = (0x1<<1), + UART_INTR_PARITY_ERR = (0x1<<2), + UART_INTR_FRAM_ERR = (0x1<<3), + UART_INTR_RXFIFO_OVF = (0x1<<4), + UART_INTR_DSR_CHG = (0x1<<5), + UART_INTR_CTS_CHG = (0x1<<6), + UART_INTR_BRK_DET = (0x1<<7), + UART_INTR_RXFIFO_TOUT = (0x1<<8), + UART_INTR_SW_XON = (0x1<<9), + UART_INTR_SW_XOFF = (0x1<<10), + UART_INTR_GLITCH_DET = (0x1<<11), + UART_INTR_TX_BRK_DONE = (0x1<<12), + UART_INTR_TX_BRK_IDLE = (0x1<<13), + UART_INTR_TX_DONE = (0x1<<14), + UART_INTR_RS485_PARITY_ERR = (0x1<<15), + UART_INTR_RS485_FRM_ERR = (0x1<<16), + UART_INTR_RS485_CLASH = (0x1<<17), + UART_INTR_CMD_CHAR_DET = (0x1<<18), +} uart_intr_t; + + +/** + * @brief Configure the baud-rate. + * + * @param hw Beginning address of the peripheral registers. + * @param baud The baud-rate to be set. When the source clock is APB, the max baud-rate is `UART_LL_BITRATE_MAX` + * @param source_clk The UART source clock. The source clock can be APB clock or REF_TICK. + * If the source clock is REF_TICK, the UART can still work when the APB changes. + * + * @return None + */ +static inline void uart_ll_set_baudrate(uart_dev_t *hw, uart_sclk_t source_clk, uint32_t baud) +{ + uint32_t sclk_freq = (source_clk == UART_SCLK_APB) ? APB_CLK_FREQ : REF_CLK_FREQ; + uint32_t clk_div = ((sclk_freq) << 4) / baud; + // The baud-rate configuration register is divided into + // an integer part and a fractional part. + hw->clk_div.div_int = clk_div >> 4; + hw->clk_div.div_frag = clk_div & 0xf; + // Configure the UART source clock. + hw->conf0.tick_ref_always_on = (source_clk == UART_SCLK_APB); +} + +/** + * @brief Get the current baud-rate. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The current baudrate + */ +static inline uint32_t uart_ll_get_baudrate(uart_dev_t *hw) +{ + uint32_t src_clk = hw->conf0.tick_ref_always_on ? APB_CLK_FREQ : REF_CLK_FREQ; + typeof(hw->clk_div) div_reg = hw->clk_div; + return ((src_clk << 4)) / ((div_reg.div_int << 4) | div_reg.div_frag); +} + +/** + * @brief Enable the UART interrupt based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be enabled. + * + * @return None + */ +static inline void uart_ll_ena_intr_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val |= mask; +} + +/** + * @brief Disable the UART interrupt based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be disabled. + * + * @return None + */ +static inline void uart_ll_disable_intr_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val &= (~mask); +} + +/** + * @brief Get the UART interrupt status. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The UART interrupt status. + */ +static inline uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) +{ + return hw->int_st.val; +} + +/** + * @brief Clear the UART interrupt status based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be cleared. + * + * @return None + */ +static inline void uart_ll_clr_intsts_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_clr.val = mask; +} + +/** + * @brief Read the UART rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * @param buf The data buffer. The buffer size should be large than 128 byts. + * @param rd_len The data length needs to be read. + * + * @return None. + */ +static inline void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_t rd_len) +{ + //Get the UART APB fifo addr. Read fifo, we use APB address + uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_REG(0) : (hw == &UART1) ? UART_FIFO_REG(1) : UART_FIFO_REG(2); + for(int i = 0; i < rd_len; i++) { + buf[i] = READ_PERI_REG(fifo_addr); + } +} + +/** + * @brief Write byte to the UART txfifo. + * + * @param hw Beginning address of the peripheral registers. + * @param buf The data buffer. + * @param wr_len The data length needs to be writen. + * + * @return None + */ +static inline void uart_ll_write_txfifo(uart_dev_t *hw, const uint8_t *buf, uint32_t wr_len) +{ + //Get the UART AHB fifo addr, Write fifo, we use AHB address + uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : (hw == &UART1) ? UART_FIFO_AHB_REG(1) : UART_FIFO_AHB_REG(2); + for(int i = 0; i < wr_len; i++) { + WRITE_PERI_REG(fifo_addr, buf[i]); + } +} + +/** + * @brief Reset the UART hw rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None + */ +static inline void uart_ll_rxfifo_rst(uart_dev_t *hw) +{ + //Hardware issue: we can not use `rxfifo_rst` to reset the hw rxfifo. + uint16_t fifo_cnt; + typeof(hw->mem_rx_status) rxmem_sta; + //Get the UART APB fifo addr + uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_REG(0) : (hw == &UART1) ? UART_FIFO_REG(1) : UART_FIFO_REG(2); + do { + fifo_cnt = hw->status.rxfifo_cnt; + rxmem_sta.val = hw->mem_rx_status.val; + if(fifo_cnt != 0 || (rxmem_sta.rd_addr != rxmem_sta.wr_addr)) { + READ_PERI_REG(fifo_addr); + } else { + break; + } + } while(1); +} + +/** + * @brief Reset the UART hw txfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None + */ +static inline void uart_ll_txfifo_rst(uart_dev_t *hw) +{ + hw->conf0.txfifo_rst = 1; + hw->conf0.txfifo_rst = 0; +} + +/** + * @brief Get the length of readable data in UART rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The readable data length in rxfifo. + */ +static inline uint32_t uart_ll_get_rxfifo_len(uart_dev_t *hw) +{ + return hw->status.rxfifo_cnt; +} + +/** + * @brief Get the writable data length of UART txfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The data length of txfifo can be written. + */ +static inline uint32_t uart_ll_get_txfifo_len(uart_dev_t *hw) +{ + return UART_LL_FIFO_DEF_LEN - hw->status.txfifo_cnt; +} + +/** + * @brief Configure the UART stop bit. + * + * @param hw Beginning address of the peripheral registers. + * @param stop_bit The stop bit number to be set. + * + * @return None. + */ +static inline void uart_ll_set_stop_bits(uart_dev_t *hw, uart_stop_bits_t stop_bit) +{ + //workaround for hardware issue, when UART stop bit set as 2-bit mode. + if(stop_bit == UART_STOP_BITS_2) { + hw->rs485_conf.dl1_en = 1; + hw->conf0.stop_bit_num = 0x1; + } else { + hw->rs485_conf.dl1_en = 0; + hw->conf0.stop_bit_num = stop_bit; + } +} + +/** + * @brief Get the configuration of the UART stop bit. + * + * @param hw Beginning address of the peripheral registers. + * @param stop_bit The pointer to accept the stop bit configuration + * + * @return None. + */ +static inline void uart_ll_get_stop_bits(uart_dev_t *hw, uart_stop_bits_t *stop_bit) +{ + //workaround for hardware issue, when UART stop bit set as 2-bit mode. + if(hw->rs485_conf.dl1_en == 1 && hw->conf0.stop_bit_num == 0x1) { + *stop_bit = UART_STOP_BITS_2; + } else { + *stop_bit = hw->conf0.stop_bit_num; + } +} + +/** + * @brief Configure the UART parity check mode. + * + * @param hw Beginning address of the peripheral registers. + * @param parity_mode The parity check mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_parity(uart_dev_t *hw, uart_parity_t parity_mode) +{ + if(parity_mode != UART_PARITY_DISABLE) { + hw->conf0.parity = parity_mode & 0x1; + } + hw->conf0.parity_en = (parity_mode >> 1) & 0x1; +} + +/** + * @brief Get the UART parity check mode configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param parity_mode The pointer to accept the parity check mode configuration. + * + * @return None. + */ +static inline void uart_ll_get_parity(uart_dev_t *hw, uart_parity_t *parity_mode) +{ + if(hw->conf0.parity_en) { + *parity_mode = 0X2 | hw->conf0.parity; + } else { + *parity_mode = UART_PARITY_DISABLE; + } +} + +/** + * @brief Set the UART rxfifo full threshold value. When the data in rxfifo is more than the threshold value, + * it will produce rxfifo_full_int_raw interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param full_thrhd The full threshold value of the rxfifo. `full_thrhd` should be less than `UART_LL_FIFO_DEF_LEN`. + * + * @return None. + */ +static inline void uart_ll_set_rxfifo_full_thr(uart_dev_t *hw, uint16_t full_thrhd) +{ + hw->conf1.rxfifo_full_thrhd = full_thrhd; +} + +/** + * @brief Set the txfifo empty threshold. when the data length in txfifo is less than threshold value, + * it will produce txfifo_empty_int_raw interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param empty_thrhd The empty threshold of txfifo. + * + * @return None. + */ +static inline void uart_ll_set_txfifo_empty_thr(uart_dev_t *hw, uint16_t empty_thrhd) +{ + hw->conf1.txfifo_empty_thrhd = empty_thrhd; +} + +/** + * @brief Set the UART rx-idle threshold value. when receiver takes more time than rx_idle_thrhd to receive a byte data, + * it will produce frame end signal for uhci to stop receiving data. + * + * @param hw Beginning address of the peripheral registers. + * @param rx_idle_thr The rx-idle threshold to be set. + * + * @return None. + */ +static inline void uart_ll_set_rx_idle_thr(uart_dev_t *hw, uint32_t rx_idle_thr) +{ + hw->idle_conf.rx_idle_thrhd = rx_idle_thr; +} + +/** + * @brief Configure the duration time between transfers. + * + * @param hw Beginning address of the peripheral registers. + * @param idle_num the duration time between transfers. + * + * @return None. + */ +static inline void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num) +{ + hw->idle_conf.tx_idle_num = idle_num; +} + +/** + * @brief Configure the timeout value for receiver receiving a byte, and enable rx timeout function. + * + * @param hw Beginning address of the peripheral registers. + * @param tout_thr The timeout value. The rx timeout function will be disabled if `tout_thr == 0`. + * + * @return None. + */ +static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint8_t tout_thr) +{ + // The tout_thresh = 1, defines TOUT interrupt timeout equal to + // transmission time of one symbol (~11 bit) on current baudrate + if (hw->conf0.tick_ref_always_on == 0) { + //Hardware issue workaround: when using ref_tick, the rx timeout threshold needs increase to 10 times. + //T_ref = T_apb * APB_CLK/(REF_TICK << CLKDIV_FRAG_BIT_WIDTH) + tout_thr = tout_thr * UART_LL_TOUT_REF_FACTOR_DEFAULT; + } + if(tout_thr > 0) { + hw->conf1.rx_tout_thrhd = tout_thr; + hw->conf1.rx_tout_en = 1; + } else { + hw->conf1.rx_tout_en = 0; + } +} + +/** + * @brief Configure the transmiter to send break chars. + * + * @param hw Beginning address of the peripheral registers. + * @param break_num The number of the break chars need to be send. + * + * @return None. + */ +static inline void uart_ll_tx_break(uart_dev_t *hw, uint32_t break_num) +{ + if(break_num > 0) { + hw->idle_conf.tx_brk_num = break_num; + hw->conf0.txd_brk = 1; + } else { + hw->conf0.txd_brk = 0; + } +} + +/** + * @brief Configure the UART hardware flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl The hw flow control configuration. + * @param rx_thrs The rx flow control signal will be active if the data length in rxfifo is more than this value. + * + * @return None. + */ +static inline void uart_ll_set_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t flow_ctrl, uint32_t rx_thrs) +{ + //only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set. + if(flow_ctrl & UART_HW_FLOWCTRL_RTS) { + hw->conf1.rx_flow_thrhd = rx_thrs; + hw->conf1.rx_flow_en = 1; + } else { + hw->conf1.rx_flow_en = 0; + } + if(flow_ctrl & UART_HW_FLOWCTRL_CTS) { + hw->conf0.tx_flow_en = 1; + } else { + hw->conf0.tx_flow_en = 0; + } +} + +/** + * @brief Configure the hardware flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl A pointer to accept the hw flow control configuration. + * + * @return None. + */ +static inline void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t *flow_ctrl) +{ + *flow_ctrl = UART_HW_FLOWCTRL_DISABLE; + if(hw->conf1.rx_flow_en) { + *flow_ctrl |= UART_HW_FLOWCTRL_RTS; + } + if(hw->conf0.tx_flow_en) { + *flow_ctrl |= UART_HW_FLOWCTRL_CTS; + } +} + +/** + * @brief Configure the software flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl The UART sofware flow control settings. + * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. + * + * @return None. + */ +static inline void uart_ll_set_sw_flow_ctrl(uart_dev_t *hw, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en) +{ + if(sw_flow_ctrl_en) { + hw->swfc_conf.xon_threshold = flow_ctrl->xon_thrd; + hw->swfc_conf.xoff_threshold = flow_ctrl->xoff_thrd; + hw->swfc_conf.xon_char = flow_ctrl->xon_char; + hw->swfc_conf.xoff_char = flow_ctrl->xoff_char; + hw->flow_conf.sw_flow_con_en = 1; + hw->flow_conf.xonoff_del = 1; + } else { + hw->flow_conf.sw_flow_con_en = 0; + hw->flow_conf.xonoff_del = 0; + } +} + +/** + * @brief Configure the AT cmd char. When the receiver receives a continuous AT cmd char, it will produce at_cmd_char_det interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param cmd_char The AT cmd char configuration.The configuration member is: + * - cmd_char The AT cmd character + * - char_num The number of received AT cmd char must be equal to or greater than this value + * - gap_tout The interval between each AT cmd char, when the duration is less than this value, it will not take this data as AT cmd char + * - pre_idle The idle time before the first AT cmd char, when the duration is less than this value, it will not take the previous data as the last AT cmd char + * - post_idle The idle time after the last AT cmd char, when the duration is less than this value, it will not take this data as the first AT cmd char + * + * @return None. + */ +static inline void uart_ll_set_at_cmd_char(uart_dev_t *hw, uart_at_cmd_t *cmd_char) +{ + hw->at_cmd_char.data = cmd_char->cmd_char; + hw->at_cmd_char.char_num = cmd_char->char_num; + hw->at_cmd_postcnt.post_idle_num = cmd_char->post_idle; + hw->at_cmd_precnt.pre_idle_num = cmd_char->pre_idle; + hw->at_cmd_gaptout.rx_gap_tout = cmd_char->gap_tout; +} + +/** + * @brief Set the UART data bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param data_bit The data bit mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_data_bit_num(uart_dev_t *hw, uart_word_length_t data_bit) +{ + hw->conf0.bit_num = data_bit; +} + +/** + * @brief Get the UART source clock. + * + * @param hw Beginning address of the peripheral registers. + * @param source_clk The pointer to accept the UART source clock configuration. + * + * @return None. + */ +static inline void uart_ll_get_sclk(uart_dev_t *hw, uart_sclk_t* source_clk) +{ + *source_clk = hw->conf0.tick_ref_always_on ? UART_SCLK_APB : UART_SCLK_REF_TICK; +} + +/** + * @brief Set the rts active level. + * + * @param hw Beginning address of the peripheral registers. + * @param level The rts active level, 0 or 1. + * + * @return None. + */ +static inline void uart_ll_set_rts_active_level(uart_dev_t *hw, int level) +{ + hw->conf0.sw_rts = level & 0x1; +} + +/** + * @brief Set the dtr active level. + * + * @param hw Beginning address of the peripheral registers. + * @param level The dtr active level, 0 or 1. + * + * @return None. + */ +static inline void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) +{ + hw->conf0.sw_dtr = level & 0x1; +} + +/** + * @brief Set the UART wakeup threshold. + * + * @param hw Beginning address of the peripheral registers. + * @param wakeup_thrd The wakeup threshold value to be set. When the input rx edge changes more than this value, + * the UART will active from light sleeping mode. + * + * @return None. + */ +static inline void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) +{ + hw->sleep_conf.active_threshold = wakeup_thrd - SOC_UART_MIN_WAKEUP_THRESH; +} + +/** + * @brief Configure the UART work in normal mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_normal(uart_dev_t *hw) +{ + hw->rs485_conf.en = 0; + hw->rs485_conf.tx_rx_en = 0; + hw->rs485_conf.rx_busy_tx_en = 0; + hw->conf0.irda_en = 0; +} + +/** + * @brief Configure the UART work in rs485_app_ctrl mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_rs485_app_ctrl(uart_dev_t *hw) +{ + // Application software control, remove echo + hw->rs485_conf.rx_busy_tx_en = 1; + hw->conf0.irda_en = 0; + hw->conf0.sw_rts = 0; + hw->conf0.irda_en = 0; + hw->rs485_conf.en = 1; +} + +/** + * @brief Configure the UART work in rs485_half_duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_rs485_half_duplex(uart_dev_t *hw) +{ + // Enable receiver, sw_rts = 1 generates low level on RTS pin + hw->conf0.sw_rts = 1; + // Must be set to 0 to automatically remove echo + hw->rs485_conf.tx_rx_en = 0; + // This is to void collision + hw->rs485_conf.rx_busy_tx_en = 1; + hw->conf0.irda_en = 0; + hw->rs485_conf.en = 1; +} + +/** + * @brief Configure the UART work in collision_detect mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_collision_detect(uart_dev_t *hw) +{ + hw->conf0.irda_en = 0; + // Transmitters output signal loop back to the receivers input signal + hw->rs485_conf.tx_rx_en = 1 ; + // Transmitter should send data when the receiver is busy + hw->rs485_conf.rx_busy_tx_en = 1; + hw->conf0.sw_rts = 0; + hw->rs485_conf.en = 1; +} + +/** + * @brief Configure the UART work in irda mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_irda(uart_dev_t *hw) +{ + hw->rs485_conf.en = 0; + hw->rs485_conf.tx_rx_en = 0; + hw->rs485_conf.rx_busy_tx_en = 0; + hw->conf0.sw_rts = 0; + hw->conf0.irda_en = 1; +} + +/** + * @brief Set uart mode. + * + * @param hw Beginning address of the peripheral registers. + * @param mode The UART mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_mode(uart_dev_t *hw, uart_mode_t mode) +{ + switch (mode) { + default: + case UART_MODE_UART: + uart_ll_set_mode_normal(hw); + break; + case UART_MODE_RS485_COLLISION_DETECT: + uart_ll_set_mode_collision_detect(hw); + break; + case UART_MODE_RS485_APP_CTRL: + uart_ll_set_mode_rs485_app_ctrl(hw); + break; + case UART_MODE_RS485_HALF_DUPLEX: + uart_ll_set_mode_rs485_half_duplex(hw); + break; + case UART_MODE_IRDA: + uart_ll_set_mode_irda(hw); + break; + } +} + +/** + * @brief Get the UART AT cmd char configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param cmd_char The Pointer to accept value of UART AT cmd char. + * @param char_num Pointer to accept the repeat number of UART AT cmd char. + * + * @return None. + */ +static inline void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char, uint8_t *char_num) +{ + *cmd_char = hw->at_cmd_char.data; + *char_num = hw->at_cmd_char.char_num; +} + +/** + * @brief Get the UART wakeup threshold value. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The UART wakeup threshold value. + */ +static inline uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw) +{ + return hw->sleep_conf.active_threshold; +} + +/** + * @brief Get the UART data bit configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param data_bit The pointer to accept the UART data bit configuration. + * + * @return The bit mode. + */ +static inline void uart_ll_get_data_bit_num(uart_dev_t *hw, uart_word_length_t *data_bit) +{ + *data_bit = hw->conf0.bit_num; +} + +/** + * @brief Check if the UART sending state machine is in the IDLE state. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if the state machine is in the IDLE state, otherwise false is returned. + */ +static inline bool uart_ll_is_tx_idle(uart_dev_t *hw) +{ + typeof(hw->status) status = hw->status; + return ((status.txfifo_cnt == 0) && (status.st_utx_out == 0)); +} + +/** + * @brief Check if the UART rts flow control is enabled. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if hw rts flow control is enabled, otherwise false is returned. + */ +static inline bool uart_ll_is_hw_rts_en(uart_dev_t *hw) +{ + return hw->conf1.rx_flow_en; +} + +/** + * @brief Check if the UART cts flow control is enabled. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if hw cts flow control is enabled, otherwise false is returned. + */ +static inline bool uart_ll_is_hw_cts_en(uart_dev_t *hw) +{ + return hw->conf0.tx_flow_en; +} + +/** + * @brief Configure TX signal loop back to RX module, just for the testing purposes + * + * @param hw Beginning address of the peripheral registers. + * @param loop_back_en Set ture to enable the loop back function, else set it false. + * + * @return None + */ +static inline void uart_ll_set_loop_back(uart_dev_t *hw, bool loop_back_en) +{ + hw->conf0.loopback = loop_back_en; +} + +/** + * @brief Inverse the UART signal with the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param inv_mask The UART signal bitmap needs to be inversed. + * Use the ORred mask of `uart_signal_inv_t`; + * + * @return None. + */ +static inline void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask) +{ + typeof(hw->conf0) conf0_reg = hw->conf0; + conf0_reg.irda_tx_inv |= (inv_mask & UART_SIGNAL_IRDA_TX_INV); + conf0_reg.irda_rx_inv |= (inv_mask & UART_SIGNAL_IRDA_RX_INV); + conf0_reg.rxd_inv |= (inv_mask & UART_SIGNAL_RXD_INV); + conf0_reg.cts_inv |= (inv_mask & UART_SIGNAL_CTS_INV); + conf0_reg.dsr_inv |= (inv_mask & UART_SIGNAL_DSR_INV); + conf0_reg.txd_inv |= (inv_mask & UART_SIGNAL_TXD_INV); + conf0_reg.rts_inv |= (inv_mask & UART_SIGNAL_RTS_INV); + conf0_reg.dtr_inv |= (inv_mask & UART_SIGNAL_DTR_INV); + hw->conf0.val = conf0_reg.val; +} + +#undef UART_LL_TOUT_REF_FACTOR_DEFAULT diff --git a/components/soc/esp32/include/soc/uart_caps.h b/components/soc/esp32/include/soc/uart_caps.h index 21af9f4d8..348a907ed 100644 --- a/components/soc/esp32/include/soc/uart_caps.h +++ b/components/soc/esp32/include/soc/uart_caps.h @@ -1,9 +1,9 @@ -// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD +// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// + // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -18,8 +18,16 @@ extern "C" { #endif -#define SOC_UART_NUM 3 +#define UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ +#define UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ + +// ESP32 have 3 UART. +#define SOC_UART_NUM (3) +#define SOC_UART_MIN_WAKEUP_THRESH (2) + +#define UART_INTR_MASK (0x7ffff) //All interrupt mask #ifdef __cplusplus } #endif + diff --git a/components/soc/esp32/sources.cmake b/components/soc/esp32/sources.cmake index efdf366f2..4241d3a1a 100644 --- a/components/soc/esp32/sources.cmake +++ b/components/soc/esp32/sources.cmake @@ -18,7 +18,9 @@ set(SOC_SRCS "adc_periph.c" "spi_periph.c" "ledc_periph.c" "i2s_periph.c" - "i2c_periph.c") + "i2c_periph.c" + "uart_periph.c" + ) if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC) list(APPEND SOC_SRCS "emac_hal.c") diff --git a/components/soc/esp32/uart_periph.c b/components/soc/esp32/uart_periph.c new file mode 100644 index 000000000..7695b4a6e --- /dev/null +++ b/components/soc/esp32/uart_periph.c @@ -0,0 +1,45 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/uart_periph.h" + +/* + Bunch of constants for every UART peripheral: GPIO signals, irqs, hw addr of registers etc +*/ +const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { + { + .tx_sig = U0TXD_OUT_IDX, + .rx_sig = U0RXD_IN_IDX, + .rts_sig = U0RTS_OUT_IDX, + .cts_sig = U0CTS_IN_IDX, + .irq = ETS_UART0_INTR_SOURCE, + .module = PERIPH_UART0_MODULE, + }, + { + .tx_sig = U1TXD_OUT_IDX, + .rx_sig = U1RXD_IN_IDX, + .rts_sig = U1RTS_OUT_IDX, + .cts_sig = U1CTS_IN_IDX, + .irq = ETS_UART1_INTR_SOURCE, + .module = PERIPH_UART1_MODULE, + }, + { + .tx_sig = U2TXD_OUT_IDX, + .rx_sig = U2RXD_IN_IDX, + .rts_sig = U2RTS_OUT_IDX, + .cts_sig = U2CTS_IN_IDX, + .irq = ETS_UART2_INTR_SOURCE, + .module = PERIPH_UART2_MODULE, + }, +}; \ No newline at end of file diff --git a/components/soc/esp32s2beta/include/hal/uart_ll.h b/components/soc/esp32s2beta/include/hal/uart_ll.h new file mode 100644 index 000000000..8e75d1c57 --- /dev/null +++ b/components/soc/esp32s2beta/include/hal/uart_ll.h @@ -0,0 +1,757 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The LL layer for UART register operations. +// Note that most of the register operations in this layer are non-atomic operations. + + +#pragma once +#include "hal/uart_types.h" +#include "soc/uart_periph.h" + +// The default fifo depth +#define UART_LL_FIFO_DEF_LEN (UART_FIFO_LEN) +// Get UART hardware instance with giving uart num +#define UART_LL_GET_HW(num) (((num) == 0) ? (&UART0) : (&UART1)) + + +// Define UART interrupts +typedef enum { + UART_INTR_RXFIFO_FULL = (0x1<<0), + UART_INTR_TXFIFO_EMPTY = (0x1<<1), + UART_INTR_PARITY_ERR = (0x1<<2), + UART_INTR_FRAM_ERR = (0x1<<3), + UART_INTR_RXFIFO_OVF = (0x1<<4), + UART_INTR_DSR_CHG = (0x1<<5), + UART_INTR_CTS_CHG = (0x1<<6), + UART_INTR_BRK_DET = (0x1<<7), + UART_INTR_RXFIFO_TOUT = (0x1<<8), + UART_INTR_SW_XON = (0x1<<9), + UART_INTR_SW_XOFF = (0x1<<10), + UART_INTR_GLITCH_DET = (0x1<<11), + UART_INTR_TX_BRK_DONE = (0x1<<12), + UART_INTR_TX_BRK_IDLE = (0x1<<13), + UART_INTR_TX_DONE = (0x1<<14), + UART_INTR_RS485_PARITY_ERR = (0x1<<15), + UART_INTR_RS485_FRM_ERR = (0x1<<16), + UART_INTR_RS485_CLASH = (0x1<<17), + UART_INTR_CMD_CHAR_DET = (0x1<<18), +} uart_intr_t; + + +/** + * @brief Configure the baud-rate. + * + * @param hw Beginning address of the peripheral registers. + * @param baud The baud rate to be set. When the source clock is APB, the max baud rate is `UART_LL_BITRATE_MAX` + * @param source_clk The UART source clock. The source clock can be APB clock or REF_TICK. + * If the source clock is REF_TICK, the UART can still work when the APB changes. + * + * @return None + */ +static inline void uart_ll_set_baudrate(uart_dev_t *hw, uart_sclk_t source_clk, uint32_t baud) +{ + uint32_t sclk_freq = (source_clk == UART_SCLK_APB) ? APB_CLK_FREQ : REF_CLK_FREQ; + uint32_t clk_div = ((sclk_freq) << 4) / baud; + // The baud rate configuration register is divided into + // an integer part and a fractional part. + hw->clk_div.div_int = clk_div >> 4; + hw->clk_div.div_frag = clk_div & 0xf; + // Configure the UART source clock. + hw->conf0.tick_ref_always_on = (source_clk == UART_SCLK_APB); +} + +/** + * @brief Get the current baud-rate. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The current baudrate + */ +static inline uint32_t uart_ll_get_baudrate(uart_dev_t *hw) +{ + uint32_t src_clk = hw->conf0.tick_ref_always_on ? APB_CLK_FREQ : REF_CLK_FREQ; + typeof(hw->clk_div) div_reg = hw->clk_div; + return ((src_clk << 4)) / ((div_reg.div_int << 4) | div_reg.div_frag); +} + +/** + * @brief Enable the UART interrupt based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be enabled. + * + * @return None + */ +static inline void uart_ll_ena_intr_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val |= mask; +} + +/** + * @brief Disable the UART interrupt based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be disabled. + * + * @return None + */ +static inline void uart_ll_disable_intr_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_ena.val &= (~mask); +} + +/** + * @brief Get the UART interrupt status. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The UART interrupt status. + */ +static inline uint32_t uart_ll_get_intsts_mask(uart_dev_t *hw) +{ + return hw->int_st.val; +} + +/** + * @brief Clear the UART interrupt status based on the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param mask The bitmap of the interrupts need to be cleared. + * + * @return None + */ +static inline void uart_ll_clr_intsts_mask(uart_dev_t *hw, uint32_t mask) +{ + hw->int_clr.val = mask; +} + +/** + * @brief Read the UART rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * @param buf The data buffer. The buffer size should be large than 128 byts. + * @param rd_len The data length needs to be read. + * + * @return None. + */ +static inline void uart_ll_read_rxfifo(uart_dev_t *hw, uint8_t *buf, uint32_t rd_len) +{ + //Get the UART fifo addr, ESP32-S2 have 2 UART + uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : UART_FIFO_AHB_REG(1); + for(int i = 0; i < rd_len; i++) { + buf[i] = READ_PERI_REG(fifo_addr); + } +} + +/** + * @brief Write byte to the UART txfifo. + * + * @param hw Beginning address of the peripheral registers. + * @param buf The data buffer. + * @param wr_len The data length needs to be writen. + * + * @return None + */ +static inline void uart_ll_write_txfifo(uart_dev_t *hw, const uint8_t *buf, uint32_t wr_len) +{ + //Get the UART fifo addr, ESP32-S2 have 2 UART + uint32_t fifo_addr = (hw == &UART0) ? UART_FIFO_AHB_REG(0) : UART_FIFO_AHB_REG(1); + for(int i = 0; i < wr_len; i++) { + WRITE_PERI_REG(fifo_addr, buf[i]); + } +} + +/** + * @brief Reset the UART hw rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None + */ +static inline void uart_ll_rxfifo_rst(uart_dev_t *hw) +{ + hw->conf0.rxfifo_rst = 1; + hw->conf0.rxfifo_rst = 0; +} + +/** + * @brief Reset the UART hw txfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None + */ +static inline void uart_ll_txfifo_rst(uart_dev_t *hw) +{ + hw->conf0.txfifo_rst = 1; + hw->conf0.txfifo_rst = 0; +} + +/** + * @brief Get the length of readable data in UART rxfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The readable data length in rxfifo. + */ +static inline uint32_t uart_ll_get_rxfifo_len(uart_dev_t *hw) +{ + return hw->status.rxfifo_cnt; +} + +/** + * @brief Get the writable data length of UART txfifo. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The data length of txfifo can be written. + */ +static inline uint32_t uart_ll_get_txfifo_len(uart_dev_t *hw) +{ + return UART_LL_FIFO_DEF_LEN - hw->status.txfifo_cnt; +} + +/** + * @brief Configure the UART stop bit. + * + * @param hw Beginning address of the peripheral registers. + * @param stop_bit The stop bit number to be set. + * + * @return None. + */ +static inline void uart_ll_set_stop_bits(uart_dev_t *hw, uart_stop_bits_t stop_bit) +{ + hw->conf0.stop_bit_num = stop_bit; +} + +/** + * @brief Get the configuration of the UART stop bit. + * + * @param hw Beginning address of the peripheral registers. + * @param stop_bit The pointer to accept the stop bit configuration + * + * @return None. + */ +static inline void uart_ll_get_stop_bits(uart_dev_t *hw, uart_stop_bits_t *stop_bit) +{ + *stop_bit = hw->conf0.stop_bit_num; +} + +/** + * @brief Configure the UART parity check mode. + * + * @param hw Beginning address of the peripheral registers. + * @param parity_mode The parity check mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_parity(uart_dev_t *hw, uart_parity_t parity_mode) +{ + if(parity_mode != UART_PARITY_DISABLE) { + hw->conf0.parity = parity_mode & 0x1; + } + hw->conf0.parity_en = (parity_mode >> 1) & 0x1; +} + +/** + * @brief Get the UART parity check mode configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param parity_mode The pointer to accept the parity check mode configuration. + * + * @return None. + */ +static inline void uart_ll_get_parity(uart_dev_t *hw, uart_parity_t *parity_mode) +{ + if(hw->conf0.parity_en) { + *parity_mode = 0X2 | hw->conf0.parity; + } else { + *parity_mode = UART_PARITY_DISABLE; + } +} + +/** + * @brief Set the UART rxfifo full threshold value. When the data in rxfifo is more than the threshold value, + * it will produce rxfifo_full_int_raw interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param full_thrhd The full threshold value of the rxfifo. `full_thrhd` should be less than `UART_LL_FIFO_DEF_LEN`. + * + * @return None. + */ +static inline void uart_ll_set_rxfifo_full_thr(uart_dev_t *hw, uint16_t full_thrhd) +{ + hw->conf1.rxfifo_full_thrhd = full_thrhd; +} + +/** + * @brief Set the txfifo empty threshold. when the data length in txfifo is less than threshold value, + * it will produce txfifo_empty_int_raw interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param empty_thrhd The empty threshold of txfifo. + * + * @return None. + */ +static inline void uart_ll_set_txfifo_empty_thr(uart_dev_t *hw, uint16_t empty_thrhd) +{ + hw->conf1.txfifo_empty_thrhd = empty_thrhd; +} + +/** + * @brief Set the UART rx-idle threshold value. when receiver takes more time than rx_idle_thrhd to receive a byte data, + * it will produce frame end signal for uhci to stop receiving data. + * + * @param hw Beginning address of the peripheral registers. + * @param rx_idle_thr The rx-idle threshold to be set. + * + * @return None. + */ +static inline void uart_ll_set_rx_idle_thr(uart_dev_t *hw, uint32_t rx_idle_thr) +{ + hw->idle_conf.rx_idle_thrhd = rx_idle_thr; +} + +/** + * @brief Configure the duration time between transfers. + * + * @param hw Beginning address of the peripheral registers. + * @param idle_num the duration time between transfers. + * + * @return None. + */ +static inline void uart_ll_set_tx_idle_num(uart_dev_t *hw, uint32_t idle_num) +{ + hw->idle_conf.tx_idle_num = idle_num; +} + +/** + * @brief Configure the timeout value for receiver receiving a byte, and enable rx timeout function. + * + * @param hw Beginning address of the peripheral registers. + * @param tout_thr The timeout value. The rx timeout function will be disabled if `tout_thr == 0`. + * + * @return None. + */ +static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint8_t tout_thr) +{ + if(tout_thr > 0) { + hw->mem_conf.rx_tout_thrhd = tout_thr; + hw->conf1.rx_tout_en = 1; + } else { + hw->conf1.rx_tout_en = 0; + } +} + +/** + * @brief Configure the transmiter to send break chars. + * + * @param hw Beginning address of the peripheral registers. + * @param break_num The number of the break chars need to be send. + * + * @return None. + */ +static inline void uart_ll_tx_break(uart_dev_t *hw, uint32_t break_num) +{ + if(break_num > 0) { + hw->idle_conf.tx_brk_num = break_num; + hw->conf0.txd_brk = 1; + } else { + hw->conf0.txd_brk = 0; + } +} + +/** + * @brief Configure the UART hardware flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl The hw flow control configuration. + * @param rx_thrs The rx flow control signal will be active if the data length in rxfifo is more than this value. + * + * @return None. + */ +static inline void uart_ll_set_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t flow_ctrl, uint32_t rx_thrs) +{ + //only when UART_HW_FLOWCTRL_RTS is set , will the rx_thresh value be set. + if(flow_ctrl & UART_HW_FLOWCTRL_RTS) { + hw->mem_conf.rx_flow_thrhd = rx_thrs; + hw->conf1.rx_flow_en = 1; + } else { + hw->conf1.rx_flow_en = 0; + } + if(flow_ctrl & UART_HW_FLOWCTRL_CTS) { + hw->conf0.tx_flow_en = 1; + } else { + hw->conf0.tx_flow_en = 0; + } +} + +/** + * @brief Configure the hardware flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl A pointer to accept the hw flow control configuration. + * + * @return None. + */ +static inline void uart_ll_get_hw_flow_ctrl(uart_dev_t *hw, uart_hw_flowcontrol_t *flow_ctrl) +{ + *flow_ctrl = UART_HW_FLOWCTRL_DISABLE; + if(hw->conf1.rx_flow_en) { + *flow_ctrl |= UART_HW_FLOWCTRL_RTS; + } + if(hw->conf0.tx_flow_en) { + *flow_ctrl |= UART_HW_FLOWCTRL_CTS; + } +} + +/** + * @brief Configure the software flow control. + * + * @param hw Beginning address of the peripheral registers. + * @param flow_ctrl The UART sofware flow control settings. + * @param sw_flow_ctrl_en Set true to enable software flow control, otherwise set it false. + * + * @return None. + */ +static inline void uart_ll_set_sw_flow_ctrl(uart_dev_t *hw, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en) +{ + if(sw_flow_ctrl_en) { + hw->swfc_conf1.xon_threshold = flow_ctrl->xon_thrd; + hw->swfc_conf0.xoff_threshold = flow_ctrl->xoff_thrd; + hw->swfc_conf1.xon_char = flow_ctrl->xon_char; + hw->swfc_conf0.xoff_char = flow_ctrl->xoff_char; + hw->flow_conf.sw_flow_con_en = 1; + hw->flow_conf.xonoff_del = 1; + } else { + hw->flow_conf.sw_flow_con_en = 0; + hw->flow_conf.xonoff_del = 0; + } +} + +/** + * @brief Configure the AT cmd char. When the receiver receives a continuous AT cmd char, it will produce at_cmd_char_det interrupt. + * + * @param hw Beginning address of the peripheral registers. + * @param cmd_char The AT cmd char configuration.The configuration member is: + * - cmd_char The AT cmd character + * - char_num The number of received AT cmd char must be equal to or greater than this value + * - gap_tout The interval between each AT cmd char, when the duration is less than this value, it will not take this data as AT cmd char + * - pre_idle The idle time before the first AT cmd char, when the duration is less than this value, it will not take the previous data as the last AT cmd char + * - post_idle The idle time after the last AT cmd char, when the duration is less than this value, it will not take this data as the first AT cmd char + * + * @return None. + */ +static inline void uart_ll_set_at_cmd_char(uart_dev_t *hw, uart_at_cmd_t *cmd_char) +{ + hw->at_cmd_char.data = cmd_char->cmd_char; + hw->at_cmd_char.char_num = cmd_char->char_num; + hw->at_cmd_postcnt.post_idle_num = cmd_char->post_idle; + hw->at_cmd_precnt.pre_idle_num = cmd_char->pre_idle; + hw->at_cmd_gaptout.rx_gap_tout = cmd_char->gap_tout; +} + +/** + * @brief Set the UART data bit mode. + * + * @param hw Beginning address of the peripheral registers. + * @param data_bit The data bit mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_data_bit_num(uart_dev_t *hw, uart_word_length_t data_bit) +{ + hw->conf0.bit_num = data_bit; +} + +/** + * @brief Get the UART source clock. + * + * @param hw Beginning address of the peripheral registers. + * @param source_clk The pointer to accept the UART source clock configuration. + * + * @return None. + */ +static inline void uart_ll_get_sclk(uart_dev_t *hw, uart_sclk_t* source_clk) +{ + *source_clk = hw->conf0.tick_ref_always_on ? UART_SCLK_APB : UART_SCLK_REF_TICK; +} + +/** + * @brief Set the rts active level. + * + * @param hw Beginning address of the peripheral registers. + * @param level The rts active level, 0 or 1. + * + * @return None. + */ +static inline void uart_ll_set_rts_active_level(uart_dev_t *hw, int level) +{ + hw->conf0.sw_rts = level & 0x1; +} + +/** + * @brief Set the dtr active level. + * + * @param hw Beginning address of the peripheral registers. + * @param level The dtr active level, 0 or 1. + * + * @return None. + */ +static inline void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) +{ + hw->conf0.sw_dtr = level & 0x1; +} + +/** + * @brief Set the UART wakeup threshold. + * + * @param hw Beginning address of the peripheral registers. + * @param wakeup_thrd The wakeup threshold value to be set. When the input rx edge changes more than this value, + * the UART will active from light sleeping mode. + * + * @return None. + */ +static inline void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) +{ + hw->sleep_conf.active_threshold = wakeup_thrd - SOC_UART_MIN_WAKEUP_THRESH; +} + +/** + * @brief Configure the UART work in normal mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_normal(uart_dev_t *hw) +{ + hw->rs485_conf.en = 0; + hw->rs485_conf.tx_rx_en = 0; + hw->rs485_conf.rx_busy_tx_en = 0; + hw->conf0.irda_en = 0; +} + +/** + * @brief Configure the UART work in rs485_app_ctrl mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_rs485_app_ctrl(uart_dev_t *hw) +{ + // Application software control, remove echo + hw->rs485_conf.rx_busy_tx_en = 1; + hw->conf0.irda_en = 0; + hw->conf0.sw_rts = 0; + hw->conf0.irda_en = 0; + hw->rs485_conf.en = 1; +} + +/** + * @brief Configure the UART work in rs485_half_duplex mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_rs485_half_duplex(uart_dev_t *hw) +{ + // Enable receiver, sw_rts = 1 generates low level on RTS pin + hw->conf0.sw_rts = 1; + // Must be set to 0 to automatically remove echo + hw->rs485_conf.tx_rx_en = 0; + // This is to void collision + hw->rs485_conf.rx_busy_tx_en = 1; + hw->conf0.irda_en = 0; + hw->rs485_conf.en = 1; +} + +/** + * @brief Configure the UART work in collision_detect mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_collision_detect(uart_dev_t *hw) +{ + hw->conf0.irda_en = 0; + // Transmitters output signal loop back to the receivers input signal + hw->rs485_conf.tx_rx_en = 1 ; + // Transmitter should send data when the receiver is busy + hw->rs485_conf.rx_busy_tx_en = 1; + hw->conf0.sw_rts = 0; + hw->rs485_conf.en = 1; +} + +/** + * @brief Configure the UART work in irda mode. + * + * @param hw Beginning address of the peripheral registers. + * + * @return None. + */ +static inline void uart_ll_set_mode_irda(uart_dev_t *hw) +{ + hw->rs485_conf.en = 0; + hw->rs485_conf.tx_rx_en = 0; + hw->rs485_conf.rx_busy_tx_en = 0; + hw->conf0.sw_rts = 0; + hw->conf0.irda_en = 1; +} + +/** + * @brief Set uart mode. + * + * @param hw Beginning address of the peripheral registers. + * @param mode The UART mode to be set. + * + * @return None. + */ +static inline void uart_ll_set_mode(uart_dev_t *hw, uart_mode_t mode) +{ + switch (mode) { + default: + case UART_MODE_UART: + uart_ll_set_mode_normal(hw); + break; + case UART_MODE_RS485_COLLISION_DETECT: + uart_ll_set_mode_collision_detect(hw); + break; + case UART_MODE_RS485_APP_CTRL: + uart_ll_set_mode_rs485_app_ctrl(hw); + break; + case UART_MODE_RS485_HALF_DUPLEX: + uart_ll_set_mode_rs485_half_duplex(hw); + break; + case UART_MODE_IRDA: + uart_ll_set_mode_irda(hw); + break; + } +} + +/** + * @brief Get the UART AT cmd char configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param cmd_char The Pointer to accept value of UART AT cmd char. + * @param char_num Pointer to accept the repeat number of UART AT cmd char. + * + * @return None. + */ +static inline void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char, uint8_t *char_num) +{ + *cmd_char = hw->at_cmd_char.data; + *char_num = hw->at_cmd_char.char_num; +} + +/** + * @brief Get the UART wakeup threshold value. + * + * @param hw Beginning address of the peripheral registers. + * + * @return The UART wakeup threshold value. + */ +static inline uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw) +{ + return hw->sleep_conf.active_threshold; +} + +/** + * @brief Get the UART data bit configuration. + * + * @param hw Beginning address of the peripheral registers. + * @param data_bit The pointer to accept the UART data bit configuration. + * + * @return The bit mode. + */ +static inline void uart_ll_get_data_bit_num(uart_dev_t *hw, uart_word_length_t *data_bit) +{ + *data_bit = hw->conf0.bit_num; +} + +/** + * @brief Check if the UART sending state machine is in the IDLE state. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if the state machine is in the IDLE state, otherwise false is returned. + */ +static inline bool uart_ll_is_tx_idle(uart_dev_t *hw) +{ + return ((hw->status.txfifo_cnt == 0) && (hw->fsm_status.st_utx_out == 0)); +} + +/** + * @brief Check if the UART rts flow control is enabled. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if hw rts flow control is enabled, otherwise false is returned. + */ +static inline bool uart_ll_is_hw_rts_en(uart_dev_t *hw) +{ + return hw->conf1.rx_flow_en; +} + +/** + * @brief Check if the UART cts flow control is enabled. + * + * @param hw Beginning address of the peripheral registers. + * + * @return True if hw cts flow control is enabled, otherwise false is returned. + */ +static inline bool uart_ll_is_hw_cts_en(uart_dev_t *hw) +{ + return hw->conf0.tx_flow_en; +} + +/** + * @brief Configure TX signal loop back to RX module, just for the testing purposes + * + * @param hw Beginning address of the peripheral registers. + * @param loop_back_en Set ture to enable the loop back function, else set it false. + * + * @return None + */ +static inline void uart_ll_set_loop_back(uart_dev_t *hw, bool loop_back_en) +{ + hw->conf0.loopback = loop_back_en; +} + +/** + * @brief Inverse the UART signal with the given mask. + * + * @param hw Beginning address of the peripheral registers. + * @param inv_mask The UART signal bitmap needs to be inversed. + * Use the ORred mask of `uart_signal_inv_t`; + * + * @return None. + */ +static inline void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask) +{ + typeof(hw->conf0) conf0_reg = hw->conf0; + conf0_reg.irda_tx_inv |= (inv_mask & UART_SIGNAL_IRDA_TX_INV); + conf0_reg.irda_rx_inv |= (inv_mask & UART_SIGNAL_IRDA_RX_INV); + conf0_reg.rxd_inv |= (inv_mask & UART_SIGNAL_RXD_INV); + conf0_reg.cts_inv |= (inv_mask & UART_SIGNAL_CTS_INV); + conf0_reg.dsr_inv |= (inv_mask & UART_SIGNAL_DSR_INV); + conf0_reg.txd_inv |= (inv_mask & UART_SIGNAL_TXD_INV); + conf0_reg.rts_inv |= (inv_mask & UART_SIGNAL_RTS_INV); + conf0_reg.dtr_inv |= (inv_mask & UART_SIGNAL_DTR_INV); + hw->conf0.val = conf0_reg.val; +} diff --git a/components/soc/esp32s2beta/include/soc/uart_caps.h b/components/soc/esp32s2beta/include/soc/uart_caps.h index 1981f7ebf..b6a84ce84 100644 --- a/components/soc/esp32s2beta/include/soc/uart_caps.h +++ b/components/soc/esp32s2beta/include/soc/uart_caps.h @@ -1,9 +1,9 @@ -// Copyright 2017-2018 Espressif Systems (Shanghai) PTE LTD +// Copyright 2010-2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// + // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -18,8 +18,15 @@ extern "C" { #endif -#define SOC_UART_NUM 2 +#define UART_FIFO_LEN (128) /*!< The UART hardware FIFO length */ +#define UART_BITRATE_MAX (5000000) /*!< Max bit rate supported by UART */ + +// ESP32-S2 have 2 UART. +#define SOC_UART_NUM (2) +#define SOC_UART_MIN_WAKEUP_THRESH (2) +#define UART_INTR_MASK (0x7ffff) //All interrupt mask #ifdef __cplusplus } #endif + diff --git a/components/soc/esp32s2beta/sources.cmake b/components/soc/esp32s2beta/sources.cmake index c7a10af4b..c2260099b 100644 --- a/components/soc/esp32s2beta/sources.cmake +++ b/components/soc/esp32s2beta/sources.cmake @@ -15,7 +15,9 @@ set(SOC_SRCS "adc_periph.c" "spi_periph.c" "ledc_periph.c" "i2s_periph.c" - "i2c_periph.c") + "i2c_periph.c" + "uart_periph.c" + ) if(NOT CMAKE_BUILD_EARLY_EXPANSION) set_source_files_properties("esp32s2beta/rtc_clk.c" PROPERTIES diff --git a/components/soc/esp32s2beta/uart_periph.c b/components/soc/esp32s2beta/uart_periph.c new file mode 100644 index 000000000..b3f484d76 --- /dev/null +++ b/components/soc/esp32s2beta/uart_periph.c @@ -0,0 +1,37 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "soc/uart_periph.h" + +/* + Bunch of constants for every UART peripheral: GPIO signals, irqs, hw addr of registers etc +*/ +const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM] = { + { + .tx_sig = U0TXD_OUT_IDX, + .rx_sig = U0RXD_IN_IDX, + .rts_sig = U0RTS_OUT_IDX, + .cts_sig = U0CTS_IN_IDX, + .irq = ETS_UART0_INTR_SOURCE, + .module = PERIPH_UART0_MODULE, + }, + { + .tx_sig = U1TXD_OUT_IDX, + .rx_sig = U1RXD_IN_IDX, + .rts_sig = U1RTS_OUT_IDX, + .cts_sig = U1CTS_IN_IDX, + .irq = ETS_UART1_INTR_SOURCE, + .module = PERIPH_UART1_MODULE, + }, +}; diff --git a/components/soc/include/hal/uart_hal.h b/components/soc/include/hal/uart_hal.h new file mode 100644 index 000000000..1c9d65d5b --- /dev/null +++ b/components/soc/include/hal/uart_hal.h @@ -0,0 +1,426 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/******************************************************************************* + * NOTICE + * The hal is not public api, don't use in application code. + * See readme.md in soc/include/hal/readme.md + ******************************************************************************/ + +// The HAL layer for UART. +// There is no parameter check in the hal layer, so the caller must ensure the correctness of the parameters. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "hal/uart_ll.h" +#include "hal/uart_types.h" + +/** + * Context that should be maintained by both the driver and the HAL + */ +typedef struct { + uart_dev_t *dev; +} uart_hal_context_t; + +/** + * @brief Clear the UART interrupt status + * + * @param hal Context of the HAL layer + * @param mask The interrupt status mask to be cleared. Using the ORred mask of `UART_INTR_RXFIFO_FULL ... UART_INTR_CMD_CHAR_DET` + * + * @return None + */ +#define uart_hal_clr_intsts_mask(hal, mask) uart_ll_clr_intsts_mask((hal)->dev, mask) + +/** + * @brief Disable the UART interrupt + * + * @param hal Context of the HAL layer + * @param mask The interrupt mask to be disabled. Using the ORred mask of `UART_INTR_RXFIFO_FULL ... UART_INTR_CMD_CHAR_DET` + * + * @return None + */ +#define uart_hal_disable_intr_mask(hal, mask) uart_ll_disable_intr_mask((hal)->dev, mask) + +/** + * @brief Enable the UART interrupt + * + * @param hal Context of the HAL layer + * @param mask The UART interrupt mask to be enabled. Using the ORred mask of `UART_INTR_RXFIFO_FULL ... UART_INTR_CMD_CHAR_DET` + * + * @return None + */ +#define uart_hal_ena_intr_mask(hal, mask) uart_ll_ena_intr_mask((hal)->dev, mask) + +/** + * @brief Get the UART interrupt status + * + * @param hal Context of the HAL layer + * + * @return UART interrupt status + */ +#define uart_hal_get_intsts_mask(hal) uart_ll_get_intsts_mask((hal)->dev) + +/** + * @brief Get the UART pattern char configuration + * + * @param hal Context of the HAL layer + * @param cmd_char Pointer to accept UART AT cmd char + * @param char_num Pointer to accept the `UART_CHAR_NUM` configuration + * + * @return None + */ +#define uart_hal_get_at_cmd_char(hal, cmd_char, char_num) uart_ll_get_at_cmd_char((hal)->dev, cmd_char, char_num) + +/** + * @brief Set the UART rst signal active level + * + * @param hal Context of the HAL layer + * @param active_level The rts active level. The active level is low if set to 0. The active level is high if set to 1 + * + * @return None + */ +#define uart_hal_set_rts(hal, active_level) uart_ll_set_rts_active_level((hal)->dev, active_level) + +/** + * @brief Get the txfifo writeable length(in byte) + * + * @param hal Context of the HAL layer + * + * @return UART txfifo writeable length + */ +#define uart_hal_get_txfifo_len(hal) uart_ll_get_txfifo_len((hal)->dev) + +/** + * @brief Check if the UART sending state machine is in the IDLE state. + * + * @param hal Context of the HAL layer + * + * @return True if the state machine is in the IDLE state, otherwise false will be returned. + */ +#define uart_hal_is_tx_idle(hal) uart_ll_is_tx_idle((hal)->dev) + +/** + * @brief Read data from the UART rxfifo + * + * @param hal Context of the HAL layer + * @param buf Pointer to the buffer used to store the read data. The buffer size should be large than 128 byts + * @param rd_len The length has been read out from the rxfifo + * + * @return None + */ +void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *rd_len); + +/** + * @brief Write data into the UART txfifo + * + * @param hal Context of the HAL layer + * @param buf Pointer of the data buffer need to be written to txfifo + * @param data_size The data size(in byte) need to be written + * @param write_size The size has been written + * + * @return None + */ +void uart_hal_write_txfifo(uart_hal_context_t *hal, const uint8_t *buf, uint32_t data_size, uint32_t *write_size); + +/** + * @brief Reset the UART txfifo + * + * @param hal Context of the HAL layer + * + * @return None + */ +void uart_hal_txfifo_rst(uart_hal_context_t *hal); + +/** + * @brief Reset the UART rxfifo + * + * @param hal Context of the HAL layer + * + * @return None + */ +void uart_hal_rxfifo_rst(uart_hal_context_t *hal); + +/** + * @brief Init the UART hal and set the UART to the default configuration. + * + * @param hal Context of the HAL layer + * @param uart_num The uart port number, the max port number is (UART_NUM_MAX -1) + * + * @return None + */ +void uart_hal_init(uart_hal_context_t *hal, uart_port_t uart_num); + +/** + * @brief Configure the UART baud-rate and select the source clock + * + * @param hal Context of the HAL layer + * @param source_clk The UART source clock. Support `UART_SCLK_REF_TICK` and `UART_SCLK_APB` + * @param baud_rate The baud-rate to be set + * + * @return None + */ +void uart_hal_set_baudrate(uart_hal_context_t *hal, uart_sclk_t source_clk, uint32_t baud_rate); + +/** + * @brief Configure the UART stop bit + * + * @param hal Context of the HAL layer + * @param stop_bit The stop bit to be set + * + * @return None + */ +void uart_hal_set_stop_bits(uart_hal_context_t *hal, uart_stop_bits_t stop_bit); + +/** + * @brief Configure the UART data bit + * + * @param hal Context of the HAL layer + * @param data_bit The data bit to be set + * + * @return None + */ +void uart_hal_set_data_bit_num(uart_hal_context_t *hal, uart_word_length_t data_bit); + +/** + * @brief Configure the UART parity mode + * + * @param hal Context of the HAL layer + * @param parity_mode The UART parity mode to be set + * + * @return None + */ +void uart_hal_set_parity(uart_hal_context_t *hal, uart_parity_t parity_mode); + +/** + * @brief Configure the UART hardware flow control + * + * @param hal Context of the HAL layer + * @param flow_ctrl The flow control mode to be set + * @param rx_thresh The rts flow control signal will be active if the data length in rxfifo is large than this value + * + * @return None + */ +void uart_hal_set_hw_flow_ctrl(uart_hal_context_t *hal, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh); + +/** + * @brief Configure the UART AT cmd char detect function. When the receiver receives a continuous AT cmd char, it will produce a interrupt + * + * @param hal Context of the HAL layer + * @param at_cmd The AT cmd char detect configuration + * + * @return None. + */ +void uart_hal_set_at_cmd_char(uart_hal_context_t *hal, uart_at_cmd_t *at_cmd); + +/** + * @brief Set the timeout value of the UART receiver + * + * @param hal Context of the HAL layer + * @param tout The timeout value for receiver to receive a data + * + * @return None + */ +void uart_hal_set_rx_timeout(uart_hal_context_t *hal, const uint8_t tout); + +/** + * @brief Set the UART dtr signal active level + * + * @param hal Context of the HAL layer + * @param active_level The dtr active level. The active level is low if set to 0. The active level is high if set to 1 + * + * @return None + */ +void uart_hal_set_dtr(uart_hal_context_t *hal, int active_level); + +/** + * @brief Set the UART software flow control + * + * @param hal Context of the HAL layer + * @param flow_ctrl The software flow control configuration + * @param sw_flow_ctrl_en Set true to enable the software flow control, otherwise set it false + * + * @return None + */ +void uart_hal_set_sw_flow_ctrl(uart_hal_context_t *hal, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en); + +/** + * @brief Set the UART tx idle number + * + * @param hal Context of the HAL layer + * @param idle_num The cycle number betwin the two transmission + * + * @return None + */ +void uart_hal_set_tx_idle_num(uart_hal_context_t *hal, uint16_t idle_num); + +/** + * @brief Set the UART rxfifo full threshold + * + * @param hal Context of the HAL layer + * @param full_thrhd The rxfifo full threshold. If the `UART_RXFIFO_FULL` interrupt is enabled and + * the data length in rxfifo is more than this value, it will generate `UART_RXFIFO_FULL` interrupt + * + * @return None + */ +void uart_hal_set_rxfifo_full_thr(uart_hal_context_t *hal, uint32_t full_thrhd); + +/** + * @brief Set the UART txfifo empty threshold + * + * @param hal Context of the HAL layer + * @param empty_thrhd The txfifo empty threshold to be set. If the `UART_TXFIFO_EMPTY` interrupt is enabled and + * the data length in txfifo is less than this value, it will generate `UART_TXFIFO_EMPTY` interrupt + * + * @return None + */ +void uart_hal_set_txfifo_empty_thr(uart_hal_context_t *hal, uint32_t empty_thrhd); + +/** + * @brief Configure the UART to send a number of break(NULL) chars + * + * @param hal Context of the HAL layer + * @param break_num The number of the break char need to be send + * + * @return None + */ +void uart_hal_tx_break(uart_hal_context_t *hal, uint32_t break_num); + +/** + * @brief Configure the UART wake up function. + * Note that RXD cannot be input through GPIO Matrix but only through IO_MUX when use this function + * + * @param hal Context of the HAL layer + * @param wakeup_thrd The wake up threshold to be set. The system will be woken up from light-sleep when the input RXD edge changes more times than `wakeup_thrd+2` + * + * @return None + */ +void uart_hal_set_wakeup_thrd(uart_hal_context_t *hal, uint32_t wakeup_thrd); + +/** + * @brief Configure the UART mode + * + * @param hal Context of the HAL layer + * @param mode The UART mode to be set + * + * @return None + */ +void uart_hal_set_mode(uart_hal_context_t *hal, uart_mode_t mode); + +/** + * @brief Configure the UART hardware to inverse the signals + * + * @param hal Context of the HAL layer + * @param inv_mask The sigal mask needs to be inversed. Use the ORred mask of type `uart_signal_inv_t` + * + * @return None + */ +void uart_hal_inverse_signal(uart_hal_context_t *hal, uint32_t inv_mask); + +/** + * @brief Get the UART wakeup threshold configuration + * + * @param hal Context of the HAL layer + * @param wakeup_thrd Pointer to accept the value of UART wakeup threshold configuration + * + * @return None + */ +void uart_hal_get_wakeup_thrd(uart_hal_context_t *hal, uint32_t *wakeup_thrd); + +/** + * @brief Get the UART data bit configuration + * + * @param hal Context of the HAL layer + * @param data_bit Pointer to accept the value of UART data bit configuration + * + * @return None + */ +void uart_hal_get_data_bit_num(uart_hal_context_t *hal, uart_word_length_t *data_bit); + +/** + * @brief Get the UART stop bit configuration + * + * @param hal Context of the HAL layer + * @param stop_bit Pointer to accept the value of UART stop bit configuration + * + * @return None + */ +void uart_hal_get_stop_bits(uart_hal_context_t *hal, uart_stop_bits_t *stop_bit); + +/** + * @brief Get the UART parity mode configuration + * + * @param hal Context of the HAL layer + * @param parity_mode Pointer to accept the UART parity mode configuration + * + * @return None + */ +void uart_hal_get_parity(uart_hal_context_t *hal, uart_parity_t *parity_mode); + +/** + * @brief Get the UART baud-rate configuration + * + * @param hal Context of the HAL layer + * @param baud_rate Pointer to accept the current baud-rate + * + * @return None + */ +void uart_hal_get_baudrate(uart_hal_context_t *hal, uint32_t *baud_rate); + +/** + * @brief Get the hw flow control configuration + * + * @param hal Context of the HAL layer + * @param flow_ctrl Pointer to accept the UART flow control configuration + * + * @return None + */ +void uart_hal_get_hw_flow_ctrl(uart_hal_context_t *hal, uart_hw_flowcontrol_t *flow_ctrl); + +/** + * @brief Check if the UART rts flow control is enabled + * + * @param hal Context of the HAL layer + * + * @return True if rts flow control is enabled, otherwise false will be returned + */ +bool uart_hal_is_hw_rts_en(uart_hal_context_t *hal); + +/** + * @brief Get the UART source clock configuration + * + * @param hal Context of the HAL layer + * @param sclk The poiter to accept the UART source clock configuration + * + * @return None + */ +void uart_hal_get_sclk(uart_hal_context_t *hal, uart_sclk_t *sclk); + +/** + * @brief Configure TX signal loop back to RX module, just for the testing purposes + * + * @param hal Context of the HAL layer + * @param loop_back_en Set ture to enable the loop back function, else set it false. + * + * @return None + */ +void uart_hal_set_loop_back(uart_hal_context_t *hal, bool loop_back_en); + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/components/soc/include/hal/uart_types.h b/components/soc/include/hal/uart_types.h new file mode 100644 index 000000000..852c6c62e --- /dev/null +++ b/components/soc/include/hal/uart_types.h @@ -0,0 +1,145 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "soc/uart_caps.h" + + +/** + * @brief UART port number, can be UART_NUM_0 ~ (UART_NUM_MAX -1). + */ +typedef int uart_port_t; + +/** + * @brief UART mode selection + */ +typedef enum { + UART_MODE_UART = 0x00, /*!< mode: regular UART mode*/ + UART_MODE_RS485_HALF_DUPLEX = 0x01, /*!< mode: half duplex RS485 UART mode control by RTS pin */ + UART_MODE_IRDA = 0x02, /*!< mode: IRDA UART mode*/ + UART_MODE_RS485_COLLISION_DETECT = 0x03, /*!< mode: RS485 collision detection UART mode (used for test purposes)*/ + UART_MODE_RS485_APP_CTRL = 0x04, /*!< mode: application control RS485 UART mode (used for test purposes)*/ +} uart_mode_t; + +/** + * @brief UART word length constants + */ +typedef enum { + UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/ + UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/ + UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/ + UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/ + UART_DATA_BITS_MAX = 0x4, +} uart_word_length_t; + +/** + * @brief UART stop bits number + */ +typedef enum { + UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/ + UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/ + UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/ + UART_STOP_BITS_MAX = 0x4, +} uart_stop_bits_t; + +/** + * @brief UART parity constants + */ +typedef enum { + UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/ + UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/ + UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/ +} uart_parity_t; + +/** + * @brief UART hardware flow control modes + */ +typedef enum { + UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/ + UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/ + UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/ + UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/ + UART_HW_FLOWCTRL_MAX = 0x4, +} uart_hw_flowcontrol_t; + +/** + * @brief UART signal bit map + */ +typedef enum { + UART_SIGNAL_IRDA_TX_INV = (0x1 << 0), /*!< inverse the UART irda_tx signal*/ + UART_SIGNAL_IRDA_RX_INV = (0x1 << 1), /*!< inverse the UART irda_rx signal*/ + UART_SIGNAL_RXD_INV = (0x1 << 2), /*!< inverse the UART rxd signal*/ + UART_SIGNAL_CTS_INV = (0x1 << 3), /*!< inverse the UART cts signal*/ + UART_SIGNAL_DSR_INV = (0x1 << 4), /*!< inverse the UART dsr signal*/ + UART_SIGNAL_TXD_INV = (0x1 << 5), /*!< inverse the UART txd signal*/ + UART_SIGNAL_RTS_INV = (0x1 << 6), /*!< inverse the UART rts signal*/ + UART_SIGNAL_DTR_INV = (0x1 << 7), /*!< inverse the UART dtr signal*/ +} uart_signal_inv_t; + +/** + * @brief UART source clock + */ +typedef enum { + UART_SCLK_APB = 0x0, /*!< UART source clock from APB*/ + UART_SCLK_REF_TICK = 0x01, /*!< UART source clock from REF_TICK*/ +} uart_sclk_t; + +/** + * @brief UART AT cmd char configuration parameters + * Note that this function may different on different chip. Please refer to the TRM at confirguration. + */ +typedef struct { + uint8_t cmd_char; /*!< UART AT cmd char*/ + uint8_t char_num; /*!< AT cmd char repeat number*/ + uint32_t gap_tout; /*!< gap time(in baud-rate) between AT cmd char*/ + uint32_t pre_idle; /*!< the idle time(in baud-rate) between the non AT char and first AT char*/ + uint32_t post_idle; /*!< the idle time(in baud-rate) between the last AT char and the none AT char*/ +} uart_at_cmd_t; + +/** + * @brief UART software flow control configuration parameters + */ +typedef struct { + uint8_t xon_char; /*!< Xon flow control char*/ + uint8_t xoff_char; /*!< Xoff flow control char*/ + uint8_t xon_thrd; /*!< If the software flow control is enabled and the data amount in rxfifo is less than xon_thrd, an xon_char will be sent*/ + uint8_t xoff_thrd; /*!< If the software flow control is enabled and the data amount in rxfifo is more than xoff_thrd, an xoff_char will be sent*/ +} uart_sw_flowctrl_t; + +/** + * @brief UART configuration parameters for uart_param_config function + */ +typedef struct { + int baud_rate; /*!< UART baud rate*/ + uart_word_length_t data_bits; /*!< UART byte size*/ + uart_parity_t parity; /*!< UART parity mode*/ + uart_stop_bits_t stop_bits; /*!< UART stop bits*/ + uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts)*/ + uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold*/ + union { + uart_sclk_t source_clk; /*!< UART source clock selection */ + bool use_ref_tick __attribute__((deprecated)); + }; +} uart_config_t; + +#ifdef __cplusplus +} +#endif diff --git a/components/soc/include/soc/uart_periph.h b/components/soc/include/soc/uart_periph.h index 27324cd1d..7dbf8aedd 100644 --- a/components/soc/include/soc/uart_periph.h +++ b/components/soc/include/soc/uart_periph.h @@ -3,7 +3,6 @@ // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at -// // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software @@ -14,7 +13,19 @@ #pragma once -#include "soc/uart_caps.h" #include "soc/uart_reg.h" #include "soc/uart_struct.h" -#include "soc/uart_channel.h" +#include "soc/uart_caps.h" +#include "soc/periph_defs.h" +#include "soc/gpio_sig_map.h" + +typedef struct { + const uint8_t tx_sig; + const uint8_t rx_sig; + const uint8_t rts_sig; + const uint8_t cts_sig; + const uint8_t irq; + const periph_module_t module; +} uart_signal_conn_t; + +extern const uart_signal_conn_t uart_periph_signal[SOC_UART_NUM]; diff --git a/components/soc/include/soc/uhci_periph.h b/components/soc/include/soc/uhci_periph.h new file mode 100644 index 000000000..cbfae2ac9 --- /dev/null +++ b/components/soc/include/soc/uhci_periph.h @@ -0,0 +1,18 @@ +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "soc/uhci_reg.h" +#include "soc/uhci_struct.h" +#include "soc/periph_defs.h" \ No newline at end of file diff --git a/components/soc/linker.lf b/components/soc/linker.lf index 754b5fa09..847ad9086 100644 --- a/components/soc/linker.lf +++ b/components/soc/linker.lf @@ -12,6 +12,10 @@ entries: rtc_wdt (noflash_text) spi_hal_iram (noflash_text) spi_slave_hal_iram (noflash_text) + if UART_ISR_IN_IRAM = y: + uart_hal_iram (noflash_text) + else: + uart_hal_iram (default) spi_flash_hal_iram (noflash) ledc_hal_iram (noflash_text) i2c_hal_iram (noflash) diff --git a/components/soc/src/hal/uart_hal.c b/components/soc/src/hal/uart_hal.c new file mode 100644 index 000000000..51db4a048 --- /dev/null +++ b/components/soc/src/hal/uart_hal.c @@ -0,0 +1,156 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The HAL layer for UART (common part) +#include "hal/uart_hal.h" + + +void uart_hal_set_baudrate(uart_hal_context_t *hal, uart_sclk_t source_clk, uint32_t baud_rate) +{ + uart_ll_set_baudrate(hal->dev, source_clk, baud_rate); +} + +void uart_hal_get_baudrate(uart_hal_context_t *hal, uint32_t *baud_rate) +{ + *baud_rate = uart_ll_get_baudrate(hal->dev); +} + +void uart_hal_set_stop_bits(uart_hal_context_t *hal, uart_stop_bits_t stop_bit) +{ + uart_ll_set_stop_bits(hal->dev, stop_bit); +} + +void uart_hal_get_stop_bits(uart_hal_context_t *hal, uart_stop_bits_t *stop_bit) +{ + uart_ll_get_stop_bits(hal->dev, stop_bit); +} + +void uart_hal_set_data_bit_num(uart_hal_context_t *hal, uart_word_length_t data_bit) +{ + uart_ll_set_data_bit_num(hal->dev, data_bit); +} + +void uart_hal_get_data_bit_num(uart_hal_context_t *hal, uart_word_length_t *data_bit) +{ + uart_ll_get_data_bit_num(hal->dev, data_bit); +} + +void uart_hal_set_parity(uart_hal_context_t *hal, uart_parity_t parity_mode) +{ + uart_ll_set_parity(hal->dev, parity_mode); +} + +void uart_hal_get_parity(uart_hal_context_t *hal, uart_parity_t *parity_mode) +{ + uart_ll_get_parity(hal->dev, parity_mode); +} + +void uart_hal_set_hw_flow_ctrl(uart_hal_context_t *hal, uart_hw_flowcontrol_t flow_ctrl, uint8_t rx_thresh) +{ + uart_ll_set_hw_flow_ctrl(hal->dev, flow_ctrl, rx_thresh); +} + +void uart_hal_get_hw_flow_ctrl(uart_hal_context_t *hal, uart_hw_flowcontrol_t *flow_ctrl) +{ + uart_ll_get_hw_flow_ctrl(hal->dev, flow_ctrl); +} + +void uart_hal_set_sw_flow_ctrl(uart_hal_context_t *hal, uart_sw_flowctrl_t *flow_ctrl, bool sw_flow_ctrl_en) +{ + uart_ll_set_sw_flow_ctrl(hal->dev, flow_ctrl, sw_flow_ctrl_en); +} + +void uart_hal_set_at_cmd_char(uart_hal_context_t *hal, uart_at_cmd_t *at_cmd) +{ + uart_ll_set_at_cmd_char(hal->dev, at_cmd); +} + +void uart_hal_set_rx_timeout(uart_hal_context_t *hal, const uint8_t tout) +{ + uart_ll_set_rx_tout(hal->dev, tout); +} + +void uart_hal_get_sclk(uart_hal_context_t *hal, uart_sclk_t *sclk) +{ + uart_ll_get_sclk(hal->dev, sclk); +} + +void uart_hal_set_tx_idle_num(uart_hal_context_t *hal, uint16_t idle_num) +{ + uart_ll_set_tx_idle_num(hal->dev, idle_num); +} + +void uart_hal_set_dtr(uart_hal_context_t *hal, int active_level) +{ + uart_ll_set_dtr_active_level(hal->dev, active_level); +} + +void uart_hal_set_rxfifo_full_thr(uart_hal_context_t *hal, uint32_t full_thrhd) +{ + uart_ll_set_rxfifo_full_thr(hal->dev, full_thrhd); +} + +void uart_hal_set_txfifo_empty_thr(uart_hal_context_t *hal, uint32_t empty_thrhd) +{ + uart_ll_set_txfifo_empty_thr(hal->dev, empty_thrhd); +} + +void uart_hal_set_wakeup_thrd(uart_hal_context_t *hal, uint32_t wakeup_thrd) +{ + uart_ll_set_wakeup_thrd(hal->dev, wakeup_thrd); +} + +void uart_hal_get_wakeup_thrd(uart_hal_context_t *hal, uint32_t *wakeup_thrd) +{ + *wakeup_thrd = uart_ll_get_wakeup_thrd(hal->dev); +} + +void uart_hal_set_mode(uart_hal_context_t *hal, uart_mode_t mode) +{ + uart_ll_set_mode(hal->dev, mode); +} + +bool uart_hal_is_hw_rts_en(uart_hal_context_t *hal) +{ + return uart_ll_is_hw_rts_en(hal->dev); +} + +void uart_hal_inverse_signal(uart_hal_context_t *hal, uint32_t inv_mask) +{ + uart_ll_inverse_signal(hal->dev, inv_mask); +} + +void uart_hal_set_loop_back(uart_hal_context_t *hal, bool loop_back_en) +{ + uart_ll_set_loop_back(hal->dev, loop_back_en); +} + +void uart_hal_init(uart_hal_context_t *hal, int uart_num) +{ + // Set default baud: 115200, use APB clock. + const uint32_t baud_def = 115200; + uart_ll_set_baudrate(hal->dev, UART_SCLK_APB, baud_def); + // Set UART mode. + uart_ll_set_mode(hal->dev, UART_MODE_UART); + // Disable UART parity + uart_ll_set_parity(hal->dev, UART_PARITY_DISABLE); + // 8-bit world + uart_ll_set_data_bit_num(hal->dev, UART_DATA_8_BITS); + // 1-bit stop bit + uart_ll_set_stop_bits(hal->dev, UART_STOP_BITS_1); + // Set tx idle + uart_ll_set_tx_idle_num(hal->dev, 0); + // Disable hw-flow control + uart_ll_set_hw_flow_ctrl(hal->dev, UART_HW_FLOWCTRL_DISABLE, 100); +} \ No newline at end of file diff --git a/components/soc/src/hal/uart_hal_iram.c b/components/soc/src/hal/uart_hal_iram.c new file mode 100644 index 000000000..f13ce4b08 --- /dev/null +++ b/components/soc/src/hal/uart_hal_iram.c @@ -0,0 +1,48 @@ +// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// The HAL layer for UART (IRAM part) +#include "hal/uart_hal.h" + +void uart_hal_txfifo_rst(uart_hal_context_t *hal) +{ + uart_ll_txfifo_rst(hal->dev); +} + +void uart_hal_rxfifo_rst(uart_hal_context_t *hal) +{ + uart_ll_rxfifo_rst(hal->dev); +} + +void uart_hal_tx_break(uart_hal_context_t *hal, uint32_t break_num) +{ + uart_ll_tx_break(hal->dev, break_num); +} + +void uart_hal_write_txfifo(uart_hal_context_t *hal, const uint8_t *buf, uint32_t data_size, uint32_t *write_size) +{ + uint16_t fill_len = uart_ll_get_txfifo_len(hal->dev); + if(fill_len > data_size) { + fill_len = data_size; + } + *write_size = fill_len; + uart_ll_write_txfifo(hal->dev, buf, fill_len); +} + +void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *rd_len) +{ + uint16_t read_len = uart_ll_get_rxfifo_len(hal->dev); + *rd_len = read_len; + uart_ll_read_rxfifo(hal->dev, buf, read_len); +} diff --git a/components/vfs/test/test_vfs_select.c b/components/vfs/test/test_vfs_select.c index 313f67138..6255aadcf 100644 --- a/components/vfs/test/test_vfs_select.c +++ b/components/vfs/test/test_vfs_select.c @@ -18,6 +18,7 @@ #include #include "unity.h" #include "freertos/FreeRTOS.h" +#include "soc/uart_struct.h" #include "driver/uart.h" #include "esp_vfs.h" #include "esp_vfs_dev.h" @@ -101,10 +102,11 @@ static void uart1_init(void) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; - uart_param_config(UART_NUM_1, &uart_config); uart_driver_install(UART_NUM_1, 256, 256, 0, NULL, 0); + uart_param_config(UART_NUM_1, &uart_config); } static void send_task(void *param) @@ -128,7 +130,7 @@ static void init(int *uart_fd, int *socket_fd) test_case_uses_tcpip(); uart1_init(); - UART1.conf0.loopback = 1; + uart_set_loop_back(UART_NUM_1, true); *uart_fd = open("/dev/uart/1", O_RDWR); TEST_ASSERT_NOT_EQUAL_MESSAGE(*uart_fd, -1, "Cannot open UART"); @@ -142,7 +144,6 @@ static void deinit(int uart_fd, int socket_fd) { esp_vfs_dev_uart_use_nonblocking(1); close(uart_fd); - UART1.conf0.loopback = 0; uart_driver_delete(UART_NUM_1); close(socket_fd); diff --git a/components/vfs/test/test_vfs_uart.c b/components/vfs/test/test_vfs_uart.c index f28250529..77815aed7 100644 --- a/components/vfs/test/test_vfs_uart.c +++ b/components/vfs/test/test_vfs_uart.c @@ -28,6 +28,7 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "driver/uart.h" +#include "soc/uart_struct.h" #include "esp_vfs_dev.h" #include "esp_vfs.h" #include "sdkconfig.h" @@ -214,10 +215,11 @@ TEST_CASE("Can use termios for UART", "[vfs]") .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; - uart_param_config(UART_NUM_1, &uart_config); uart_driver_install(UART_NUM_1, 256, 256, 0, NULL, 0); + uart_param_config(UART_NUM_1, &uart_config); const int uart_fd = open("/dev/uart/1", O_RDWR); TEST_ASSERT_NOT_EQUAL_MESSAGE(uart_fd, -1, "Cannot open UART"); diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index a8eac66c2..28e0d6f79 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -22,6 +22,7 @@ #include "esp_vfs.h" #include "esp_vfs_dev.h" #include "esp_attr.h" +#include "soc/uart_periph.h" #include "driver/uart.h" #include "sdkconfig.h" #include "driver/uart_select.h" diff --git a/docs/Doxyfile b/docs/Doxyfile index 8dfc41218..ce15c0433 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -116,6 +116,7 @@ INPUT = \ ../../components/soc/include/hal/dac_types.h \ ../../components/soc/include/hal/adc_types.h \ ../../components/soc/include/hal/gpio_types.h \ + ../../components/soc/include/hal/uart_types.h \ ../../components/soc/esp32/include/soc/adc_channel.h \ ../../components/soc/esp32/include/soc/dac_channel.h \ ../../components/soc/esp32/include/soc/touch_channel.h \ diff --git a/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c index f1a91e9bd..6d83a31f2 100644 --- a/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_spp_client/main/spp_client_demo.c @@ -593,14 +593,15 @@ static void spp_uart_init(void) .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_RTS, .rx_flow_ctrl_thresh = 122, + .source_clk = UART_SCLK_APB, }; + //Install UART driver, and get the queue. + uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_uart_queue, 0); //Set UART parameters uart_param_config(UART_NUM_0, &uart_config); //Set UART pins uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - //Install UART driver, and get the queue. - uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_uart_queue, 0); xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL); } diff --git a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c index f1eaba16b..a973afb80 100644 --- a/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c +++ b/examples/bluetooth/bluedroid/ble/ble_spp_server/main/ble_spp_server_demo.c @@ -395,14 +395,15 @@ static void spp_uart_init(void) .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_RTS, .rx_flow_ctrl_thresh = 122, + .source_clk = UART_SCLK_APB, }; + //Install UART driver, and get the queue. + uart_driver_install(UART_NUM_0, 4096, 8192, 10,&spp_uart_queue,0); //Set UART parameters uart_param_config(UART_NUM_0, &uart_config); //Set UART pins uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - //Install UART driver, and get the queue. - uart_driver_install(UART_NUM_0, 4096, 8192, 10,&spp_uart_queue,0); xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL); } diff --git a/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c index 6214dec13..ad397fed2 100644 --- a/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c +++ b/examples/bluetooth/bluedroid/hci/controller_hci_uart/main/controller_hci_uart_demo.c @@ -10,7 +10,9 @@ #include #include "nvs_flash.h" #include "esp_bt.h" +#include "soc/uhci_periph.h" #include "driver/uart.h" +#include "driver/periph_ctrl.h" #include "esp_log.h" static const char *tag = "CONTROLLER_UART_HCI"; diff --git a/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.c b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.c new file mode 100644 index 000000000..8196e89c6 --- /dev/null +++ b/examples/bluetooth/esp_ble_mesh/ble_mesh_client_model/main/board.c @@ -0,0 +1,115 @@ +/* board.c - Board-specific hooks */ + +/* + * Copyright (c) 2017 Intel Corporation + * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" + +#include "driver/uart.h" +#include "esp_log.h" + +#include "esp_ble_mesh_provisioning_api.h" +#include "board.h" + +#define TAG "BOARD" + +#define MESH_UART_NUM UART_NUM_1 + +#define UART_BUF_SIZE 128 + +#define UART1_TX_PIN GPIO_NUM_16 +#define UART1_RX_PIN GPIO_NUM_17 + +extern uint16_t remote_addr; + +struct _led_state led_state[3] = { + { LED_OFF, LED_OFF, LED_R, "red" }, + { LED_OFF, LED_OFF, LED_G, "green" }, + { LED_OFF, LED_OFF, LED_B, "blue" }, +}; + +void board_output_number(esp_ble_mesh_output_action_t action, uint32_t number) +{ + ESP_LOGI(TAG, "Board output number %d", number); +} + +void board_prov_complete(void) +{ + board_led_operation(LED_G, LED_OFF); +} + +void board_led_operation(uint8_t pin, uint8_t onoff) +{ + for (int i = 0; i < ARRAY_SIZE(led_state); i++) { + if (led_state[i].pin != pin) { + continue; + } + if (onoff == led_state[i].previous) { + ESP_LOGW(TAG, "led %s is already %s", + led_state[i].name, (onoff ? "on" : "off")); + return; + } + gpio_set_level(pin, onoff); + led_state[i].previous = onoff; + return; + } + ESP_LOGE(TAG, "LED is not found!"); +} + +static void board_uart_task(void *p) +{ + uint8_t *data = calloc(1, UART_BUF_SIZE); + uint32_t input; + + while (1) { + int len = uart_read_bytes(MESH_UART_NUM, data, UART_BUF_SIZE, 100 / portTICK_RATE_MS); + if (len > 0) { + input = strtoul((const char *)data, NULL, 16); + remote_addr = input & 0xFFFF; + ESP_LOGI(TAG, "%s: input 0x%08x, remote_addr 0x%04x", __func__, input, remote_addr); + memset(data, 0, UART_BUF_SIZE); + } + } + + vTaskDelete(NULL); +} + +static void board_led_init(void) +{ + for (int i = 0; i < ARRAY_SIZE(led_state); i++) { + gpio_pad_select_gpio(led_state[i].pin); + gpio_set_direction(led_state[i].pin, GPIO_MODE_OUTPUT); + gpio_set_level(led_state[i].pin, LED_OFF); + led_state[i].previous = LED_OFF; + } +} + +static void board_uart_init(void) +{ + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, + }; + uart_driver_install(MESH_UART_NUM, UART_BUF_SIZE * 2, 0, 0, NULL, 0); + uart_param_config(MESH_UART_NUM, &uart_config); + uart_set_pin(MESH_UART_NUM, UART1_TX_PIN, UART1_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); +} + +void board_init(void) +{ + board_led_init(); + board_uart_init(); + xTaskCreate(board_uart_task, "board_uart_task", 2048, NULL, 5, NULL); +} diff --git a/examples/ethernet/iperf/main/ethernet_example_main.c b/examples/ethernet/iperf/main/ethernet_example_main.c index 7a57826bf..952cda607 100644 --- a/examples/ethernet/iperf/main/ethernet_example_main.c +++ b/examples/ethernet/iperf/main/ethernet_example_main.c @@ -72,13 +72,12 @@ static void initialize_console(void) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .use_ref_tick = true + .source_clk = UART_SCLK_REF_TICK, }; - ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); - /* Install UART driver for interrupt-driven reads and writes */ ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); + ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); /* Tell VFS to use UART driver */ esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); diff --git a/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c b/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c index 85826fd2d..40d06fb44 100644 --- a/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c +++ b/examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c @@ -72,13 +72,12 @@ static void initialize_console(void) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .use_ref_tick = true + .source_clk = UART_SCLK_REF_TICK, }; - ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); - /* Install UART driver for interrupt-driven reads and writes */ ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); + ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); /* Tell VFS to use UART driver */ esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); diff --git a/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c b/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c index 89457e492..c70f119b1 100644 --- a/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c +++ b/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c @@ -682,8 +682,14 @@ nmea_parser_handle_t nmea_parser_init(const nmea_parser_config_t *config) .data_bits = config->uart.data_bits, .parity = config->uart.parity, .stop_bits = config->uart.stop_bits, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; + if (uart_driver_install(esp_gps->uart_port, CONFIG_NMEA_PARSER_RING_BUFFER_SIZE, 0, + config->uart.event_queue_size, &esp_gps->event_queue, 0) != ESP_OK) { + ESP_LOGE(GPS_TAG, "install uart driver failed"); + goto err_uart_install; + } if (uart_param_config(esp_gps->uart_port, &uart_config) != ESP_OK) { ESP_LOGE(GPS_TAG, "config uart parameter failed"); goto err_uart_config; @@ -693,11 +699,6 @@ nmea_parser_handle_t nmea_parser_init(const nmea_parser_config_t *config) ESP_LOGE(GPS_TAG, "config uart gpio failed"); goto err_uart_config; } - if (uart_driver_install(esp_gps->uart_port, CONFIG_NMEA_PARSER_RING_BUFFER_SIZE, 0, - config->uart.event_queue_size, &esp_gps->event_queue, 0) != ESP_OK) { - ESP_LOGE(GPS_TAG, "install uart driver failed"); - goto err_uart_install; - } /* Set pattern interrupt, used to detect the end of a line */ uart_enable_pattern_det_baud_intr(esp_gps->uart_port, '\n', 1, 9, 0, 0); /* Set pattern queue size */ diff --git a/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c b/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c index 3b4a5872e..33f0d2d71 100644 --- a/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c +++ b/examples/peripherals/uart/uart_async_rxtxtasks/main/uart_async_rxtxtasks_main.c @@ -25,12 +25,13 @@ void init(void) { .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; - uart_param_config(UART_NUM_1, &uart_config); - uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); // We won't use a buffer for sending data. uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, 0, 0, NULL, 0); + uart_param_config(UART_NUM_1, &uart_config); + uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } int sendData(const char* logName, const char* data) diff --git a/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c b/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c index c9b5dbc7b..75283efab 100644 --- a/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c +++ b/examples/peripherals/uart/uart_echo/main/uart_echo_example_main.c @@ -40,11 +40,12 @@ static void echo_task(void *arg) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; + uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL, 0); uart_param_config(UART_NUM_1, &uart_config); uart_set_pin(UART_NUM_1, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS); - uart_driver_install(UART_NUM_1, BUF_SIZE * 2, 0, 0, NULL, 0); // Configure a temporary buffer for the incoming data uint8_t *data = (uint8_t *) malloc(BUF_SIZE); diff --git a/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c b/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c index f6577fba8..6cadc16f6 100644 --- a/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c +++ b/examples/peripherals/uart/uart_echo_rs485/main/rs485_example.c @@ -62,6 +62,7 @@ static void echo_task(void *arg) .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .rx_flow_ctrl_thresh = 122, + .source_clk = UART_SCLK_APB, }; // Set UART log level @@ -69,6 +70,9 @@ static void echo_task(void *arg) ESP_LOGI(TAG, "Start RS485 application test and configure UART."); + // Install UART driver (we don't need an event queue here) + // In this example we don't even use a buffer for sending data. + uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0); // Configure UART parameters uart_param_config(uart_num, &uart_config); @@ -76,10 +80,6 @@ static void echo_task(void *arg) // Set UART1 pins(TX: IO23, RX: I022, RTS: IO18, CTS: IO19) uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS); - // Install UART driver (we don't need an event queue here) - // In this example we don't even use a buffer for sending data. - uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0); - // Set RS485 half duplex mode uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX); diff --git a/examples/peripherals/uart/uart_events/main/uart_events_example_main.c b/examples/peripherals/uart/uart_events/main/uart_events_example_main.c index e6d334712..4d574b355 100644 --- a/examples/peripherals/uart/uart_events/main/uart_events_example_main.c +++ b/examples/peripherals/uart/uart_events/main/uart_events_example_main.c @@ -128,16 +128,17 @@ void app_main(void) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; + //Install UART driver, and get the queue. + uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0); uart_param_config(EX_UART_NUM, &uart_config); //Set UART log level esp_log_level_set(TAG, ESP_LOG_INFO); //Set UART pins (using UART0 default pins ie no changes.) uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - //Install UART driver, and get the queue. - uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0); //Set uart pattern detect function. uart_enable_pattern_det_baud_intr(EX_UART_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0); diff --git a/examples/peripherals/uart/uart_select/main/uart_select_example_main.c b/examples/peripherals/uart/uart_select/main/uart_select_example_main.c index d7b3c8849..5020fb767 100644 --- a/examples/peripherals/uart/uart_select/main/uart_select_example_main.c +++ b/examples/peripherals/uart/uart_select/main/uart_select_example_main.c @@ -27,10 +27,11 @@ static void uart_select_task(void *arg) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; - uart_param_config(UART_NUM_0, &uart_config); uart_driver_install(UART_NUM_0, 2*1024, 0, 0, NULL, 0); + uart_param_config(UART_NUM_0, &uart_config); while (1) { int fd; diff --git a/examples/protocols/icmp_echo/main/echo_example_main.c b/examples/protocols/icmp_echo/main/echo_example_main.c index 53acb1742..573378fe6 100644 --- a/examples/protocols/icmp_echo/main/echo_example_main.c +++ b/examples/protocols/icmp_echo/main/echo_example_main.c @@ -41,12 +41,11 @@ static void initialize_console(void) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .use_ref_tick = true + .source_clk = UART_SCLK_REF_TICK, }; - ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); - /* Install UART driver for interrupt-driven reads and writes */ ESP_ERROR_CHECK(uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0)); + ESP_ERROR_CHECK(uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config)); /* Tell VFS to use UART driver */ esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); diff --git a/examples/protocols/pppos_client/components/modem/src/esp_modem.c b/examples/protocols/pppos_client/components/modem/src/esp_modem.c index 99e10db2a..cf604b2b6 100644 --- a/examples/protocols/pppos_client/components/modem/src/esp_modem.c +++ b/examples/protocols/pppos_client/components/modem/src/esp_modem.c @@ -369,8 +369,14 @@ modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config) .data_bits = config->data_bits, .parity = config->parity, .stop_bits = config->stop_bits, + .source_clk = UART_SCLK_APB, .flow_ctrl = (config->flow_control == MODEM_FLOW_CONTROL_HW) ? UART_HW_FLOWCTRL_CTS_RTS : UART_HW_FLOWCTRL_DISABLE }; + /* Install UART driver and get event queue used inside driver */ + res = uart_driver_install(esp_dte->uart_port, CONFIG_EXAMPLE_UART_RX_BUFFER_SIZE, CONFIG_EXAMPLE_UART_TX_BUFFER_SIZE, + CONFIG_EXAMPLE_UART_EVENT_QUEUE_SIZE, &(esp_dte->event_queue), 0); + MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config); + MODEM_CHECK(uart_param_config(esp_dte->uart_port, &uart_config) == ESP_OK, "config uart parameter failed", err_uart_config); if (config->flow_control == MODEM_FLOW_CONTROL_HW) { res = uart_set_pin(esp_dte->uart_port, CONFIG_EXAMPLE_UART_MODEM_TX_PIN, CONFIG_EXAMPLE_UART_MODEM_RX_PIN, @@ -387,10 +393,6 @@ modem_dte_t *esp_modem_dte_init(const esp_modem_dte_config_t *config) res = uart_set_sw_flow_ctrl(esp_dte->uart_port, true, 8, UART_FIFO_LEN - 8); } MODEM_CHECK(res == ESP_OK, "config uart flow control failed", err_uart_config); - /* Install UART driver and get event queue used inside driver */ - res = uart_driver_install(esp_dte->uart_port, CONFIG_EXAMPLE_UART_RX_BUFFER_SIZE, CONFIG_EXAMPLE_UART_TX_BUFFER_SIZE, - CONFIG_EXAMPLE_UART_EVENT_QUEUE_SIZE, &(esp_dte->event_queue), 0); - MODEM_CHECK(res == ESP_OK, "install uart driver failed", err_uart_config); /* Set pattern interrupt, used to detect the end of a line. */ res = uart_enable_pattern_det_baud_intr(esp_dte->uart_port, '\n', 1, MIN_PATTERN_INTERVAL, MIN_POST_IDLE, MIN_PRE_IDLE); /* Set pattern queue size */ diff --git a/examples/system/console/components/cmd_system/cmd_system.c b/examples/system/console/components/cmd_system/cmd_system.c index e78e41bc1..0b4655b82 100644 --- a/examples/system/console/components/cmd_system/cmd_system.c +++ b/examples/system/console/components/cmd_system/cmd_system.c @@ -17,6 +17,7 @@ #include "esp_spi_flash.h" #include "driver/rtc_io.h" #include "driver/uart.h" +#include "hal/uart_ll.h" #include "argtable3/argtable3.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -287,11 +288,12 @@ static int light_sleep(int argc, char **argv) } if (CONFIG_ESP_CONSOLE_UART_NUM <= UART_NUM_1) { ESP_LOGI(TAG, "Enabling UART wakeup (press ENTER to exit light sleep)"); - ESP_ERROR_CHECK( uart_set_wakeup_threshold(CONFIG_ESP_CONSOLE_UART_NUM, 3) ); + uart_ll_set_wakeup_thrd(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM), 3); ESP_ERROR_CHECK( esp_sleep_enable_uart_wakeup(CONFIG_ESP_CONSOLE_UART_NUM) ); } fflush(stdout); - uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); + //Wait UART TX idle + while(!uart_ll_is_tx_idle(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM))); esp_light_sleep_start(); esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); const char *cause_str; diff --git a/examples/system/console/main/console_example_main.c b/examples/system/console/main/console_example_main.c index 0255da410..0caae2127 100644 --- a/examples/system/console/main/console_example_main.c +++ b/examples/system/console/main/console_example_main.c @@ -79,13 +79,12 @@ static void initialize_console(void) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .use_ref_tick = true + .source_clk = UART_SCLK_REF_TICK, }; - ESP_ERROR_CHECK( uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config) ); - /* Install UART driver for interrupt-driven reads and writes */ ESP_ERROR_CHECK( uart_driver_install(CONFIG_ESP_CONSOLE_UART_NUM, 256, 0, 0, NULL, 0) ); + ESP_ERROR_CHECK( uart_param_config(CONFIG_ESP_CONSOLE_UART_NUM, &uart_config) ); /* Tell VFS to use UART driver */ esp_vfs_dev_uart_use_driver(CONFIG_ESP_CONSOLE_UART_NUM); diff --git a/examples/system/light_sleep/main/light_sleep_example_main.c b/examples/system/light_sleep/main/light_sleep_example_main.c index 4b8dc1711..a55b2ed94 100644 --- a/examples/system/light_sleep/main/light_sleep_example_main.c +++ b/examples/system/light_sleep/main/light_sleep_example_main.c @@ -17,6 +17,7 @@ #include "esp_sleep.h" #include "esp_log.h" #include "driver/uart.h" +#include "hal/uart_ll.h" #include "driver/rtc_io.h" /* Most development boards have "boot" button attached to GPIO0. @@ -57,7 +58,7 @@ void app_main(void) /* To make sure the complete line is printed before entering sleep mode, * need to wait until UART TX FIFO is empty: */ - uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM); + while(!uart_ll_is_tx_idle(UART_LL_GET_HW(CONFIG_ESP_CONSOLE_UART_NUM))); /* Get timestamp before entering sleep */ int64_t t_before_us = esp_timer_get_time(); diff --git a/examples/system/select/main/select_example.c b/examples/system/select/main/select_example.c index 78d151627..ccfcf28a7 100644 --- a/examples/system/select/main/select_example.c +++ b/examples/system/select/main/select_example.c @@ -86,7 +86,6 @@ static void uart1_deinit(void) close(uart_fd); uart_fd = -1; uart_driver_delete(UART_NUM_1); - UART1.conf0.loopback = 0; } static void uart1_init(void) @@ -96,11 +95,12 @@ static void uart1_init(void) .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_DISABLE + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = UART_SCLK_APB, }; - uart_param_config(UART_NUM_1, &uart_config); uart_driver_install(UART_NUM_1, 256, 0, 0, NULL, 0); - UART1.conf0.loopback = 1; + uart_param_config(UART_NUM_1, &uart_config); + uart_set_loop_back(UART_NUM_1, true); if ((uart_fd = open("/dev/uart/1", O_RDWR | O_NONBLOCK)) == -1) { ESP_LOGE(TAG, "Cannot open UART1");