我正在尝试通过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;
}
答案 0 :(得分:0)
B230400
文档是矛盾的。 cfsetspeed被记录为需要speed_t类型,而注释中指出您需要使用“ B”常量之一,例如“ B230400”。您是否尝试过使用实际的speed_t类型?
在任何情况下,您提供的速度都是波特率,在这种情况下,假设没有节流,它可以使您获得大约23,000字节/秒的速度。
速度取决于硬件和链接限制。串行协议还允许暂停传输。
FWIW,根据您列出的时间和速度,如果一切正常,您将在50秒内获得大约1 MB的内存。您实际上得到什么速度?
另一个“也”是选项结构。自从我必须执行任何串行I / O以来已经有好几年了,但是IIRC,您实际上需要设置所需的选项以及硬件支持的选项,例如CTS / RTS,XON / XOFF等。
答案 1 :(得分:0)
由于我发送的缓冲区超出了缓冲区可以立即处理的小部分,因此我耗尽了它们之间的缓冲区。
您仅提供了代码片段(而不是一个最小,完整和可验证的示例),因此您的数据大小是未知的。
但是Linux内核缓冲区大小是已知的。你觉得是什么?
(仅供参考,大小为4KB。)
如果我测量了消耗时间和写入缓冲区的字节数,我会计算出比指定波特率低近10倍的波特率。
您将吞吐量与波特率混淆了。
由于每个字符的成帧开销(可能是帧的十个位中的两个)(假设为8N1),异步串行链路的最大吞吐量(仅有效负载)将始终小于波特率。由于您的termios配置不完整,因此开销实际上可能是帧的11位中的3位(假设为8N2)。
为了获得最大的吞吐量,发送UART必须使行充满帧,并且永远不要让行空闲。
用户空间程序必须能够足够快速地提供数据,最好通过一个大的 write()来减少系统调用的开销。
设置UART或写时我错过了什么吗?
使用Linux,您对UART硬件的访问权限受到限制。
从用户空间,您的程序访问串行终端。
您的程序以次优方式访问串行终端。
您的termios配置似乎不完整。
它使硬件和软件流控制都保持不变。
停止位数不变。
Ignore modem control lines
和Enable receiver
标志未启用。
对于原始读取,未分配VMIN和VTIME值。
这是正常现象吗?
有多种方法可以轻松地加快传输速度。
首先,您的程序将非阻塞模式与非规范模式结合在一起。这是接收的简并组合,而发送则是次优组合。
您没有提供使用非阻塞模式的理由,并且未编写程序来正确使用它。
因此,应将您的程序修改为使用阻止模式而不是非阻止模式。
第二,在 write()系统调用之间的 tcdrain()可能会在串行链接上引入空闲时间。使用阻塞模式消除了 write()系统调用之间的这种延迟策略的需要。
实际上,在阻止模式下,只需要一个 write()系统调用即可传输整个dataLength
。这还将最大程度地减少串行链路上引入的任何空闲时间。
请注意,第一个 write()不能正确检查返回值是否存在可能的错误情况,这总是可能的。
最重要的是:通过使用阻塞I / O,您的程序将更简单,吞吐量也将得到提高。