Linux串行通信与中断

时间:2016-09-02 10:02:04

标签: linux linux-kernel serial-port signals interrupt-handling

我有两个设备通过串口相互连接。 一个作为主人,另一个作为奴隶。

主设备是基于ARM的套件,运行linux。

当前情况是主发送命令然后轮询com端口,直到从站回复。

现在我不想使用民意调查。我需要处理器执行其他任务,直到奴隶回复。

我知道解决方案是使用中断但无法找到更多细节。 我找到了一些使用信号的解决方案。它以非阻塞模式读取ttys,然后在数据就绪时发送io信号。

那么,串行通信中的中断和信号有什么区别? 在使用中断时是否正确我应该编写设备驱动程序或内核模块? 为了不使用轮询,还有其他有效的解决方案吗?

1 个答案:

答案 0 :(得分:1)

  

为了不使用轮询,还有其他有效的解决方案吗?

多线程方法

前段时间我有同样的任务,我找到解决问题的最好方法是使用pthreads。基本上,我接下来做了:

  • 生产者线程(主线程):等待串口新数据;一旦有新数据可用 - 将其写入circular buffer生成数据)并通过pthread_cond_signal()
  • 唤醒用户线程
  • 消费者线程:等待生产者线程唤醒我(使用pthread_cond_wait()函数);一旦醒来 - 从循环缓冲区读取新数据(消耗数据)并正确处理
  • 在我的情况下,串口已在 non-blocking mode 中打开,因为我想等待poll()函数中提供的超时新数据。如果您不需要此功能 - 您可以在阻止模式中打开串口,只需使用阻止read()调用(由@sawdust在评论中提出)

这样你就不会浪费CPU时间等待新数据到达,同时你不需要弄乱信号(使用信号有很多complications,所以我决定避免它。)

AIO API

进行异步读取的唯一其他API是来自aio_read()接口的POSIX AIO。但据我所知,aio_read()基于信号。唯一的区别是:

  • SIGIO信号告诉您新数据可供阅读,您需要手动阅读
  • aio_read()为您提供读取数据(仅read(),只是异步)。

我不建议你使用它,因为这个API似乎并不普及,并且没有信号驱动方法的任何好处。

  

那么,串行通信中的中断和信号有什么区别?

  • 中断是低级概念,所以只在内核中处理
  • 信号是操作系统概念,用于内核在发生某些事件时通知您的用户空间应用程序

换句话说,当你的串口硬件产生中断时,它会在内核中处理,并且内核会生成SIGIO信号,通知你的用户空间应用程序新事件(例如,新数据可供读取)。 / p>

  

使用中断时是否正确我应该编写设备驱动程序或内核模块?

通常是的,您只能在内核中处理中断。但在这种情况下你不需要。它已经在内核中完成,更具体地说,在line discipline代码中。它会为您生成信号(发生中断时),您可以在用户空间应用程序中使用它。

如果您需要一些细节:

  • 驱动程序代码流程:tty_flip_buffer_push() - > 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()
  • __receive_buf()

    if (read_cnt(ldata)) {
        kill_fasync(&tty->fasync, SIGIO, POLL_IN);
        wake_up_interruptible_poll(&tty->read_wait, POLLIN);
    }
    
  • 发送SIGIO信号,如下所示:kill_fasync() - > kill_fasync_rcu() - > send_sigio() - > send_sigio_to_task() - > do_send_sig_info() - > send_signal()

因此,当串口驱动程序中发生相应的中断时,您可以依赖内核向您发送消息(通过信号)。

另见

[1] Serial Programming HOWTO: Asynchronous Input Example

[2] The TTY demystified

[3] LDD3: Asynchronous Notification