前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2——GPIO子系统重要概念

2——GPIO子系统重要概念

作者头像
韦东山
发布2021-12-08 10:07:15
1.8K0
发布2021-12-08 10:07:15
举报
文章被收录于专栏:韦东山嵌入式

资料下载

coding无法使用浏览器打开,必须用git工具下载:

代码语言:javascript
复制
git clone https://e.coding.net/weidongshan/linux/doc_and_source_for_drivers.git

视频观看

百问网驱动大全

16.2 GPIO子系统重要概念

16.2.1 引入

要操作GPIO引脚,先把所用引脚配置为GPIO功能,这通过Pinctrl子系统来实现。 然后就可以根据设置引脚方向(输入还是输出)、读值──获得电平状态,写值──输出高低电平。 以前我们通过寄存器来操作GPIO引脚,即使LED驱动程序,对于不同的板子它的代码也完全不同。 当BSP工程师实现了GPIO子系统后,我们就可以: a. 在设备树里指定GPIO引脚 b. 在驱动代码中: 使用GPIO子系统的标准函数获得GPIO、设置GPIO方向、读取/设置GPIO值。 这样的驱动代码,将是单板无关的。

16.2.2 在设备树中指定引脚

在几乎所有ARM芯片中,GPIO都分为几组,每组中有若干个引脚。所以在使用GPIO子系统之前,就要先确定:它是哪组的?组里的哪一个? 在设备树中,“GPIO组”就是一个GPIO Controller,这通常都由芯片厂家设置好。我们要做的是找到它名字,比如“gpio1”,然后指定要用它里面的哪个引脚,比如<&gpio1 0>。 有代码更直观,下图是一些芯片的GPIO控制器节点,它们一般都是厂家定义好,在xxx.dtsi文件中:

在这里插入图片描述
在这里插入图片描述

我们暂时只需要关心里面的这2个属性:

代码语言:javascript
复制
gpio-controller;
#gpio-cells = <2>;

“gpio-controller”表示这个节点是一个GPIO Controller,它下面有很多引脚。 “#gpio-cells = <2>”表示这个控制器下每一个引脚要用2个32位的数(cell)来描述。 为什么要用2个数?其实使用多个cell来描述一个引脚,这是GPIO Controller自己决定的。比如可以用其中一个cell来表示那是哪一个引脚,用另一个cell来表示它是高电平有效还是低电平有效,甚至还可以用更多的cell来示其他特性。 普遍的用法是,用第1个cell来表示哪一个引脚,用第2个cell来表示有效电平:

代码语言:javascript
复制
GPIO_ACTIVE_HIGH : 高电平有效
GPIO_ACTIVE_LOW  :  低电平有效

定义GPIO Controller是芯片厂家的事,我们怎么引用某个引脚呢?在自己的设备节点中使用属性"[-]gpios",示例如下:

在这里插入图片描述
在这里插入图片描述

上图中,可以使用gpios属性,也可以使用name-gpios属性。

16.2.3 在驱动代码中调用GPIO子系统

在设备树中指定了GPIO引脚,在驱动代码中如何使用? 也就是GPIO子系统的接口函数是什么? GPIO子系统有两套接口:基于描述符的(descriptor-based)、老的(legacy)。前者的函数都有前缀“gpiod_”,它使用gpio_desc结构体来表示一个引脚;后者的函数都有前缀“gpio_”,它使用一个整数来表示一个引脚。

要操作一个引脚,首先要get引脚,然后设置方向,读值、写值。

驱动程序中要包含头文件,

代码语言:javascript
复制
#include <linux/gpio/consumer.h>   // descriptor-based

代码语言:javascript
复制
#include <linux/gpio.h>            // legacy

下表列出常用的函数:

descriptor-based

legacy

说明

获得GPIO

gpiod_get

gpio_request

gpiod_get_index

gpiod_get_array

gpio_request_array

devm_gpiod_get

devm_gpiod_get_index

devm_gpiod_get_array

设置方向

gpiod_direction_input

gpio_direction_input

gpiod_direction_output

gpio_direction_output

读值、写值

gpiod_get_value

gpio_get_value

gpiod_set_value

gpio_set_value

释放GPIO

gpio_free

gpio_free

gpiod_put

gpio_free_array

gpiod_put_array

devm_gpiod_put

devm_gpiod_put_array

有前缀“devm_”的含义是“设备资源管理”(Managed Device Resource),这是一种自动释放资源的机制。它的思想是“资源是属于设备的,设备不存在时资源就可以自动释放”。 比如在Linux开发过程中,先申请了GPIO,再申请内存;如果内存申请失败,那么在返回之前就需要先释放GPIO资源。如果使用devm的相关函数,在内存申请失败时可以直接返回:设备的销毁函数会自动地释放已经申请了的GPIO资源。 建议使用“devm_”版本的相关函数。

举例,假设备在设备树中有如下节点:

