我最近注意到我的系统(运行在 AT91SAM9G15 上)有一个非常奇怪的行为:尽管我一直在读取串行端口,但 TTY 驱动程序有时需要 1.2 秒才能从输入队列传送数据。 事情是:我没有丢失任何数据,只是需要太多调用才能读取数据。
也许我的代码可以帮助解释这个问题。
首先,我设置我的串口:
/* 8N1 */
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
/** Parity bit (none) */
tty.c_cflag &= ~(PARENB | PARODD);
/** Stop bit (1)*/
tty.c_cflag &= ~CSTOPB;
/* Noncanonical mode */
tty.c_lflag = 0;
tty.c_oflag = 0;
tty.c_cc[VMIN] = 0;
tty.c_cc[VTIME] = 0;
稍后,select 被调用:
s_ret = select(rfid_fd + 1, &set, NULL, NULL, &port_timeval);
所以 read() 可以发挥它的魔力:
...
if ((rd_ret = read(rfid_fd, &recv_buff[u16_recv_len], (u16_req_len - u16_recv_len))) > 0)
...
紧接着,如果我继续读取串行端口 15 秒,有好几次我都看不到数据,而且我知道准时到达(带有时间戳)的数据来晚了。从输入队列中获取数据的延迟可能从 300 毫秒到 1.5 秒不等。
我已经尝试了所有我能想到的设置。现在很棘手,因为我不知道 at91 UART 驱动程序是否没有向 tty 驱动程序传送数据,或者 tty 驱动程序没有获取它?这是哪个?
如有任何帮助,我们将不胜感激。
最佳答案
设置端口标志的正常过程是读取 termios
结构,保存它以供以后恢复,修改(在它的副本中)您想要更改的标志,然后执行 tcsetattr()
调用。您已经初始化了 c_lflag = 0;
,这可能会对您的问题产生一些次要影响。
接下来您必须考虑阅读有关 VMIN
和 VTIME
元素的文档。将两者都设置为 0
会使驱动程序成为非阻塞设备,因此您将进入一个循环,试图读取缓冲区中应该包含的任何内容。但在这样做之前,请三思,您有两个线程争相将字符放入缓冲区(您的进程试图从缓冲区中获取它,而驱动程序中断例程试图将刚刚读取的字符放入)而没有休息。等待一个字符可用会更好(可能这就是问题所在),将 VMIN
设置为 1
并将 VTIME
设置为 0
。这使得驱动程序在一个字符可用时立即唤醒您的进程,并且可能更接近您想要的。
经过所有这些猜测,您还没有发布任何可用于检查您所说内容的可重现代码,因此这是我们能为您提供的最多帮助。
关于linux - TTY 输入队列太慢无法返回数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42123077/