diff --git a/components/driver/include/driver/uart.h b/components/driver/include/driver/uart.h index b0596a8cfb..f3f544a40b 100644 --- a/components/driver/include/driver/uart.h +++ b/components/driver/include/driver/uart.h @@ -70,6 +70,8 @@ typedef enum { typedef struct { uart_event_type_t type; /*!< UART event type */ size_t size; /*!< UART data size for UART_DATA event*/ + bool timeout_flag; /*!< UART data read timeout flag for UART_DATA event (no new data received during configured RX TOUT)*/ + /*!< If the event is caused by FIFO-full interrupt, then there will be no event with the timeout flag before the next byte coming.*/ } uart_event_t; typedef intr_handle_t uart_isr_handle_t; @@ -845,6 +847,20 @@ esp_err_t uart_wait_tx_idle_polling(uart_port_t uart_num); */ esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en); +/** + * @brief Configure behavior of UART RX timeout interrupt. + * + * When always_rx_timeout is true, timeout interrupt is triggered even if FIFO is full. + * This function can cause extra timeout interrupts triggered only to send the timeout event. + * Call this function only if you want to ensure timeout interrupt will always happen after a byte stream. + * + * @param uart_num UART number + * @param always_rx_timeout_en Set to false enable the default behavior of timeout interrupt, + * set it to true to always trigger timeout interrupt. + * + */ +void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout_en); + #ifdef __cplusplus } #endif diff --git a/components/driver/uart.c b/components/driver/uart.c index 7b1ce68cf7..43a4685f47 100644 --- a/components/driver/uart.c +++ b/components/driver/uart.c @@ -52,13 +52,13 @@ static const char* UART_TAG = "uart"; return (ret_val); \ } -#define UART_EMPTY_THRESH_DEFAULT (10) -#define UART_FULL_THRESH_DEFAULT (120) -#define UART_TOUT_THRESH_DEFAULT (10) -#define UART_CLKDIV_FRAG_BIT_WIDTH (3) -#define UART_TX_IDLE_NUM_DEFAULT (0) -#define UART_PATTERN_DET_QLEN_DEFAULT (10) -#define UART_MIN_WAKEUP_THRESH (SOC_UART_MIN_WAKEUP_THRESH) +#define UART_EMPTY_THRESH_DEFAULT (10) +#define UART_FULL_THRESH_DEFAULT (120) +#define UART_TOUT_THRESH_DEFAULT (10) +#define UART_CLKDIV_FRAG_BIT_WIDTH (3) +#define UART_TX_IDLE_NUM_DEFAULT (0) +#define UART_PATTERN_DET_QLEN_DEFAULT (10) +#define UART_MIN_WAKEUP_THRESH (SOC_UART_MIN_WAKEUP_THRESH) #define UART_INTR_CONFIG_FLAG ((UART_INTR_RXFIFO_FULL) \ | (UART_INTR_RXFIFO_TOUT) \ @@ -104,6 +104,7 @@ typedef struct { intr_handle_t intr_handle; /*!< UART interrupt handle*/ uart_mode_t uart_mode; /*!< UART controller actual mode set by uart_set_mode() */ bool coll_det_flg; /*!< UART collision detection flag */ + bool rx_always_timeout_flg; /*!< UART always detect rx timeout flag */ //rx parameters int rx_buffered_len; /*!< UART cached data length */ @@ -805,6 +806,10 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) pat_flg = 0; } if (p_uart->rx_buffer_full_flg == false) { + rx_fifo_len = uart_hal_get_rxfifo_len(&(uart_context[uart_num].hal)); + if ((p_uart_obj[uart_num]->rx_always_timeout_flg) && !(uart_intr_status & UART_INTR_RXFIFO_TOUT)) { + rx_fifo_len--; // leave one byte in the fifo in order to trigger uart_intr_rxfifo_tout + } 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; @@ -822,6 +827,7 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param) 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_event.timeout_flag = (uart_intr_status & UART_INTR_RXFIFO_TOUT) ? true : false; UART_ENTER_CRITICAL_ISR(&uart_selectlock); if (p_uart->uart_select_notif_callback) { p_uart->uart_select_notif_callback(uart_num, UART_SELECT_READ_NOTIF, &HPTaskAwoken); @@ -1294,6 +1300,7 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b p_uart_obj[uart_num]->uart_num = uart_num; p_uart_obj[uart_num]->uart_mode = UART_MODE_UART; p_uart_obj[uart_num]->coll_det_flg = false; + p_uart_obj[uart_num]->rx_always_timeout_flg = false; p_uart_obj[uart_num]->tx_fifo_sem = xSemaphoreCreateBinary(); xSemaphoreGive(p_uart_obj[uart_num]->tx_fifo_sem); p_uart_obj[uart_num]->tx_done_sem = xSemaphoreCreateBinary(); @@ -1490,8 +1497,12 @@ esp_err_t uart_set_tx_empty_threshold(uart_port_t uart_num, int threshold) 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); - + // get maximum timeout threshold + uint16_t tout_max_thresh = uart_hal_get_max_rx_timeout_thrd(&(uart_context[uart_num].hal)); + if (tout_thresh > tout_max_thresh) { + ESP_LOGE(UART_TAG, "tout_thresh = %d > maximum value = %d", tout_thresh, tout_max_thresh); + return ESP_ERR_INVALID_ARG; + } 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)); @@ -1543,3 +1554,13 @@ esp_err_t uart_set_loop_back(uart_port_t uart_num, bool loop_back_en) uart_hal_set_loop_back(&(uart_context[uart_num].hal), loop_back_en); return ESP_OK; } + +void uart_set_always_rx_timeout(uart_port_t uart_num, bool always_rx_timeout) +{ + uint16_t rx_tout = uart_hal_get_rx_tout_thr(&(uart_context[uart_num].hal)); + if (rx_tout) { + p_uart_obj[uart_num]->rx_always_timeout_flg = always_rx_timeout; + } else { + p_uart_obj[uart_num]->rx_always_timeout_flg = false; + } +} diff --git a/components/freemodbus/port/portserial.c b/components/freemodbus/port/portserial.c index dd716181c0..d2fcf9284d 100644 --- a/components/freemodbus/port/portserial.c +++ b/components/freemodbus/port/portserial.c @@ -103,7 +103,7 @@ void vMBPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable) } } -static void vMBPortSerialRxPoll(size_t xEventSize) +static USHORT usMBPortSerialRxPoll(size_t xEventSize) { BOOL xReadStatus = TRUE; USHORT usCnt = 0; @@ -114,17 +114,18 @@ static void vMBPortSerialRxPoll(size_t xEventSize) // Get received packet into Rx buffer for(usCnt = 0; xReadStatus && (usCnt < xEventSize); usCnt++ ) { // Call the Modbus stack callback function and let it fill the buffers. - xReadStatus = pxMBFrameCBByteReceived(); // callback to execute receive FSM state machine + xReadStatus = pxMBFrameCBByteReceived(); // callback to execute receive FSM } uart_flush_input(ucUartNumber); // Send event EV_FRAME_RECEIVED to allow stack process packet -#ifndef MB_TIMER_PORT_ENABLED +#if !CONFIG_FMB_TIMER_PORT_ENABLED // Let the stack know that T3.5 time is expired and data is received (void)pxMBPortCBTimerExpired(); // calls callback xMBRTUTimerT35Expired(); #endif ESP_LOGD(TAG, "RX: %d bytes\n", usCnt); } } + return usCnt; } BOOL xMBPortSerialTxPoll(void) @@ -136,7 +137,7 @@ BOOL xMBPortSerialTxPoll(void) // Continue while all response bytes put in buffer or out of buffer while((bNeedPoll) && (usCount++ < MB_SERIAL_BUF_SIZE)) { // Calls the modbus stack callback function to let it fill the UART transmit buffer. - bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // callback to transmit FSM state machine + bNeedPoll = pxMBFrameCBTransmitterEmpty( ); // callback to transmit FSM } ESP_LOGD(TAG, "MB_TX_buffer send: (%d) bytes\n", (uint16_t)usCount); // Waits while UART sending the packet @@ -151,15 +152,23 @@ BOOL xMBPortSerialTxPoll(void) static void vUartTask(void *pvParameters) { uart_event_t xEvent; + USHORT usResult = 0; for(;;) { if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) { ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); switch(xEvent.type) { //Event of UART receving data case UART_DATA: - ESP_LOGD(TAG,"Receive data, len: %d", xEvent.size); - // Read received data and send it to modbus stack - vMBPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Data event, length: %d", xEvent.size); + // This flag set in the event means that no more + // data received during configured timeout and UART TOUT feature is triggered + if (xEvent.timeout_flag) { + // Get buffered data length + ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size)); + // Read received data and send it to modbus stack + usResult = usMBPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Timeout occured, processed: %d bytes", usResult); + } break; //Event of HW FIFO overflow detected case UART_FIFO_OVF: @@ -251,12 +260,14 @@ BOOL xMBPortSerialInit(UCHAR ucPORT, ULONG ulBaudRate, MB_QUEUE_LENGTH, &xMbUartQueue, MB_PORT_SERIAL_ISR_FLAG); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "mb serial driver failure, uart_driver_install() returned (0x%x).", xErr); -#ifndef MB_TIMER_PORT_ENABLED +#if !CONFIG_FMB_TIMER_PORT_ENABLED // Set timeout for TOUT interrupt (T3.5 modbus time) xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr); #endif + // Set always timeout flag to trigger timeout interrupt even after rx fifo full + uart_set_always_rx_timeout(ucUartNumber, true); // Create a task to handle UART events BaseType_t xStatus = xTaskCreate(vUartTask, "uart_queue_task", MB_SERIAL_TASK_STACK_SIZE, NULL, MB_SERIAL_TASK_PRIO, &xMbTaskHandle); diff --git a/components/freemodbus/port/portserial_m.c b/components/freemodbus/port/portserial_m.c index e326a1ad9c..944e269953 100644 --- a/components/freemodbus/port/portserial_m.c +++ b/components/freemodbus/port/portserial_m.c @@ -96,7 +96,7 @@ void vMBMasterPortSerialEnable(BOOL bRxEnable, BOOL bTxEnable) } } -static void vMBMasterPortSerialRxPoll(size_t xEventSize) +static USHORT usMBMasterPortSerialRxPoll(size_t xEventSize) { BOOL xReadStatus = TRUE; USHORT usCnt = 0; @@ -109,8 +109,11 @@ static void vMBMasterPortSerialRxPoll(size_t xEventSize) uiRxBufferPos = 0; for(usCnt = 0; xReadStatus && (usCnt < usLength); usCnt++ ) { // Call the Modbus stack callback function and let it fill the stack buffers. - xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM state machine + xReadStatus = pxMBMasterFrameCBByteReceived(); // callback to receive FSM } +#if !CONFIG_FMB_TIMER_PORT_ENABLED + pxMBMasterPortCBTimerExpired(); +#endif // The buffer is transferred into Modbus stack and is not needed here any more uart_flush_input(ucUartNumber); ESP_LOGD(TAG, "Received data: %d(bytes in buffer)\n", (uint32_t)usCnt); @@ -118,6 +121,7 @@ static void vMBMasterPortSerialRxPoll(size_t xEventSize) } else { ESP_LOGE(TAG, "%s: bRxState disabled but junk data (%d bytes) received. ", __func__, xEventSize); } + return usCnt; } BOOL xMBMasterPortSerialTxPoll(void) @@ -145,15 +149,25 @@ BOOL xMBMasterPortSerialTxPoll(void) static void vUartTask(void* pvParameters) { uart_event_t xEvent; + USHORT usResult = 0; for(;;) { if (xQueueReceive(xMbUartQueue, (void*)&xEvent, portMAX_DELAY) == pdTRUE) { ESP_LOGD(TAG, "MB_uart[%d] event:", ucUartNumber); switch(xEvent.type) { //Event of UART receiving data case UART_DATA: - ESP_LOGD(TAG,"Receive data, len: %d.", xEvent.size); - // Read received data and send it to modbus stack - vMBMasterPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Data event, len: %d.", xEvent.size); + // This flag set in the event means that no more + // data received during configured timeout and UART TOUT feature is triggered + if (xEvent.timeout_flag) { + // Get buffered data length + ESP_ERROR_CHECK(uart_get_buffered_data_len(ucUartNumber, &xEvent.size)); + // Read received data and send it to modbus stack + usResult = usMBMasterPortSerialRxPoll(xEvent.size); + ESP_LOGD(TAG,"Timeout occurred, processed: %d bytes", usResult); + // Block receiver task until data is not processed + vTaskSuspend(NULL); + } break; //Event of HW FIFO overflow detected case UART_FIFO_OVF: @@ -249,6 +263,8 @@ BOOL xMBMasterPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, xErr = uart_set_rx_timeout(ucUartNumber, MB_SERIAL_TOUT); MB_PORT_CHECK((xErr == ESP_OK), FALSE, "mb serial set rx timeout failure, uart_set_rx_timeout() returned (0x%x).", xErr); + // Set always timeout flag to trigger timeout interrupt even after rx fifo full + uart_set_always_rx_timeout(ucUartNumber, true); // Create a task to handle UART events BaseType_t xStatus = xTaskCreate(vUartTask, "uart_queue_task", MB_SERIAL_TASK_STACK_SIZE, NULL, MB_SERIAL_TASK_PRIO, &xMbTaskHandle); diff --git a/components/soc/esp32/include/hal/uart_ll.h b/components/soc/esp32/include/hal/uart_ll.h index 33002ca47a..25727978f4 100644 --- a/components/soc/esp32/include/hal/uart_ll.h +++ b/components/soc/esp32/include/hal/uart_ll.h @@ -395,31 +395,6 @@ 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. * @@ -822,4 +797,66 @@ static inline void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask) hw->conf0.val = conf0_reg.val; } +/** + * @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 as a bit time. 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, uint16_t tout_thr) +{ + 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; + } else { + //If APB_CLK is used: counting rate is BAUD tick rate / 8 + tout_thr = (tout_thr + 7) / 8; + } + 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 Get the timeout value for receiver receiving a byte. + * + * @param hw Beginning address of the peripheral registers. + * + * @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0. + */ +static inline uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw) +{ + uint16_t tout_thrd = 0; + if (hw->conf1.rx_tout_en > 0) { + if (hw->conf0.tick_ref_always_on == 0) { + tout_thrd = (uint16_t)(hw->conf1.rx_tout_thrhd / UART_LL_TOUT_REF_FACTOR_DEFAULT); + } else { + tout_thrd = (uint16_t)(hw->conf1.rx_tout_thrhd << 3); + } + } + return tout_thrd; +} + +/** + * @brief Get UART maximum timeout threshold. + * + * @param hw Beginning address of the peripheral registers. + * + * @return maximum timeout threshold. + */ +static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw) +{ + uint16_t tout_thrd = 0; + if (hw->conf0.tick_ref_always_on == 0) { + tout_thrd = (uint16_t)(UART_RX_TOUT_THRHD_V / UART_LL_TOUT_REF_FACTOR_DEFAULT); + } else { + tout_thrd = (uint16_t)(UART_RX_TOUT_THRHD_V << 3); + } + return tout_thrd; +} #undef UART_LL_TOUT_REF_FACTOR_DEFAULT diff --git a/components/soc/esp32s2beta/include/hal/uart_ll.h b/components/soc/esp32s2beta/include/hal/uart_ll.h index 7a2a045d35..bafd8f9c3d 100644 --- a/components/soc/esp32s2beta/include/hal/uart_ll.h +++ b/components/soc/esp32s2beta/include/hal/uart_ll.h @@ -349,24 +349,6 @@ 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. * @@ -767,3 +749,50 @@ static inline void uart_ll_inverse_signal(uart_dev_t *hw, uint32_t inv_mask) conf0_reg.dtr_inv |= (inv_mask & UART_SIGNAL_DTR_INV) ? 1 : 0; hw->conf0.val = conf0_reg.val; } + +/** + * @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_thrd The timeout value as UART bit time. The rx timeout function will be disabled if `tout_thrd == 0`. + * + * @return None. + */ +static inline void uart_ll_set_rx_tout(uart_dev_t *hw, uint16_t tout_thrd) +{ + uint16_t tout_val = tout_thrd; + if(tout_thrd > 0) { + hw->mem_conf.rx_tout_thrhd = tout_val; + hw->conf1.rx_tout_en = 1; + } else { + hw->conf1.rx_tout_en = 0; + } +} + +/** + * @brief Get the timeout value for receiver receiving a byte. + * + * @param hw Beginning address of the peripheral registers. + * + * @return tout_thr The timeout threshold value. If timeout feature is disabled returns 0. + */ +static inline uint16_t uart_ll_get_rx_tout_thr(uart_dev_t *hw) +{ + uint16_t tout_thrd = 0; + if(hw->conf1.rx_tout_en > 0) { + tout_thrd = hw->mem_conf.rx_tout_thrhd; + } + return tout_thrd; +} + +/** + * @brief Get UART maximum timeout threshold. + * + * @param hw Beginning address of the peripheral registers. + * + * @return maximum timeout threshold. + */ +static inline uint16_t uart_ll_max_tout_thrd(uart_dev_t *hw) +{ + return UART_RX_TOUT_THRHD_V; +} diff --git a/components/soc/include/hal/uart_hal.h b/components/soc/include/hal/uart_hal.h index 1547d61bf8..3e277a0e02 100644 --- a/components/soc/include/hal/uart_hal.h +++ b/components/soc/include/hal/uart_hal.h @@ -127,13 +127,14 @@ typedef struct { /** * @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 + * @param[in] hal Context of the HAL layer + * @param[in] buf Pointer to the buffer used to store the read data. The buffer size should be large than 128 bytes + * @param[inout] inout_rd_len As input, the size of output buffer to read (set to 0 to read all available data). + * As output, returns the actual size written into the output buffer. * * @return None */ -void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *rd_len); +void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *inout_rd_len); /** * @brief Write data into the UART txfifo @@ -430,6 +431,42 @@ void uart_hal_get_sclk(uart_hal_context_t *hal, uart_sclk_t *sclk); */ void uart_hal_set_loop_back(uart_hal_context_t *hal, bool loop_back_en); +/** + * @brief Calculate uart symbol bit length, as defined in configuration. + * + * @param hw Beginning address of the peripheral registers. + * + * @return number of bits per UART symbol. + */ +uint8_t uart_hal_get_symb_len(uart_hal_context_t *hal); + +/** + * @brief Get UART maximum timeout threshold. + * + * @param hw Beginning address of the peripheral registers. + * + * @return maximum timeout threshold value for target. + */ +uint16_t uart_hal_get_max_rx_timeout_thrd(uart_hal_context_t *hal); + +/** + * @brief Get the timeout threshold value set for receiver. + * + * @param hw Beginning address of the peripheral registers. + * + * @return tout_thr The timeout value. If timeout is disabled then returns 0. + */ +#define uart_hal_get_rx_tout_thr(hal) uart_ll_get_rx_tout_thr((hal)->dev) + +/** + * @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. + */ +#define uart_hal_get_rxfifo_len(hal) uart_ll_get_rxfifo_len((hal)->dev) + #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/components/soc/src/hal/uart_hal.c b/components/soc/src/hal/uart_hal.c index 51db4a048c..1f68b5c2be 100644 --- a/components/soc/src/hal/uart_hal.c +++ b/components/soc/src/hal/uart_hal.c @@ -76,11 +76,6 @@ 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); @@ -153,4 +148,33 @@ void uart_hal_init(uart_hal_context_t *hal, int uart_num) 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 +} + +uint8_t uart_hal_get_symb_len(uart_hal_context_t *hal) +{ + uint8_t symbol_len = 1; // number of bits per symbol including start + uart_parity_t parity_mode; + uart_stop_bits_t stop_bit; + uart_word_length_t data_bit; + uart_ll_get_data_bit_num(hal->dev, &data_bit); + uart_ll_get_stop_bits(hal->dev, &stop_bit); + uart_ll_get_parity(hal->dev, &parity_mode); + symbol_len += (data_bit < UART_DATA_BITS_MAX) ? (uint8_t)data_bit + 5 : 8; + symbol_len += (stop_bit > UART_STOP_BITS_1) ? 2 : 1; + symbol_len += (parity_mode > UART_PARITY_DISABLE) ? 1 : 0; + return symbol_len; +} + +void uart_hal_set_rx_timeout(uart_hal_context_t *hal, const uint8_t tout) +{ + uint8_t symb_len = uart_hal_get_symb_len(hal); + uart_ll_set_rx_tout(hal->dev, symb_len * tout); +} + +uint16_t uart_hal_get_max_rx_timeout_thrd(uart_hal_context_t *hal) +{ + uint8_t symb_len = uart_hal_get_symb_len(hal); + uint16_t max_tout_thresh = uart_ll_max_tout_thrd(hal->dev); + return (max_tout_thresh / symb_len); +} + diff --git a/components/soc/src/hal/uart_hal_iram.c b/components/soc/src/hal/uart_hal_iram.c index f13ce4b089..13f0e56412 100644 --- a/components/soc/src/hal/uart_hal_iram.c +++ b/components/soc/src/hal/uart_hal_iram.c @@ -40,9 +40,11 @@ void uart_hal_write_txfifo(uart_hal_context_t *hal, const uint8_t *buf, uint32_t 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) +void uart_hal_read_rxfifo(uart_hal_context_t *hal, uint8_t *buf, int *inout_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); + if (*inout_rd_len <= 0) { + *inout_rd_len = uart_ll_get_rxfifo_len(hal->dev); + } + uart_ll_read_rxfifo(hal->dev, buf, *inout_rd_len); } +