1

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;
}
l4z6_z
  • 141
  • 1
  • 6

2 Answers2

0

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.

Terry Carmen
  • 3,720
  • 1
  • 16
  • 32
  • 2
    Ah thank you. Its embarrassing. I thought Baud refers to byte plus start, stop, etc. Should have known better.... Then everything is working just as it should but not like i want it to... The command cfmakeraw() sets every options like CTS and so on like i want them to be. – l4z6_z Aug 03 '18 at 15:37
0

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.

You have only provided code snippets (rather than a minimal, complete, and verifiable example), so your data size is unknown.
But the Linux kernel buffer size is known. What do you think it is?
(FYI it's 4KB.)

If I measure the time needed for the drain and the number of bytese written to the buffer I calculate a Baudrate nearly 10 times lower than the specified Baudrate.

You're confusing throughput with baudrate.

The maximum throughput (of just payload) of an asynchronous serial link will always be less than the baudrate due to framing overhead per character, which could be two of the ten bits of the frame (assuming 8N1). Since your termios configuration is incomplete, the overhead could actually be three of the eleven bits of the frame (assuming 8N2).

In order to achieve the maximum throughput, the tranmitting UART must saturate the line with frames and never let the line go idle.
The userspace program must be able to supply data fast enough, preferably by one large write() to reduce syscall overhead.

Did I miss something while setting the UART or while writing?

With Linux, you have limited access to the UART hardware.
From userspace your program accesses a serial terminal.
Your program accesses the serial terminal in a sub-optinal manner.

Your termios configuration appears to be incomplete.
It leaves both hardware and software flow-control untouched.
The number of stop bits is untouched.
The Ignore modem control lines and Enable receiver flags are not enabled.
For raw reading, the VMIN and VTIME values are not assigned.

Or is this normal?

There are ways to easily speed up the transfer.

First, your program combines non-blocking mode with non-canonical mode. That's a degenerate combination for receiving, and suboptimal for transmitting.
You have provided no reason for using non-blocking mode, and your program is not written to properly utilize it.
Therefore your program should be revised to use blocking mode instead of non-blocking mode.

Second, the tcdrain() between write() syscalls can introduce idle time on the serial link. Use of blocking mode eliminates the need for this delay tactic between write() syscalls.

In fact with blocking mode only one write() syscall should be needed to transmit the entire dataLength. This would also minimize any idle time introduced on the serial link.
Note that the first write() does not properly check the return value for a possible error condition, which is always possible.


Bottom line: your program would be simpler and throughput would be improved by using blocking I/O.

sawdust
  • 16,103
  • 3
  • 40
  • 50
  • It's not terribly useful to calculate efficiency as a percentage... better to treat line symbols and data bits and bytes as different quantities, related by the line code. For an 8N1 bipolar line code (which is the dominant one for UART) it's straightforward to see the conversion factor is 10 symbols per data byte, with a minimum channel bandwidth of half the baud rate. If you get into other "serial" line codes like v.42bis, the relationship between bandwidth, baud rate, and data rate gets really messy really quick. (Yes, that's usually the other side of the modem from the UART) – Ben Voigt Aug 03 '18 at 20:50
  • @BenVoigt -- Removed the percentage number. – sawdust Aug 03 '18 at 23:47