【问题标题】:Blocking read on GPIO from Python: How to block using epoll() and select.EPOLLET阻止从 Python 读取 GPIO:如何使用 epoll() 和 select.EPOLLET 进行阻止
【发布时间】:2018-05-13 20:49:11
【问题描述】:

我正在嵌入式系统(ARM 内核)上尝试从 Python 进行 GPIO 访问,该系统正在运行使用 Buildroot(内核 4.1.15)构建的 linux。

我希望我的代码阻塞等待 GPIO2 上的引脚更改(即我不想通过重复调用“读取”来轮询引脚)。我正在尝试在边缘触发模式下使用“epoll”来做到这一点:

见Python docs for epoll。 select.EPOLLET 标志用于获取 epoll 的边沿触发。另见Linux docs for epoll。

为简单起见,我已经使用 sysfs 从控制台设置了我的 GPIO 引脚:

# cat /sys/class/gpio/gpio2/direction 
in
# cat /sys/class/gpio/gpio2/edge
rising

这是我的 Python 代码:

#!/usr/bin/env python
# coding=utf8

from time import sleep
import select
import sys

if __name__ == '__main__':

    try:
        pinIn = open("/sys/class/gpio/gpio2/value", "r")
    except IOError:
        print("Error setting up GPIO pin")
        sys.exit()

    myPoll = select.epoll()
    myPoll.register(pinIn.fileno(), select.EPOLLPRI | select.EPOLLET)

    while(1):

        events = myPoll.poll(4)
        print("EPoll result: %s" % (str(events),))

        for fd, event_type in events:
            print("FD: %d; Events: %d" % (fd, event_type))
            if event_type & select.EPOLLIN:
                print("-EPOLLIN!")
            if event_type & select.EPOLLPRI:
                print("-EPOLLPRI!")
            if event_type & select.EPOLLERR:
                print("-EPOLLERR!")

        value = pinIn.read(1)
        pinIn.seek(0)
        print("--> %s" % (str(value),))
        sleep(1)

为了测试,我从信号发生器以每周期约 2 秒的速度向输入引脚馈送方波,因此我可以看到引脚何时发生变化。

当我在我的嵌入式系统上运行它时,我得到了这个:

# python3 /usr/sbin/test-gpio-python.py 
EPoll result: [(3, 10)]
FD: 3; Events: 10
-EPOLLPRI!
-EPOLLERR!
--> 0

代码在 1 秒休眠时休眠,然后在下一次迭代中,poll() 立即返回并且不会阻塞。它应该阻塞,因为我的输入仅在每 2 秒一个上升沿运行。

为什么“poll()”没有阻塞?

==== 编辑:====

最初,当我尝试使用“select.EPOLLET”时,代码导致了一个奇怪的错误:

OverflowError: can't convert negative value to unsigned int

但是,我发现我不小心使用了 myPoll = select.poll() 而不是 epoll()。代码现已修复。

【问题讨论】:

标签: python select embedded-linux epoll epollet


【解决方案1】:

我决定通过查看 /proc/interrupts 来检查中断信息。

在将 GPIO 引脚的 edge 设置为“上升”后仅几秒钟:

# cat /proc/interrupts 
...
 33:        421  gpio-mxc   2 Edge      gpiolib
...

嗯,已经发生了 421 次中断!

两秒后:

# cat /proc/interrupts 
...
 33:        852  gpio-mxc   2 Edge      gpiolib
...

这可以解释。中断以每秒约 400 次的速度堆积,绝对比我在 Python 中处理它们的速度要快。

使用示波器进行的进一步调查显示,信号发生器仅输出约 1.6 V,并且看起来噪声正在触发设备上的输入电路。

当我切换到正确的信号发生器输出并在 GPIO 引脚上获得干净的信号时,我开始获得预期数量的中断,并且 python 代码正常工作(即 poll() 在输入上升沿之间正确阻塞)。

【讨论】:

猜你喜欢
  • 2020-10-10
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 1970-01-01
  • 1970-01-01
  • 2012-05-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多