linux gpio控制之sysfs接口和gpiod
一、sysfs接口
在3.14及之后的linux中对gpio提供了sysfs接口,说明文档:Documents/gpio/sysfs.txt。
Platforms which use the "gpiolib" implementors framework may choose to configure a sysfs user interface to GPIOs.This is different from the debugfs interface, since it provides control over GPIO direction and value instead of just showing a gpio state summary. Plus, it could be present on production systems without debugging support.
Note that standard kernel drivers exist for common "LEDs and Buttons" GPIO tasks: "leds-gpio" and "gpio_keys", respectively. Use those instead of talking directly to the GPIOs; they integrate with kernel frameworks better than your userspace code could.
1. 目录
/sys/class/gpio
2. 操作
1) echo 29 > export 2) 此时会产生一个gpio29 的目录. 3) cd gpio29 4) 关注以下几个文件: direction 这个文件是控制你是输出还是输入模式 如果想设置为输入:echo in > direction 如果想设置为输出:echo out > direction value 这个文件是在输出模式时,控制高低电平 高电平:echo 1 > value 低电平:echo 0 > value edge 这个控制中断触发模式 无: echo none > edge 上升沿触发:echo rising > edge 下降沿触发:echo falling > edge 轮询:echo both > edge active_low: 这个按照官方的说法是这个翻转电平,输入非零的数即上升沿变为下降沿。 o: echo 0 > active_low 非零的数: echo 3 > active_low 5)关闭这个GPIO控制。 cd /sys/class/gpio/ echo 29 > unexport
二、Linux读写GPIO的几种方法
1. 用GPIO sysfs读写IO
在Linux中,最常见的读写GPIO方式就是用GPIO sysfs interface,是通过操作/sys/class/gpio
目录下的export
、unexport
、gpio{N}/direction
, gpio{N}/value
(用实际引脚号替代{N})等文件实现的,经常出现shell脚本里面。比如在shell中控制树莓派3B的GPIO12:
sudo su
cd /sys/class/gpio
echo 12 > export
echo out > gpio12/direction # io used for output
echo 1 > gpio12/value # output logic 1 level
echo 0 > gpio12/value # output logic 0 level
echo 12 > unexport
基于GPIO sysfs interface封装的库很多,这里推荐vsergeev写的python-periphery、c-periphery和lua-periphery,python、lua和c任君挑选,通用性挺好的。
GPIO sysfs interface目前用的较广泛,但存在一些问题,比如不能并发获取sysfs属性、基本是为shell设计接口。所以从linux 4.8开始gpiod取代了它。
Since linux 4.8 the GPIO sysfs interface is deprecated. User space should use
the character device instead. This library encapsulates the ioctl calls and
data structures behind a straightforward API.
2. 用libgpiod读写IO
新的设计gpiod,GPIO访问控制是通过操作字符设备文件(比如/dev/gpiodchip0
)实现的,并通过libgpiod提供一些命令工具、c库以及python封装。
The new character device interface guarantees all allocated resources are
freed after closing the device file descriptor and adds several new features
that are not present in the obsolete sysfs interface (like event polling,
setting/reading multiple values at once or open-source and open-drain GPIOs).
Unfortunately interacting with the linux device file can no longer be done
using only standard command-line tools. This is the reason for creating a
library encapsulating the cumbersome, ioctl-based kernel-userspace interaction
in a set of convenient functions and opaque data structures.
Additionally this project contains a set of command-line tools that should
allow an easy conversion of user scripts to using the character device.
通过libgpiod提供的gpioset
、gpioget
、gpiomon
可以快速的读写GPIO和检测输入事件。
sudo apt install -y gpiod
sudo gpioset 0 12=0
sudo gpiomon 0 12 # detect event on gpio12
gpiod由于比较新,用的人还非常少,虽说libgpiod里面有python封装,但还没有打包到debian stretch的仓库里面,所以用python ctypes封装了一份,在voice-engine/gpio-next,控制一个LED的python代码是这样:
import time
from gpio_next import GPIO
LED = GPIO(12, direction=1)
for i in range(10):
LED.write(i & 1)
time.sleep(1)
用sysfs,或gpiod,都是用linux对GPIO封装的接口,封装之后的通用性好了,但性能会变弱。如果学过51、ARM单片机,最熟悉读写GPIO方式大概就是直接操作GPIO寄存器,这是最快速的操控IO口方式,而在Linux中同样也可以直接操作GPIO寄存器。
3. 寄存器直接读写IO
树莓派相对单片机,用的是带MMU的ARM SoC BCM2837,地址空间略复杂一点,有不同的地址空间的映射,从 BCM2837数据手册来看,GPIO寄存器总线地址(bus address)从0x7E200000开始(见下图),映射的物理地址是0x3F200000(参见手册第6页)。
在Linux下直接读写物理地址,先要打开设备文件/dev/mem
,然后用mmap
把文件映射,最后根据寄存器地址读写相应的寄存器。
可以用devmem2
来读写物理内存地址,如果不能apt install devmem2
,可以在https://github.com/VCTLabs/devmem2下载并编译一份。比如,读写树莓派的IO状态:
sudo devmem2 0x3F200034 w
Physical addresses range from 0x3F000000 to 0x3FFFFFFF for peripherals. The bus addresses for peripherals are setup to map on to the peripheral bus add ressrange starting at 0x7E000000. Thus a peripheral advertised here at bus address 0x7Ennnnnn is available at physical address 0x3Fnnnnnn.
Python库RPi.GPIO就是通过直接访问寄存器控制GPIO的,由于不同芯片的GPIO寄存器地址大多不一样,所以没有什么通用性。
由于树莓派上可以跑通用的Debian Linux系统,有很多软件资源可以使用,把IO口读写和一些软件资源结合起来,有些意想不到的效果。
参考:
1. http://blog.csdn.net/mirkerson/article/details/8464290
2. https://www.cnblogs.com/chenfulin5/p/6274076.html