Linux UART比指定波特率慢

时间:2018-08-03 13:43:02

标签: linux performance system-calls uart baud-rate

我正在尝试通过UART在两个Linux系统之间进行通信。 我想发送大量数据。在指定波特率的情况下,它应该需要5秒钟左右的时间,但所需时间却接近预期时间的10倍。

由于我发送的缓冲区超出了缓冲区可以立即处理的小部分,因此我耗尽了它们之间的缓冲区。如果我测量了排空所需的时间和写入缓冲区的字节数,我会计算出比指定波特率低近10倍的波特率。

我希望慢速传输是最佳选择,但不是很多。

在设置UART或写入时我错过了什么吗?还是正常?

用于设置的代码:

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);

用于发送的代码:

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;
}

2 个答案:

答案 0 :(得分:0)

  

B230400

文档是矛盾的。 cfsetspeed被记录为需要speed_t类型,而注释中指出您需要使用“ B”常量之一,例如“ B230400”。您是否尝试过使用实际的speed_t类型?

在任何情况下,您提供的速度都是波特率,在这种情况下,假设没有节流,它可以使您获得大约23,000字节/秒的速度。

速度取决于硬件和链接限制。串行协议还允许暂停传输。

FWIW,根据您列出的时间和速度,如果一切正常,您将在50秒内获得大约1 MB的内存。您实际上得到什么速度?

另一个“也”是选项结构。自从我必须执行任何串行I / O以来已经有好几年了,但是IIRC,您实际上需要设置所需的选项以及硬件支持的选项,例如CTS / RTS,XON / XOFF等。

This might be helpful

答案 1 :(得分:0)

  

由于我发送的缓冲区超出了缓冲区可以立即处理的小部分,因此我耗尽了它们之间的缓冲区。

您仅提供了代码片段(而不是一个最小,完整和可验证的示例),因此您的数据大小是未知的。
但是Linux内核缓冲区大小是已知的。你觉得是什么?
(仅供参考,大小为4KB。)

  

如果我测量了消耗时间和写入缓冲区的字节数,我会计算出比指定波特率低近10倍的波特率。

您将吞吐量与波特率混淆了。

由于每个字符的成帧开销(可能是帧的十个位中的两个)(假设为8N1),异步串行链路的最大吞吐量(仅有效负载)将始终小于波特率。由于您的termios配置不完整,因此开销实际上可能是帧的11位中的3位(假设为8N2)。

为了获得最大的吞吐量,发送UART必须使行充满帧,并且永远不要让行空闲。
用户空间程序必须能够足够快速地提供数据,最好通过一个大的 write()来减少系统调用的开销。

  

设置UART或写时我错过了什么吗?

使用Linux,您对UART硬件的访问权限受到限制。
从用户空间,您的程序访问串行终端。
您的程序以次优方式访问串行终端。

您的termios配置似乎不完整。
它使硬件和软件流控制都保持不变。
停止位数不变。
Ignore modem control linesEnable receiver标志未启用。
对于原始读取,未分配VMIN和VTIME值。

  

这是正常现象吗?

有多种方法可以轻松地加快传输速度。

首先,您的程序将非阻塞模式与非规范模式结合在一起。这是接收的简并组合,而发送则是次优组合。
您没有提供使用非阻塞模式的理由,并且未编写程序来正确使用它。
因此,应将您的程序修改为使用阻止模式而不是非阻止模式。

第二,在 write()系统调用之间的 tcdrain()可能会在串行链接上引入空闲时间。使用阻塞模式消除了 write()系统调用之间的这种延迟策略的需要。

实际上,在阻止模式下,只需要一个 write()系统调用即可传输整个dataLength。这还将最大程度地减少串行链路上引入的任何空闲时间。
请注意,第一个 write()不能正确检查返回值是否存在可能的错误情况,这总是可能的。


最重要的是:通过使用阻塞I / O,您的程序将更简单,吞吐量也将得到提高。