一篇文章讲明白Linux下控制GPIO的三种方法

简介: 一篇文章讲明白Linux下控制GPIO的三种方法

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

//snip

GPIOs 184-215, //代码效果参考:http://www.zidongmutanji.com/zsjx/506317.html

platform/ff770000.pinctrl, gpio6:

gpio-193 (? ) in hi

gpio-194 (? ) in hi

GPIOs 216-247, platform/ff770000.pinctrl, gpio7:

gpio-218 (enable ) out hi

gpio-219 (lcd_en ) in hi

gpio-220 (lcd_cs ) in hi

gpio-221 (gslX680 wake pin ) out hi

gpio-222 (gslX680 irq pin ) out lo

gpio-223 (headset_gpio ) in hi

gpio-233 (? ) in hi

gpio-234 (? ) 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 # echo 254 > export

root@rk3288:/sys/class/gpio # ls

export

gpio254

1.2.2 设置成输出

root@rk3288:/sys/class/gpio/gpio254 # echo out > direction

root@rk3288:/sys/class/gpio/gpio254 # cat direction

out

1.2.3 输出高电平

root@rk3288:/sys/class/gpio/gpio254 # echo 1 > value

root@rk3288:/sys/class/gpio/gpio254 # cat //代码效果参考:http://www.zidongmutanji.com/bxxx/195682.html

value

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);

/向内核申请 gpio,要使用 GPIO 首先应该向内核进行申请,返回 0,代表申请成功,

可以进行后续操作/

void gpio_free(unsigned gpio);

/对应 gpio_request,是使用完gpio以后把gpio释放掉/

int gpio_direction_input(unsigned gpio);

/设置 GPIO 为输入/

int gpio_direction_output(unsigned gpio, int value);

/设置 GPIO 为输出/

int gpio_get_value(unsigned gpio);

/读取 GPIO 的值/

int gpio_set_value(unsigned gpio);

/设置 GPIO 的值/

2.1.3 操作gpio

功能和1.2一样。

#define GPIO8_A6 254

ret = gpio_request(GPIO8_A6 , "gpio8_a6");

if (!ret) {

printk("request for gpio8_a6 failed:%d\n", ret);

return 0;

}

gpio_direction_output(GPIO8_A6 ,1);//设置GPIO8_A6为输出功能且输出高电平

2.2 ioremap控制gpio

这种方法会降低程序的可读性,不建议使用。

linux内核空间访问的地址为虚拟地址(3~4GB),故在内核空间操作某个寄存器时,需先通过ioremap函数将物理地址映射成虚拟地址。

用ioremap() 获取寄存器的地址:

unsigned int iomem *base_addr1; //iomem可选择,告诉你为虚拟地址

#define GPIO8_REGBASE (0x20A0000)

#define GPIO8_A6 ((volatile unsigned int )(base_addr1 + 6)) //指针unsigned int为4字节,指针加1,字节加4

base_addr1 = ioremap(GPIO8_REGBASE, 0x14)

通过 readl() 或者 writel() 函数直接操作映射后的地址:

GPIO8_A6 |= (1[8);

int temp;

temp = readl(GPIO8_A6);

temp |= (1[8);

writel(temp, GPIO8_A6);

使用完后,取消映射:

iounmap(base_addr1);

3. 查看GPIO全部信息

cat /sys/kernel/debug/pinctrl/pinctrl/pinmux-pins

Pinmux settings per pin

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 <span class="hljs-keyword

相关文章
|
2月前
|
Ubuntu 物联网 Linux
从零安装一个Linux操作系统几种方法,以Ubuntu18.04为例
一切就绪后,我们就可以安装操作系统了。当系统通过优盘引导起来之后,我们就可以看到跟虚拟机中一样的安装向导了。之后,大家按照虚拟机中的顺序安装即可。 好了,今天主要介绍了Ubuntu Server版操作系统的安装过程,关于如何使用该操作系统,及操作系统更深层的原理,还请关注本号及相关圈子。
|
2月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
832 10
|
2月前
|
Ubuntu Linux 图形学
推广与体验Ubuntu Linux的便捷方法
如果你的朋友或家人对尝试Linux感兴趣,但希望在安装之前先体验一下,你可以分享以下链接给他们:Ubuntu在线导览。通过这个链接,他们可以在任何地方轻松体验Ubuntu,无需安装即可深入了解这个流行的操作系统。
|
2月前
|
XML 缓存 Linux
在Linux环境下解决Visual Studio Code字体显示异常和字体替换方法。
解决Linux下VS Code字体显示异常,需要对Linux字体渲染机制有所理解,并对VS Code的配置选项进行合理设置。替换字体时则要通过系统字体配置或VS Code设置来完成。通过上述方法,可以有效地解决字体显示问题,从而提升代码编辑的视觉体验。
255 0
|
5月前
|
NoSQL Linux 编译器
GDB符号表概念和在Linux下获取符号表的方法
通过掌握这些关于GDB符号表的知识,你可以更好地管理和理解你的程序,希望这些知识可以帮助你更有效地进行调试工作。
231 16
|
3月前
|
网络协议 Ubuntu Linux
Wireguard in Linux的安装方法
本文介绍了如何在Ubuntu和Rocky Linux中安装配置WireGuard,并探讨了配置过程中可能出现的DNS泄露问题及解决方法,包括通过nmtui设置DNS及调整DNS优先级参数。
|
6月前
|
Linux Shell
Linux系统下快速批量创建和删除文件的方法
总的来说,使用shell脚本来批量处理文件是一种非常强大的工具,只要你愿意花时间学习和实践,你会发现它能大大提高你的工作效率。
351 19
|
6月前
|
Ubuntu Linux 网络安全
如何在Linux中更改主机名?修改主机名最新方法
本期教程将指导您如何在Linux系统中更改主机名。主机名是Linux系统的常用功能,用于识别服务器,帮助区分不同服务器,并与网络进程和其他应用程序协同工作。教程涵盖显示当前主机名的方法(通过`hostname`命令),以及在CentOS 7、Debian 9和Ubuntu 16.04及以上版本中更改主机名的步骤(使用`hostnamectl set-hostname`命令)。对于其他Linux版本,可编辑`/etc/hostname`文件实现更改。记得重启相关服务或服务器以使更改生效!
1545 12
|
6月前
|
安全 Linux 网络安全
在Linux(CentOS和AWS)上安装更新的git2的方法并配置github-ssh
经过以上这些步骤,你现在就能在GitHub上顺利往返,如同海洋中的航海者自由驰骋。欢迎你加入码农的世界,享受这编程的乐趣吧!
233 10