Understanding UART receive buffering

wolfbert
Posts: 2
Joined: Mon Nov 14, 2022 8:10 pm

Understanding UART receive buffering

Postby wolfbert » Mon Nov 14, 2022 8:45 pm

Hi,

I'm receiving a 262 282 byte data packet (sent in one piece) on an ESP32 (2400 baud, 8N1) like so:

Code: Select all

void setup()
{
    Serial.begin(115200);

    Serial2.setRxBufferSize(512);
    Serial2.begin(2400);
}

void loop()
{
    uint8_t buffer[512];
    size_t bytesRead;

    while(!Serial2.available());
    bytesRead = Serial2.read(buffer, sizeof(buffer));

    Serial.printf("\nBytes received: %u\n", bytesRead);
}
Data is received in chunks of 120, 120 and 42 bytes.

I understand that the ESP32 has a hardware receive buffer and that an interrupt is triggered when 120 bytes have been received (or after a timeout). What I don't understand is the purpose of the internal RxRingBuffer which is initialized to 256 bytes (or 512 above). Is there a way to actually use this buffer?
Last edited by wolfbert on Tue Nov 15, 2022 4:06 am, edited 1 time in total.

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: Understanding UART receive buffering

Postby ESP_Sprite » Tue Nov 15, 2022 2:28 am

The logic is that buffering needs to happen when you receive data at a fast speed (way faster than 2400 baud) and your user code is doing other things at a particular point in time (e.g. servicing WiFi); the ringbuffer acts as an extra buffer to temporarily hold the data until your CPU can process it. Both the FIFO and the CPU are not intended to 'depacketize' your incoming bytes: if you need to detect packet boundaries, you'd need to do that in user code as the driver sees the incoming UART data as simply a stream of bytes.

wolfbert
Posts: 2
Joined: Mon Nov 14, 2022 8:10 pm

Re: Understanding UART receive buffering

Postby wolfbert » Tue Nov 15, 2022 9:52 am

Thank you for your explanation. It made me rethink my assumptions (I was used to AVR controllers), and I believe I've figured it out.

The ring buffer is of course used. But, while a transmission is ongoing, and with default settings, the first non-zero result of available() will be 120 - the first time the HW buffer is copied over. Same as on AVR actually, just that the HW buffer there is just a single byte, so data becomes immediately available in the ring buffer.

What fooled me was that I believed read() was blocking (so why stop at 120?), when in fact it was not.

By the way, to assemble the whole message (at least in my example) in Arduino, one could use Stream::readBytes(). It has its own timeout and calls HardwareSerial::read() repeatedly until the message is in (assuming one knows what to expect).

Case closed, thanks for your support.

Who is online

Users browsing this forum: No registered users and 75 guests