1. GPIO子系统概述
GPIO(General Purpose Input/Output)是嵌入式系统和单片机开发中最基础也最常用的外设接口之一。在Linux系统中,GPIO子系统作为内核的核心组件,为开发者提供了统一的操作接口。我第一次接触GPIO是在2013年做一个树莓派项目时,当时就被这种"用软件控制硬件引脚"的能力深深吸引。
简单来说,GPIO就像是你家墙上的电源插座 - 你可以选择给某个插座通电(输出模式),也可以用它检测是否有电器插入(输入模式)。Linux内核通过GPIO子系统把这些物理引脚抽象成软件可操作的对象,让我们不用直接操作寄存器就能控制硬件。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. GPIO子系统架构解析
2.1 内核空间架构
Linux GPIO子系统的架构设计体现了Unix"一切皆文件"的哲学。在内核层面,它主要包含以下几个关键组件:
-
GPIO芯片驱动层:直接与硬件交互,负责特定SoC或GPIO扩展芯片的寄存器操作。比如bcm2835_gpio.c就是树莓派的GPIO控制器驱动。
-
GPIO核心层:提供统一的API接口,实现gpiolib框架。这个层就像交通警察,管理所有GPIO控制器的注册和操作请求分发。
-
GPIO用户接口层:通过sysfs和chardev两种方式向用户空间暴露操作接口。在较新内核中,chardev(/dev/gpiochipX)正在逐步取代传统的sysfs接口。
2.2 用户空间访问方式
在实际开发中,我们主要通过以下几种方式操作GPIO:
c复制// 传统sysfs方式(逐步淘汰)
echo 17 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio17/direction
echo 1 > /sys/class/gpio/gpio17/value
// 新字符设备方式(推荐)
struct gpiohandle_request req;
fd = open("/dev/gpiochip0", O_RDWR);
ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req);
重要提示:从Linux 4.8开始,新的gpiod接口逐渐成为标准,旧的sysfs接口可能会在未来的内核版本中被移除。
3. 设备树中的GPIO配置
3.1 设备树绑定
在现代Linux系统中,GPIO资源通常通过设备树(Device Tree)进行声明和分配。一个典型的GPIO节点定义如下:
dts复制gpio-keys {
compatible = "gpio-keys";
button {
label = "Power Button";
gpios = <&gpio 17 GPIO_ACTIVE_LOW>;
linux,code = <KEY_POWER>;
};
};
这段配置表示将GPIO17用作低电平有效的电源按键。
3.2 引脚复用配置
许多SoC的GPIO引脚都有复用功能(mux),比如同一个物理引脚既可以作为普通GPIO,也可以配置为SPI时钟线。在设备树中通常这样配置:
dts复制&iomuxc {
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
