Search code examples
linuxperformancesystem-callsuartbaud-rate

Linux UART slower than specified Baudrate


I'm trying to communicate between two Linux systems via UART. I want to send large chunks of data. With the specified Baudrate it should take around 5 seconds, but it takes nearly 10 times the expected time.

As I'm sending more than the buffer can handle at once it is send in small parts and I'm draining the buffer in between. If I measure the time needed for the drain and the number of bytes written to the buffer I calculate a Baudrate nearly 10 times lower than the specified Baudrate.

I would expect a slower transmission as the optimal, but not this much.

Did I miss something while setting the UART or while writing? Or is this normal?

The code used for setup:

int bus = open(interface.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); // <- also tryed blocking
if (bus < 0) {
    return;
}

struct termios options;
memset (&options, 0, sizeof options);
if(tcgetattr(bus, &options) != 0){
    close(bus);
    bus = -1;
    return;
}
cfsetspeed (&options, B230400);
cfmakeraw(&options); // <- also tried this manually. did not make a difference
if(tcsetattr(bus, TCSANOW, &options) != 0)
{
    close(bus);
    bus = -1;
    return;
}
tcflush(bus, TCIFLUSH);

The code used to send:

int32_t res = write(bus, data, dataLength);
while (res < dataLength){
    tcdrain(bus); // <- taking way longer than expected
    int32_t r = write(bus, &data[res], dataLength - res);
    if(r == 0)
        break;
    if(r == -1){
        break;
    }
    res += r;
}

Solution

  • B230400

    The docs are contradictory. cfsetspeed is documented as requiring a speed_t type, while the note says you need to use one of the "B" constants like "B230400." Have you tried using an actual speed_t type?

    In any case, the speed you're supplying is the baud rate, which in this case should get you approximately 23,000 bytes/second, assuming there is no throttling.

    The speed is dependent on hardware and link limitations. Also the serial protocol allows pausing the transmission.

    FWIW, according to the time and speed you listed, if everything works perfectly, you'll get about 1 MB in 50 seconds. What speed are you actually getting?

    Another "also" is the options structure. It's been years since I've had to do any serial I/O, but IIRC, you need to actually set the options that you want and are supported by your hardware, like CTS/RTS, XON/XOFF, etc.

    This might be helpful.