How to read data from UART

juantxorena
Posts: 2
Joined: Sun Jan 14, 2024 4:44 pm

How to read data from UART

Postby juantxorena » Sun Jan 14, 2024 5:00 pm

Hello everybody,

I'm having a lot of trouble with reading data from a sensor which connects with UART. I've read the documentation and examples, and it works sometimes, but it crashes a lot and sometimes it doesn't gives any data (more often than not).

I'm using a esp32-c6-devkitm-1, and the sensor is this sonar.

I paste a fragment of my code, I hope is enough for receiving help. Please note that I'm testing a lot so the code is absolutely not clean, with superfluous loggers, etc:

Code: Select all

static uint16_t calculate_distance(uint8_t high, uint8_t low) {
    return ((uint16_t)high << 8) | low;
}

static void init_only_uart() {
    ESP_LOGE(TAG, "INIT ONLY UART");
    // Initialize UART configuration
    uart_config_t uart_config = {
        .baud_rate = 9600,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE
    };

    // Set up UART pins
    uart_param_config(UART_NUM, &uart_config);
    uart_set_pin(UART_NUM, UART_PIN_NO_CHANGE, WATER_DISTANCE_RX_GPIO, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    uart_driver_install(UART_NUM, BUF_SIZE * 2, 0, 0, NULL, 0);
}

static void stop_uart() {
    ESP_LOGE(TAG, "STOP UART");
    uart_driver_delete(UART_NUM);
}

void init_uart() {
    //init_only_uart();


    ESP_LOGE(TAG, "GPIO POWER");
    gpio_config_t power_conf;
    power_conf.mode = GPIO_MODE_OUTPUT;
    power_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
    power_conf.pull_up_en = GPIO_PULLUP_DISABLE;
    power_conf.pin_bit_mask = (1ULL << WATER_DISTANCE_POWER_GPIO);

    gpio_config(&power_conf);
    gpio_set_level(WATER_DISTANCE_POWER_GPIO, 1); // Start with the power off
}

void readSensorValues(void *pvParameters) {
    uint8_t data[4];
    uint16_t distances[SENSOR_READING_VALID_VALUES];
    int num_valid_samples = 0;
    int read_attempts = 0;
    //uart_init();
    const int max_read_attempts = 50;

    while (1) {
        // Turn on the sensor
        ESP_LOGW(TAG, "GPIO POWER ON");
        gpio_set_level(WATER_DISTANCE_POWER_GPIO, 1); // Turn on the sensor initially
        init_only_uart();
        vTaskDelay(pdMS_TO_TICKS(500));
        // Read NUM_SAMPLES valid frames
        num_valid_samples = 0;
        read_attempts = 0;
        uart_flush(UART_NUM);
        while (num_valid_samples < SENSOR_READING_VALID_VALUES) {
            // Read UART data
            ESP_LOGI(TAG, "Reading UART data");
            int len = uart_read_bytes(UART_NUM, data, sizeof(data), 100 / portTICK_PERIOD_MS);
            if (len == 4 && data[0] == 0xFF) {
                ESP_LOGW(TAG, "Correct data");
                uint8_t checksum = (data[0] + data[1] + data[2]) & 0x00FF;
                if (data[3] == checksum) {
                    read_attempts = -1;
                    ESP_LOGW(TAG, "Correct checksum");
                    distances[num_valid_samples++] = calculate_distance(data[1], data[2]);
                }
            }
            read_attempts++;
            if (read_attempts >= max_read_attempts) {
                ESP_LOGW(TAG, "Max read attempts reached without valid data.");
                // You may want to handle the error here, like re-initializing the UART or sensor
                break; // Exit while loop if max attempts reached
            }
        }
        ESP_LOGI(TAG, "Number of valid samples: %d", num_valid_samples);
        // Calculate average distance, excluding outliers
        if (num_valid_samples > 0) {
            uint32_t sum = 0;
            for (int i = 0; i < SENSOR_READING_VALID_VALUES; i++) {
                sum += distances[i];
            }
            uint16_t average_distance = sum / num_valid_samples;

            printf("Average Distance: %d\n", average_distance);
        } else {
            ESP_LOGE(TAG, "No valid data received.");
        }
        // Turn off the sensor
        //gpio_set_level(WATER_DISTANCE_POWER_GPIO, 0);
        stop_uart();

        // Wait for N seconds
        vTaskDelay(pdMS_TO_TICKS(10 * 1000));

    }

    free(data);
    vTaskDelete(NULL);
}
In main I call

Code: Select all

init_uart();
xTaskCreate(&readSensorValues, "readSensorValues", 3072, NULL, 1, NULL);
The part about stopping and reinstalling the UART every time was an attempt to solve my crash problems. The WATER_DISTANCE_POWER_GPIO it's for a future turning on and off the sensor to save power, but I'm having problems with it too. For now it doesn't do anything, I have the sensor connected to a 3.3V source.

What I want to do is to read the distance provided by the sensor every 10 seconds. For the distance, I take a number of reads (2 in this case) and do an average. If I don't get a valid value in a number of attempts (50 in this case), I ignore it and throw an error.

The program connects to wifi (working without problems), and it's configured to go into automatic light sleep whenever it cans. This is important, it might be related to the error, and it's important to have it working since it will be powered by solar panel and battery.

When I start the device, it works perfectly, I always get a valid reading immediately. After that, or maybe the 2nd correct value, the sensor (or UART reading) starts failing, i.e. I get a lot of "Reading UART data" logs (which, as you can see in my code, it means that it tries to read but it doesn't receive anything). Maybe it works once after 40 attempts at reading, and I get a value that normally is correct, but not always. Eventually, always while trying to read, it crashes with the following stack trace:

Code: Select all

Guru Meditation Error: Core  0 panic'ed (Interrupt wdt timeout on CPU0). 

Core  0 register dump:
MEPC    : 0x40801936  RA      : 0x4080189c  SP      : 0x40823d80  GP      : 0x408186e4  
0x40801936: uart_ll_update at /home/juantxorena/Projects/esp/esp-idf/components/hal/esp32c6/include/hal/uart_ll.h:92
 (inlined by) uart_ll_force_xon at /home/juantxorena/Projects/esp/esp-idf/components/hal/esp32c6/include/hal/uart_ll.h:1061
 (inlined by) resume_uarts at /home/juantxorena/Projects/esp/esp-idf/components/esp_hw_support/sleep_modes.c:453
 (inlined by) esp_sleep_start at /home/juantxorena/Projects/esp/esp-idf/components/esp_hw_support/sleep_modes.c:805

0x4080189c: resume_uarts at /home/juantxorena/Projects/esp/esp-idf/components/esp_hw_support/sleep_modes.c:452
 (inlined by) esp_sleep_start at /home/juantxorena/Projects/esp/esp-idf/components/esp_hw_support/sleep_modes.c:805

TP      : 0x407fd87c  T0      : 0x40027bd4  T1      : 0x400000ec  T2      : 0x00000000  
0x40027bd4: Cache_Resume_ICache in ROM

0x400000ec: __call_tdefl_init in ROM

S0/FP   : 0x40818020  S1      : 0x00000000  A0      : 0x00000000  A1      : 0xfff5ffff  
A2      : 0x00001311  A3      : 0x60001000  A4      : 0x00000003  A5      : 0x00000001  
A6      : 0x40824db0  A7      : 0x40824d78  S2      : 0x00000001  S3      : 0x00000000  
S4      : 0x00017f8d  S5      : 0x00000000  S6      : 0x40820000  S7      : 0x00000030  
S8      : 0x40820000  S9      : 0x00000000  S10     : 0x00000000  S11     : 0x00000000  
T3      : 0x00400000  T4      : 0x00000080  T5      : 0x00000000  T6      : 0x00000000  
MSTATUS : 0x00001881  MTVEC   : 0x40800001  MCAUSE  : 0x00000018  MTVAL   : 0x00008b85  
0x40800001: _vector_table at ??:?

MHARTID : 0x00000000  

Stack memory:
40823d80: 0x00000001 0x00000000 0x00000000 0x40823db8 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
40823da0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0x00000000 0x00000028
40823dc0: 0x00000004 0x0000000a 0x20000000 0x0c000000 0x00000000 0x00000000 0x70000000 0x00000000
40823de0: 0xc0000000 0x00000000 0x00000000 0x08000000 0xc0000000 0x08040000 0x00000000 0x00000000
40823e00: 0x00000000 0x00000000 0xc0000000 0x60400000 0x00000000 0x00004457 0x00000986 0x001f001f
40823e20: 0x0000000f 0x00000045 0x1745001f 0x0f761f00 0x407fd87c 0x40027bd4 0x00000028 0x00000000
0x40027bd4: Cache_Resume_ICache in ROM

40823e40: 0x00000000 0x00000000 0x40820000 0x00017f8d 0x00000000 0x00007c10 0x00000000 0x00000000
40823e60: 0x14d4f465 0x00000000 0x00000000 0x40801e6a 0x14d4f465 0x00000000 0x40818020 0x40808126
0x40801e6a: esp_light_sleep_inner at /home/juantxorena/Projects/esp/esp-idf/components/esp_hw_support/sleep_modes.c:931

0x40808126: esp_light_sleep_start at /home/juantxorena/Projects/esp/esp-idf/components/esp_hw_support/sleep_modes.c:1128

40823e80: 0xfa000000 0xf8400000 0x00000000 0x600b1c00 0x40820338 0x00000103 0x00000000 0x00000000
40823ea0: 0x00000000 0x00000002 0x00000001 0x4081b3d4 0x00000000 0x00000000 0x14d4f448 0x4080353e
0x4080353e: vApplicationSleep at /home/juantxorena/Projects/esp/esp-idf/components/esp_pm/pm_impl.c:646

40823ec0: 0x40820000 0x40820000 0x00000002 0x4080ba58 0x00000000 0x00000000 0x00000000 0x00000000
0x4080ba58: prvIdleTask at /home/juantxorena/Projects/esp/esp-idf/components/freertos/FreeRTOS-Kernel/tasks.c:4364

40823ee0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
40823f00: 0x00000000 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
40823f20: 0x0000015c 0x40823e40 0x408205e4 0x4081b42c 0x4081b42c 0x40823f24 0x4081b424 0x00000019
40823f40: 0x9faafeba 0x75e355bd 0x40823f24 0x00000000 0x00000000 0x40823920 0x454c4449 0x98eb9a00
40823f60: 0x0a48efdb 0x0053b5d2 0x00000000 0x40823f10 0x00000003 0x00000000 0x00000000 0x00000000
40823f80: 0x00000000 0x00000000 0x00000000 0x40820fa8 0x40821010 0x40821078 0x00000000 0x00000000
40823fa0: 0x00000001 0x00000000 0x00000000 0x00000000 0x4209edf0 0x00000000 0x00000000 0x00000000
0x4209edf0: _cleanup_r at /builds/idf/crosstool-NG/.build/riscv32-esp-elf/src/newlib/newlib/libc/stdio/findfp.c:229

40823fc0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
40823fe0: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
40824000: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
40824020: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
40824040: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000
40824060: 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x40000200
0x40000200: __call_esp_enable_cache_flash_wrap in ROM

40824080: 0x00000800 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
408240a0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
408240c0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
408240e0: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
40824100: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
40824120: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
40824140: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5
40824160: 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5 0xa5a5a5a5



ELF file SHA256: 965ca583ca20af95
If the UART driver has been uninstalled, it ever crashes, it's always while trying to read or something like that.

I am completely at lost. I've been with this problem on and off for months, and nothing seem to work. Any help will be greatly appreciated.

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

Re: How to read data from UART

Postby MicroController » Mon Jan 15, 2024 4:37 pm

1. free(data); - you can't do that.
2. Are you getting any errors returned when (re-)initializing the UART?
3. You're not synchronizing your reads to the data 'packets' the sensor sends, i.e. the first byte you read may actually be the 1st, 2nd, 3rd, or 4th byte of a 'packet', with a 75% chance of being the wrong one.

juantxorena
Posts: 2
Joined: Sun Jan 14, 2024 4:44 pm

Re: How to read data from UART

Postby juantxorena » Mon Jan 15, 2024 5:45 pm

MicroController wrote:
Mon Jan 15, 2024 4:37 pm
1. free(data); - you can't do that.
I will remove it then and test asap (probably weekend).
MicroController wrote:
Mon Jan 15, 2024 4:37 pm
2. Are you getting any errors returned when (re-)initializing the UART?
Nope, all the errors are while it's activated and tries to do something.
MicroController wrote:
Mon Jan 15, 2024 4:37 pm
3. You're not synchronizing your reads to the data 'packets' the sensor sends, i.e. the first byte you read may actually be the 1st, 2nd, 3rd, or 4th byte of a 'packet', with a 75% chance of being the wrong one.
How can I fix this? I'm a programmer, but high level. All of this microcontroller and low level stuff is completely new to me.

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

Re: How to read data from UART

Postby MicroController » Tue Jan 16, 2024 9:52 am

Given that the sensor apparently sends at most one frame every 100ms, I suggest reducing the timeout in

Code: Select all

int len = uart_read_bytes(UART_NUM, data, sizeof(data), 100 / portTICK_PERIOD_MS);
to 10-50ms.
This should help make sure that, if less than 4 bytes are received in that timeframe, the next byte after that is actually the first byte of a new frame.
Plus, make sure that at some point you flush the RX FIFO in case it has accumulated more than 4 bytes in between your reads.

Who is online

Users browsing this forum: No registered users and 124 guests