GPIO控制
嵌入式linux下应用编程会经常使用到gpio,GPIO 可以通过 sysfs 方式进行操控,进入到/sys/class/gpio 目录下,如下所示:
可以看到该目录下包含两个文件 export、 unexport 以及 5 个 gpiochipX(X 等于 0、 32、 64、 96、 128)命名的文件夹。
⚫ gpiochipX: 当前 SoC 所包含的 GPIO 控制器,不同的soc包含不同的GPIO控制器,当前使用的soc的GPIO控制器分别为 GPIO1、 GPIO2、 GPIO3、 GPIO4、 GPIO5,在这里分别对应 gpiochip0、 gpiochip32、gpiochip64、 gpiochip96、 gpiochip128 这 5 个文件夹, 每一个 gpiochipX 文件夹用来管理一组 GPIO。
随便进入到其中某个目录下,可以看到这些目录下包含了如下文件:
在这个目录我们主要关注的是 base、 label、 ngpio 这三个属性文件,这三个属性文件均是只读、不可写。
base: 与 gpiochipX 中的 X 相同,表示该控制器所管理的这组 GPIO 引脚中最小的编号。每一个 GPIO引脚都会有一个对应的编号, Linux 下通过这个编号来操控对应的 GPIO 引脚。
label: 该组 GPIO 对应的标签,也就是名字。
ngpio: 该控制器所管理的 GPIO 引脚的数量(所以引脚编号范围是: base ~ base+ngpio-1) 。
对于给定的一个 GPIO 引脚,如何计算它在 sysfs 中对应的编号呢?其实非常简单,譬如给定一个 GPIO引脚为 GPIO4_IO16,那它对应的编号是多少呢?首先我们要确定 GPIO4 对应于 gpiochip96,该组 GPIO 引脚的最小编号是 96(对应于 GPIO4_IO0),所以 GPIO4_IO16 对应的编号自然是 96 + 16 = 112;同理GPIO3_IO20 对应的编号是 64 + 20 = 84。
⚫ export: 用于将指定编号的 GPIO 引脚导出。 在使用 GPIO 引脚之前,需要将其导出,导出成功之后才能使用它。 注意 export 文件是只写文件,不能读取,将一个指定的编号写入到 export 文件中即可将对应的 GPIO 引脚导出,譬如:
echo 0 > export # 导出编号为 0 的 GPIO 引脚
导出成功之后会发现在/sys/class/gpio 目录下生成了一个名为 gpio0 的文件夹(gpioX, X 表示对应的编号)。这个文件夹就是导出来的 GPIO 引脚对应的文件夹,用于管理、控制该 GPIO 引脚,稍后再给大家介绍。
unexport: 将导出的 GPIO 引脚删除。当使用完 GPIO 引脚之后,我们需要将导出的引脚删除,同样该文件也是只写文件、不可读,譬如:
echo 0 > unexport # 删除导出的编号为 0 的 GPIO 引脚
删除成功之后,之前生成的 gpio0 文件夹就会消失!
以上就给大家介绍了/sys/class/gpio 目录下的所有文件和文件夹,控制 GPIO 引脚主要是通过 export 导出之后所生成的 gpioX(X 表示对应的编号)文件夹,在该文件夹目录下存在一些属性文件可用于控制 GPIO引脚的输入、输出以及输出的电平状态等。
GPIO使用
将指定的编号写入到 export 文件中,可以导出指定编号的 GPIO 引脚,导出成功之后会在/sys/class/gpio目录下生成对应的 gpioX(X 表示 GPIO 的编号)文件夹,以前面所生成的 gpio0 为例,进入到 gpio0 目录,该目录下的文件如下所示:
我们主要关心的文件是 active_low、 direction、 edge 以及 value 这四个属性文件,接下来分别介绍这四个属性文件的作用:
⚫ direction: 配置 GPIO 引脚为输入或输出模式。该文件可读、可写,读表示查看 GPIO 当前是输入还是输出模式,写表示将 GPIO 配置为输入或输出模式;读取或写入操作可取的值为"out"(输出模式)和"in"(输入模式),如下所示:
⚫ value: 在 GPIO 配置为输出模式下,向 value 文件写入"0"控制 GPIO 引脚输出低电平,写入"1"则控制 GPIO 引脚输出高电平。在输入模式下,读取 value 文件获取 GPIO 引脚当前的输入电平状态。譬如:
# 获取 GPIO 引脚的输入电平状态
echo "in" > direction
cat value
# 控制 GPIO 引脚输出高电平
echo "out" > direction
echo "1" > value
⚫ active_low: 这个属性文件用于控制极性, 可读可写,默认情况下为 0,譬如:
# active_low 等于 0 时
echo "0" > active_low
echo "out" > direction
echo "1" > value #输出高
echo "0" > value #输出低
# active_low 等于 1 时
$ echo "1" > active_low
$ echo "out" > direction
$ echo "1" > value #输出低
$ echo "0" > value #输出高
由此看出, active_low 的作用已经非常明显了, 对于输入模式来说也同样适用。
⚫ edge: 控制中断的触发模式,该文件可读可写。 在配置 GPIO 引脚的中断触发模式之前,需将其设置为输入模式:
非中断引脚: echo "none" > edge
上升沿触发: echo "rising" > edge
下降沿触发: echo "falling" > edge
边沿触发: echo "both" > edge
当引脚被配置为中断后可以使用 poll()函数监听引脚的电平状态变化,在后面的示例中将向大家介绍。
注意:并不是任何时候都会存在edge文件,当GPIO控制器没有进行中断配置时,edge是不存在的。所以使用edge进行中断配置,必须保证设备树中GPIO控制器进行了中断配置:
类似如下情况,设备树不进行GPIO控制器的中断描述时,edge不存在!
input子系统,gpio-keys使用
当我们希望gpio作为输入并且由中断触发时可以使用linux自带的key驱动。如果要使用内核自带的 KEY 驱动的话需要配置 Linux 内核。按照如下路径找到相应的配置选项:
Linux 内核自带的 KEY 驱动文件为drivers/input/keyboard/gpio_keys.c, gpio_keys.c 采用了 platform 驱动框架,在 KEY 驱动上使用了 input 子系统实现。
要 使 用 Linux 内 核 自 带 的 按 键 驱 动 程 序 很 简 单 , 只 需 要 根 据Documentation/devicetree/bindings/input/gpio-keys.txt 这个文件在设备树中添加指定的设备节点即可,节点要求如下:
①、节点名字为“gpio-keys”。
②、 gpio-keys 节点的 compatible 属性值一定要设置为“gpio-keys”。
③、所有的 KEY 都是 gpio-keys 的子节点,每个子节点可以用如下属性描述自己:
gpios: KEY 所连接的 GPIO 信息。
interrupts: KEY 所使用 GPIO 中断信息,不是必须的,可以不写。
label: KEY 名字
linux,code: KEY 要模拟的按键,也就是示例代码 58.1.2.4 中的这些按键。
④、如果按键要支持连按的话要加入 autorepeat。
打开 dts,根据上面的要求创建对应的设备节点,设备节点内容如下所示:
gpio-keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
autorepeat;
key0 {
label = "GPIO Key Enter";
linux,code = <KEY_ENTER>;
gpios = <&gpio1 18 GPIO_ACTIVE_LOW>;
};
};
注意:缺省interrupts属性的前提是GPIO控制器已经配置了中断,如果使用电平触发中断,则不建议保留autorepeat属性,否则会一直触发中断。
测试
进入系统,使用如下命令(eventx换成自己的节点)进行测试,按下按键会上报input格式数据
hexdump /dev/input/eventx