esp-idf: UART not firing RX timeout interrupt (IDFGH-6739)
Environment
Development Kit: none (custom PCB) Module or chip used: ESP32-S2-WROVER-I IDF version: v4.4-2.0.2 Build System: CMake Compiler version: toolchain-xtensa-esp32s2 8.4.0+2021r2 Operating System: Windows 10 Using an IDE: VScode + Platformio core 5.2.4 / board = esp32-s2-saola-1 Power Supply: external 3.3V
Problem Description
I use UART0 for Modbus communication - events do not get triggered after receiving a Modbus command (for example a read command with 8 bytes).
Expected behavior:
After receiving the Modbus command and no more bytes are sent, there should be RX timeout event triggered
Actual behavior:
No interrupt / events gets triggered after 8 bytes have been sent and no more bytes are sent after. An event is only triggered when the FIFO RX buffer has reached the “full threshold” (120 bytes).
Steps to reproduce:
The following code is a modified uart-echo_example, where I added uart_intr_config() and uart_enable_rx_intr() with .rxfifo_full_thresh = 20 and .rx_timeout_thresh = 2.
#include <stdio.h>
#include "sdkconfig.h"
#include "string.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_err.h"
#include "log.h"
#include "hal/uart_hal.h"
#define UART_NUM UART_NUM_0
#define ECHO_TEST_TXD (GPIO_NUM_43)
#define ECHO_TEST_RXD (GPIO_NUM_44)
#define ECHO_TEST_RTS (UART_PIN_NO_CHANGE)
#define ECHO_TEST_CTS (UART_PIN_NO_CHANGE)
#define BUF_SIZE (1024)
uart_config_t uart_config = {
.baud_rate = 19200,
.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,
};
void app_main(void)
{
vTaskDelay(5000 / portTICK_PERIOD_MS);
ESP_ERROR_CHECK(uart_driver_install(UART_NUM, BUF_SIZE * 2, 0, 0, NULL, 0));
ESP_ERROR_CHECK(uart_param_config(UART_NUM, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(UART_NUM, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));
uart_intr_config_t uart_intr = {
.intr_enable_mask = UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_FULL,
.rxfifo_full_thresh = 20,
.rx_timeout_thresh = 2,
};
ESP_ERROR_CHECK(uart_intr_config(UART_NUM, &uart_intr));
ESP_ERROR_CHECK(uart_enable_rx_intr(UART_NUM));
uint8_t *data = (uint8_t *) malloc(BUF_SIZE);
while (1) {
int length = 0;
ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_NUM, (size_t*)&length));
if (length) {
ESP_LOGI(TAG, "received %d bytes", length);
length = uart_read_bytes(UART_NUM, data, length, 20 / portTICK_RATE_MS);
}
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
I send a number of bytes to the UART using a PC and PuTTY, but the only output I get is when the RX buffer is full:
I (53420) UART test: received 20 bytes
I (61380) UART test: received 20 bytes
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 1
- Comments: 18
I did a bit more investigation by printing the content of the UART registers before and after configuration of the interrupt (increased .rx_timeout_thresh to 20):
I can see that UART_RXFIFO_FULL_THRHD is reduced form 120 to 20. That confirms the value UART_RX_TOUT_EN = 1 After setting .rx_timeout_thresh = 20, the value of UART_RX_TOUT_THRSHD = 200 (why a factor 10?)
The ESP32-S2 technical reference says:
So it seems that the required conditions I could find are met for the RX timeout function to be enabled. Anything else I missed? I have seen other threads with similar issue, but no explanation of why and how to fix it. Is that me doing something wrong or is it a bug? Please help, so I can move on!