1. 应用空间控制gpio
1.1简介
在/sys/class/gpio/下有个export文件,向export文件写入要操作的GPIO号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction和value等,direction控制GPIO输入或者输出模式,而value可控制GPIO的状态或者读取状态。
/sys/class/gpio/目录下各个文件说明:
/sys/class/gpio/export文件用于通知系统需要导出控制的GPIO引脚编号;
/sys/class/gpio/unexport 用于通知系统取消导出;
/sys/class/gpio/gpioX/direction文件,可以写入in(设置输入方向)或out(设置输出方向);
/sys/class/gpio/gpioX/value文件是可以读写GPIO状态;
/sys/class/gpio/gpiochipX目录保存系统中GPIO寄存器的信息,包括每个寄存器控制引脚的起始编号,寄存器名称,引脚总数;其中X表示具体的引脚编号。
1.2操作gpio
比如我要操作GPIO8_A6作为高电平输出有效, 那么有以下三个操作:
1. 2.1 换算对应的gpio number
可以通过/sys/kernel/debug/gpio查询信息:
root@rk3288:/sys/kernel/debug # cat gpio
GPIOs 184-215, platform/ff770000.pinctrl, gpio6:
GPIOs 216-247, platform/ff770000.pinctrl, gpio7:
gpio-218 (enable ) out hi
gpio-221 (gslX680 wake pin ) out hi
gpio-222 (gslX680 irq pin ) out lo
gpio-223 (headset_gpio ) in hi
GPIOs 248-279, platform/ff770000.pinctrl, gpio8:
GPIOs 280-311, platform/ff770000.pinctrl, gpio15:
可以看到gpio8是以nubmer为248开始, 那么GPIO8_A6就是 248 + 6 = 254,接下来就可以导出gpio了。
root@rk3288:/sys/class/gpio
root@rk3288:/sys/class/gpio
1.2.2 设置成输出
root@rk3288:/sys/class/gpio/gpio254
root@rk3288:/sys/class/gpio/gpio254
1.2.3 输出高电平
root@rk3288:/sys/class/gpio/gpio254
root@rk3288:/sys/class/gpio/gpio254
1.3 总结
这种方式一般不采用,为了gpio使用的安全性,一般是不将gpio的使用权暴露给应用层的,即sys/class/下没有gpio节点。
2. 内核空间控制gpio
在内核空间控制gpio有两种方法,第一种是通过调用gpiolib的接口来控制gpio;第二种是通过ioremap来控制gpio。
2.1 gpiolib控制gpio
2.1.1 gpiolib简介
Linux Kernel 中对 GPIO 资源进行了抽象,抽象出一个叫做 Gpiolib 的东西。

中间层是 Gpiolib,用于管理系统中的 GPIO。Gpiolib 汇总了 GPIO 的通用操作,根据 GPIO 的特性,Gpiolib 对上(其他 Drivers)提供的一套统一通用的操作 GPIO 的软件接口,屏蔽了不同芯片的具体实现。对下,Gpiolib 提供了针对不同芯片操作的一套 framework,针对不同芯片,只需要实现 Specific Chip Driver ,然后使用 Gpiolib 提供的注册函数,将其挂接到 Gpiolib 上,这样就完成了这一套东西。
2.1.2 Gpiolib 为其他驱动提供的 APIs
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
int gpio_set_value(unsigned gpio);
2.1.3 操作gpio
功能和1.2一样。
ret = gpio_request(GPIO8_A6 , "gpio8_a6");
printk("request for gpio8_a6 failed:%d\n", ret);
gpio_direction_output(GPIO8_A6 ,1);
2.2 ioremap控制gpio
这种方法会降低程序的可读性,不建议使用。
linux内核空间访问的地址为虚拟地址(3~4GB),故在内核空间操作某个寄存器时,需先通过ioremap函数将物理地址映射成虚拟地址。
用ioremap() 获取寄存器的地址:
unsigned int __iomem *base_addr1;
#define GPIO8_REGBASE (0x20A0000)
#define GPIO8_A6 (*(volatile unsigned int *)(base_addr1 + 6))
base_addr1 = ioremap(GPIO8_REGBASE, 0x14)
通过 readl() 或者 writel() 函数直接操作映射后的地址:
使用完后,取消映射:
iounmap(base_addr1);
3. 查看GPIO全部信息
cat /sys/kernel/debug/pinctrl/pinctrl/pinmux-pins
Format: pin (name): mux_owner gpio_owner hog?
pin 0 (gpio0-0): wireless-wlan (GPIO UNCLAIMED) function wireless-wlan group wifi-wake-host
pin 1 (gpio0-1): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 2 (gpio0-2): (MUX UNCLAIMED) gpio0:2
pin 3 (gpio0-3): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 4 (gpio0-4): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 5 (gpio0-5): (MUX UNCLAIMED) gpio0:5
pin 6 (gpio0-6): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 7 (gpio0-7): (MUX UNCLAIMED) gpio0:7
pin 8 (gpio0-8): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 9 (gpio0-9): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 10 (gpio0-10): (MUX UNCLAIMED) (GPIO UNCLAIMED)
pin 11 (gpio0-11): ff050000.i2c (GPIO UNCLAIMED) function i2c1 group i2c1-xfer
pin 12 (gpio0-12): ff050000.i2c (GPIO UNCLAIMED) function i2c1 group i2c1-xfer
pin 13 (gpio0-13): (MUX UNCLAIMED) (GPIO UNCLAIMED)
根据对比实验,“MUX UNCLAIMED” 的意思好像是该复用引脚未被配置,仅个人小实验,不具备绝对准确性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2020-11-06 Socket缓冲区大小修改与系统设置
2020-11-06 shell 将变量当命令执行问题【多条命令同时执行问题】
2020-11-06 将make的输出重定向到文件
2018-11-06 windows下网络丢包模拟软件(Network Emulator for Windows Toolkit)
2017-11-06 使用boost的deadline_timer实现一个异步定时器
2017-11-06 C++11 lambda 表达式解析
2017-11-06 C++11使用emplace_back代替push_back