Long delay after UART transmit

JadElClemens
Posts: 10
Joined: Mon Oct 28, 2019 9:04 pm

Long delay after UART transmit

Postby JadElClemens » Mon Oct 28, 2019 9:31 pm

Hey all,

I'm writing code for an ESP32 to talk to two devices over the same UART line using an RS485 multiplexing setup. Because my setup is not standard, I have been hesitant to use the IDF's built-in RS485 mode and instead have opted to manually control the TX/RX select line in my communications architecture.

The basic communication flow is as follows:
  • Set Select line to Write (TX) level
  • Write message (

    Code: Select all

    uart_write_bytes
    )
  • Wait for TX to finish (

    Code: Select all

    uart_wait_tx_done
    )
  • Set Select line to Read (RX) level
  • Read message, decode, process
I've noticed that in some cases, the ESP32 delays for quite a while after all bytes are transmitted before toggling the Select line (the very next function call) - sometimes up to 10-20ms - and this sometimes happens whether or not I include the

Code: Select all

uart_wait_tx_done
call. I also tried raising the priority of my comms task above all others and the problem still remains. Any ideas?
Last edited by JadElClemens on Mon Oct 28, 2019 11:59 pm, edited 1 time in total.

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: Long delay after UART transmit

Postby ESP_Angus » Mon Oct 28, 2019 11:09 pm

Hi JadElClemens,

Thanks for the detailed description of what you're seeing. I have some additional questions to help figure out what's happening here:

Which ESP-IDF version do you have?

Do you have Wi-Fi or BT enabled at the same time? When you say you raised the priority "above all other tasks", how high did you raise it? Is the task that does the RS-485 operations pinned to a core (and if so, which core)?

If you make a minimal example that just does the RS-485 operation and nothing else, does it still exhibit the same behaviour? Is there any chance you could post the code for a minimal example like this, please?

EDIT: one more question, how are you measuring the delay?

JadElClemens
Posts: 10
Joined: Mon Oct 28, 2019 9:04 pm

Re: Long delay after UART transmit

Postby JadElClemens » Tue Oct 29, 2019 12:08 am

Thanks for the quick reply.


ESP_Angus wrote:
Mon Oct 28, 2019 11:09 pm
Which ESP-IDF version do you have?
I'm using v3.2
ESP_Angus wrote:
Mon Oct 28, 2019 11:09 pm
Do you have Wi-Fi or BT enabled at the same time?
WiFi is enabled, Bluetooth is not.
ESP_Angus wrote:
Mon Oct 28, 2019 11:09 pm
When you say you raised the priority "above all other tasks", how high did you raise it?
I suppose I mean that I raised it above the priority of my (user-defined/launched) tasks. I had it up to priority 10, which is higher than the rest of my own tasks.
ESP_Angus wrote:
Mon Oct 28, 2019 11:09 pm
Is the task that does the RS-485 operations pinned to a core (and if so, which core)?
Yes, it's pinned to core 1.
ESP_Angus wrote:
Mon Oct 28, 2019 11:09 pm
If you make a minimal example that just does the RS-485 operation and nothing else, does it still exhibit the same behaviour? Is there any chance you could post the code for a minimal example like this, please?
Sure, I can test this out and post an example tomorrow.
ESP_Angus wrote:
Mon Oct 28, 2019 11:09 pm
EDIT: one more question, how are you measuring the delay?
I'm measuring from the last edge of the UART transmission to the falling edge of the Select line (transition from write to read). Occasionally the delay is just a few ms, other times it's 10-20 as I mentioned.

ESP_Angus
Posts: 2344
Joined: Sun May 08, 2016 4:11 am

Re: Long delay after UART transmit

Postby ESP_Angus » Tue Oct 29, 2019 2:21 am

Hi JadElClemens,

Try setting this config item to pin the LWIP TCP/IP task to core 0:
https://docs.espressif.com/projects/esp ... k-affinity

By default, it's un-pinned so it can run on either CPU and its priority is 18 (for memory), so it would preempt the UART task on CPU1 if something was also running on CPU0.

JadElClemens
Posts: 10
Joined: Mon Oct 28, 2019 9:04 pm

Re: Long delay after UART transmit

Postby JadElClemens » Tue Oct 29, 2019 5:25 pm

ESP_Angus wrote:
Tue Oct 29, 2019 2:21 am
Hi JadElClemens,

Try setting this config item to pin the LWIP TCP/IP task to core 0:
https://docs.espressif.com/projects/esp ... k-affinity

By default, it's un-pinned so it can run on either CPU and its priority is 18 (for memory), so it would preempt the UART task on CPU1 if something was also running on CPU0.
My WiFi and LWIP tasks are already pinned to CPU0, actually. I can double check, but I haven't changed anything in the sdkconfig in a while. Just to be sure, I'll raise my comm task's priority to 19 (just temporarily as a test) to see if that solves the issue.

JadElClemens
Posts: 10
Joined: Mon Oct 28, 2019 9:04 pm

Re: Long delay after UART transmit

Postby JadElClemens » Tue Oct 29, 2019 10:27 pm

An update: Using the built-in RS485 half-duplex mode and just inverting the RTS line when talking to the secondary endpoint seems to have solved the problem for me.
ESP_Angus wrote:
Tue Oct 29, 2019 2:21 am
By default, it's un-pinned so it can run on either CPU and its priority is 18 (for memory), so it would preempt the UART task on CPU1 if something was also running on CPU0.
I just tested with my task priority (pinned to core 1) set at 19 (WiFi and LWIP tasks are still pinned to core 0), the problem does seem to have disappeared, but it's possible that I just haven't seen it yet.

Also, regarding this:
quote=ESP_Angus post_id=51055 time=1572304149 user_id=1923]
If you make a minimal example that just does the RS-485 operation and nothing else, does it still exhibit the same behaviour? Is there any chance you could post the code for a minimal example like this, please?
[/quote]

I don't have the liberty to test this at the moment, but here's the basic flow if somebody on the ESP team would like to try and reproduce.

Code: Select all

comQueueItem message; // comQueueItem is a custom struct
while(1) {
    if(uxQueueMessagesWaiting(comQueue) { // There is another function for external subsystems to enqueue a custom struct message
        if(xQueueReceive(comQueue, (void*) &message, portMAX_DELAY) != pdTRUE) {
            continue;
        }
        uint8_t responseData[message.responseLen]; // message.responseLen is the full expected length of the packet
        configureUART(message.endpoint); //invert or remove inversion on RTS line depending on endpoint
        uart_write_bytes(UART_NUM_2, (char*) message.data, message.requestLen); // message.data malloc'd uint8_t*, filled out before enqueueing message. message.requestLen is the full request packet length.
        uart_read_bytes(UART_NUM_2, responseData, message.responseLen, 1000/portTICK_PERIOD_MS); // message.responseLen is the expected response packet length
     
        // decode raw data into a message struct based on the endpoint (protocols differ between the two)
        // call the callback function with the endpoint-specific struct as a void*
    }
}

Who is online

Users browsing this forum: Timmwardion and 136 guests