代码语言:javascript
复制
	foo_device {
		compatible = "acme,foo";
		...
		led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
			    <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
			    <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */

		power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
	};

那么可以使用下面的函数获得引脚:

代码语言:javascript
复制
struct gpio_desc *red, *green, *blue, *power;

red = gpiod_get_index(dev, "led", 0, GPIOD_OUT_HIGH);
green = gpiod_get_index(dev, "led", 1, GPIOD_OUT_HIGH);
blue = gpiod_get_index(dev, "led", 2, GPIOD_OUT_HIGH);
power = gpiod_get(dev, "power", GPIOD_OUT_HIGH);

要注意的是,gpiod_set_value设置的值是“逻辑值”,不一定等于物理值。 什么意思?

在这里插入图片描述
在这里插入图片描述

旧的“gpio_”函数没办法根据设备树信息获得引脚,它需要先知道引脚号。 引脚号怎么确定? 在GPIO子系统中,每注册一个GPIO Controller时会确定它的“base number”,那么这个控制器里的第n号引脚的号码就是:base number + n。 但是如果硬件有变化、设备树有变化,这个base number并不能保证是固定的,应该查看sysfs来确定base number。

16.2.4 sysfs中的访问方法_IMX6ULL

在sysfs中访问GPIO,实际上用的就是引脚号,老的方法。 a. 先确定某个GPIO Controller的基准引脚号(base number),再计算出某个引脚的号码。 方法如下: ① 先在开发板的/sys/class/gpio目录下,找到各个gpiochipXXX目录:

在这里插入图片描述
在这里插入图片描述

② 然后进入某个gpiochip目录,查看文件label的内容 ③ 根据label的内容对比设备树 label内容来自设备树,比如它的寄存器基地址。用来跟设备树(dtsi文件)比较,就可以知道这对应哪一个GPIO Controller。 下图是在100asK_imx6ull上运行的结果,通过对比设备树可知gpiochip96对应gpio4:

在这里插入图片描述
在这里插入图片描述

所以gpio4这组引脚的基准引脚号就是96,这也可以“cat base”来再次确认。

b. 基于sysfs操作引脚: 以100ask_imx6ull为例,它有一个按键,原理图如下:

在这里插入图片描述
在这里插入图片描述

那么GPIO4_14的号码是96+14=110,可以如下操作读取按键值:

代码语言:javascript
复制
echo  110 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio110/direction
cat /sys/class/gpio/gpio110/value
echo  110 > /sys/class/gpio/unexport

注意:如果驱动程序已经使用了该引脚,那么将会export失败,会提示下面的错误:

在这里插入图片描述
在这里插入图片描述

对于输出引脚,假设引脚号为N,可以用下面的方法设置它的值为1:

代码语言:javascript
复制
echo  N > /sys/class/gpio/export
echo out > /sys/class/gpio/gpioN/direction
echo 1 > /sys/class/gpio/gpioN/value
echo  N > /sys/class/gpio/unexport

16.2.5 sysfs中的访问方法_STM32MP157

在sysfs中访问GPIO,实际上用的就是引脚号,老的方法。 a. 先确定某个GPIO Controller的基准引脚号(base number),再计算出某个引脚的号码。 方法如下: ① 先在开发板的/sys/class/gpio目录下,找到各个gpiochipXXX目录:

在这里插入图片描述
在这里插入图片描述

② 然后进入某个gpiochip目录,查看文件label的内容 ③ 根据label的内容就知道它是哪组引脚 下图是在100ask_stm32mp157上运行的结果,可知gpiochip96对应GPIOG:

在这里插入图片描述
在这里插入图片描述

所以GPIOG这组引脚的基准引脚号就是96,这也可以“cat base”来再次确认。

b. 基于sysfs操作引脚: 以100ask_stm32mp157为例,它有一个按键,原理图如下:

在这里插入图片描述
在这里插入图片描述

那么PG2的号码是96+2=98,可以如下操作读取按键值:

代码语言:javascript
复制
echo 98 > /sys/class/gpio/export
echo in > /sys/class/gpio/gpio98/direction
cat /sys/class/gpio/gpio98/value
echo  98 > /sys/class/gpio/unexport

注意:如果驱动程序已经使用了该引脚,那么将会export失败,会提示下面的错误:

在这里插入图片描述
在这里插入图片描述

对于输出引脚,假设引脚号为N,可以用下面的方法设置它的值为1:

代码语言:javascript
复制
echo  N > /sys/class/gpio/export
echo out > /sys/class/gpio/gpioN/direction
echo 1 > /sys/class/gpio/gpioN/value
echo  N > /sys/class/gpio/unexport
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/08/26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 资料下载
  • 视频观看
  • 16.2 GPIO子系统重要概念
    • 16.2.1 引入
      • 16.2.2 在设备树中指定引脚
        • 16.2.3 在驱动代码中调用GPIO子系统
          • 16.2.4 sysfs中的访问方法_IMX6ULL
            • 16.2.5 sysfs中的访问方法_STM32MP157
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档