2

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

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

请参阅Python 文档以了解 epollselect.EPOLLET标志用于获取 epoll 的边沿触发。另请参阅epoll 的 Linux 文档

为简单起见,我已经使用 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()。代码现已修复。

4

1 回答 1

0

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

在这里,在将 GPIO 引脚的边缘设置为“上升”后仅几秒钟:

# 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() 在输入的上升沿之间正确阻塞)。

于 2017-11-30T19:23:50.917 回答