[英]Linux serial communication with interrupts
I have two devices connected to each other via serial port. 我有两个通过串口相互连接的设备。 One operates as a master and the other as a slave.
一个作为主机,另一个作为从机。
The master device is an ARM based kit that is running linux. 主设备是运行Linux的基于ARM的套件。
The current situation is master sends command then poll the com port until the slave replies. 当前情况是主机发送命令,然后轮询com端口,直到从机答复为止。
Now I don't wan't to use polling. 现在,我不想使用轮询。 I need the processor to do other tasks until slave replies.
我需要处理器执行其他任务,直到从属答复为止。
I know that the solution is to use interrupt but can't find more details. 我知道解决方案是使用中断,但找不到更多详细信息。 I found some solution that uses signals.
我找到了一些使用信号的解决方案。 It reads the ttys in nonblocking mode then send io signal when data is ready.
它以非阻塞模式读取ttys,然后在数据就绪时发送io信号。
So, what is the difference between interrupts and signals in serial communication? 那么,串行通信中的中断和信号之间有什么区别? Is that right when using interrupts I should write a device driver or kernel module or so?
使用中断时应该写设备驱动程序或内核模块吗? Is there any other efficient solution in order not to use polling?
为了不使用轮询,还有其他有效的解决方案吗?
Is there any other efficient solution in order not to use polling?
为了不使用轮询,还有其他有效的解决方案吗?
Some time ago I had the same task, and the best way I found to solve it is to use pthreads . 不久前,我完成了相同的任务,而解决该问题的最佳方法是使用pthreads 。 Basically, I did next:
基本上,我接下来要做的是:
pthread_cond_signal()
pthread_cond_signal()
唤醒使用者线程 pthread_cond_wait()
function); pthread_cond_wait()
函数); once woke up -- read new data from circular buffer ( consume data) and process it properly poll()
function. poll()
在poll()
函数中提供poll()
。 If you don't need this -- you can open serial port in blocking mode and just use blocking read()
call (as proposed by @sawdust in comment) read()
调用(由@sawdust在评论中建议) This way you don't waste CPU time waiting for new data to arrive, and in the same time you don't need to mess with signals (using signals has a lot of complications , so I decided to avoid it). 这样,您就不会浪费CPU时间来等待新数据到达,并且同时您也无需弄乱信号(使用信号会带来很多麻烦 ,因此我决定避免使用它)。
The only other API to do asynchronous read is aio_read() from POSIX AIO interface. 进行异步读取的唯一其他API是来自POSIX AIO接口的aio_read() 。 But as I understand,
aio_read()
based on signals. 但据我了解,
aio_read()
基于信号。 The only difference is: 唯一的区别是:
SIGIO
signal tells you that new data is available for reading, and you need to read it manually SIGIO
信号告知您有新数据可读取,您需要手动读取 aio_read()
gives you read data (as read()
does, only asynchronously). aio_read()
为您提供读取数据(与read()
一样,仅异步)。 I would not recommend you using it, as this API doesn't seem to be widespread and doesn't have any benefits over signal-driven approach. 我不建议您使用它,因为该API似乎并不广泛,并且与信号驱动方法相比没有任何好处。
So, what is the difference between interrupts and signals in serial communication?
那么,串行通信中的中断和信号之间有什么区别?
In other words, when your serial port hardware generates interrupt, it's handled in kernel, and kernel generates SIGIO
signal, notifying your user-space application of new event (eg new data is available for reading). 换句话说,当您的串行端口硬件产生中断时,它会在内核中处理,内核会产生
SIGIO
信号,从而将新事件通知您的用户空间应用程序(例如,可以读取新数据)。
Is that right when using interrupts I should write a device driver or kernel module or so?
使用中断时应该写设备驱动程序或内核模块吗?
Generally yes, you can handle interrupts only in kernel. 通常是的,您只能在内核中处理中断。 But in this case you don't need to.
但是在这种情况下,您不需要这样做。 It was already done for you in kernel, more specifically, in line discipline code.
它已经在内核中为您完成了,更具体地说, 在行规程代码中。 It generates signal for you (when interrupt occurred), which you can use in your user-space application.
它会为您生成信号(发生中断时),您可以在用户空间应用程序中使用该信号。
In case you want some details: 如果您需要一些细节:
tty_schedule_flip()
-> queue_work(...)
-> flush_to_ldisc()
-> receive_buf()
-> tty_ldisc_receive_buf()
-> .receive_buf2()
tty_schedule_flip()
- > queue_work(...)
- > flush_to_ldisc()
- > receive_buf()
- > tty_ldisc_receive_buf()
- > .receive_buf2()
n_tty_receive_buf2()
-> n_tty_receive_buf_common()
-> __receive_buf()
n_tty_receive_buf2()
-> n_tty_receive_buf_common()
-> __receive_buf()
__receive_buf()
does: __receive_buf()
可以:
if (read_cnt(ldata)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); wake_up_interruptible_poll(&tty->read_wait, POLLIN); }
which sends SIGIO
signal, like this: kill_fasync()
-> kill_fasync_rcu()
-> send_sigio()
-> send_sigio_to_task()
-> do_send_sig_info()
-> send_signal()
它发送
SIGIO
信号,如下所示: kill_fasync()
-> kill_fasync_rcu()
-> send_sigio()
-> send_sigio_to_task()
-> do_send_sig_info()
-> send_signal()
So you can rely on kernel to deliver you a message (via signal) when corresponding interrupt occurred in serial port driver. 因此,当串行端口驱动程序中发生相应的中断时,您可以依靠内核向您发送消息(通过信号)。
[1] Serial Programming HOWTO: Asynchronous Input Example [1] 串行编程方法:异步输入示例
[2] The TTY demystified [2] TTY神秘化
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.