Why doesn't uart_read_bytes() return immediately when data is available?

william.ferguson.au
Posts: 107
Joined: Wed Jan 02, 2019 8:55 am

Why doesn't uart_read_bytes() return immediately when data is available?

Postby william.ferguson.au » Fri Aug 04, 2023 2:19 am

The docs for uart_read_bytes() imply that if data is available it will return immediately, otherwise it will wait for ticks_to_wait. But this is not the behaviour I am seeing on ESPIDF v4.4.

Instead it always waits for (at least) ticks_to_wait before returning. And if more data is added to the buffer before ticks_to_wait expires, it resets the ticks_to_wait and start counting from zero again.
Is this expected behaviour?

If I set ticks_to_wait to portMAX_DELAY, it doesn't return until the RX buffer is full.
Is that expected behaviour?

Code: Select all

#include <esp_log.h>
#include <esp_err.h>
#include <driver/gpio.h>
#include <driver/uart.h>
#include <hal/uart_types.h>


#define TAG "main"

#define UART        UART_NUM_2
#define TXD_PIN     (GPIO_NUM_17)
#define RXD_PIN     (GPIO_NUM_16)

#define RX_BUF_SIZE 256

static void rx_task(__attribute__((unused)) void *arg) {

    uint8_t* rx_buffer = (uint8_t*) malloc(RX_BUF_SIZE);

    const uint32_t rx_timeout_ms = 15000;

    ESP_LOGI(TAG, "Starting RX task - portTICK_PERIOD_MS :  %d\n", portTICK_PERIOD_MS); // NB Need CONFIG_FREERTOS_HZ=1000 (portTick_PERIOD_MS=1) to ensure that we wakeup with ms precision.

    while (true) {
        ESP_LOGD(TAG, "Waiting for RX message timeout_ms=%d", rx_timeout_ms);

        const int32_t rx_bytes = uart_read_bytes(UART, rx_buffer, RX_BUF_SIZE, rx_timeout_ms / portTICK_PERIOD_MS);
        const int64_t message_received_us = esp_timer_get_time();

        ESP_LOGD(TAG, "Read %d bytes at %lldus - bytes:", rx_bytes, message_received_us);
        ESP_LOG_BUFFER_HEXDUMP(TAG, rx_buffer, rx_bytes, ESP_LOG_INFO);
    }
    free(rx_buffer);
    vTaskDelete(NULL);
}


void app_main(void) {
    ESP_LOGI(TAG, "Start up");
    ESP_ERROR_CHECK(gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1));

    const uart_config_t uart_config = {
            .baud_rate = 1000000,
            .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,
    };

    ESP_ERROR_CHECK(uart_driver_install(UART, RX_BUF_SIZE * 2, 0, 0, NULL, 0));
    ESP_ERROR_CHECK(uart_param_config(UART, &uart_config));
    ESP_ERROR_CHECK(uart_set_pin(UART, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));

    xTaskCreate(rx_task, "uart_rx_task", 4096, NULL, configMAX_PRIORITIES-1, NULL);
}


william.ferguson.au
Posts: 107
Joined: Wed Jan 02, 2019 8:55 am

Re: Why doesn't uart_read_bytes() return immediately when data is available?

Postby william.ferguson.au » Fri Aug 04, 2023 2:39 am

Am I correct in thinking that the length param specifies the number of bytes that MUST be read before the function returns (if it doesn't time out)?

I had been reading it as the length of the buffer that could be filled.

MicroController
Posts: 1219
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Why doesn't uart_read_bytes() return immediately when data is available?

Postby MicroController » Fri Aug 04, 2023 9:53 pm

william.ferguson.au wrote:
Fri Aug 04, 2023 2:39 am
Am I correct in thinking that the length param specifies the number of bytes that MUST be read before the function returns (if it doesn't time out)?
Correct.
It's maybe not very intuitive, but the intention seems to be for UART reading to be done in response to a UART event (c.f. https://github.com/espressif/esp-idf/bl ... main.c#L56), in which case the event tells you when and how much data is available.

william.ferguson.au
Posts: 107
Joined: Wed Jan 02, 2019 8:55 am

Re: Why doesn't uart_read_bytes() return immediately when data is available?

Postby william.ferguson.au » Sat Aug 05, 2023 2:55 am

Thanks for the confirm.

I had already switched to using the Events and that is working fine. But the API and doco makes it's use non obvious. I would have saved a lot of time. with just a bit of clarity in the doco.

Who is online

Users browsing this forum: MicroController and 202 guests