当前位置: 首页 > news >正文

详解GPIO子系统

好长时间没去写博客了,今天呢,我们来讲讲GPIO子系统,我们在讲解一个新东西之前,得先去了解一下他是干啥的吧,所以下面我们来看看关于GPIO子系统的重要的概念:

引入:

要操作GPIO引脚,先把所用引脚配置为GPIO功能,这通过Pinctrl子系统来实现。

然后就可以根据设置引脚方向(输入还是输出)、读值──获得电平状态,写值──输出高低电平。

以前我们通过寄存器来操作GPIO引脚,即使LED驱动程序,对于不同的板子它的代码也完全不同。

当BSP工程师实现了GPIO子系统后,我们就可以:

a. 在设备树里指定GPIO引脚

b. 在驱动代码中:

使用GPIO子系统的标准函数获得GPIO、设置GPIO方向、读取/设置GPIO值。

这样的驱动代码,将是单板无关的。

在设备树中指定引脚:

在几乎所有ARM芯片中,GPIO都分为几组,每组中有若干个引脚。所以在使用GPIO子系统之前,就要先确定:它是哪组的?组里的哪一个?

在设备树中,“GPIO组”就是一个GPIO Controller,这通常都由芯片厂家设置好。我们要做的是找到它名字,比如“gpio1”,然后指定要用它里面的哪个引脚,比如<&gpio1  0>。

有代码更直观,下图是一些芯片的GPIO控制器节点,它们一般都是厂家定义好,在xxx.dtsi文件中:

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

“gpio-controller”表示这个节点是一个GPIO Controller,它下面有很多引脚。

“#gpio-cells = <2>”表示这个控制器下每一个引脚要用2个32位的数(cell)来描述。

为什么要用2个数?其实使用多个cell来描述一个引脚,这是GPIO Controller自己决定的。比如可以用其中一个cell来表示那是哪一个引脚,用另一个cell来表示它是高电平有效还是低电平有效,甚至还可以用更多的cell来示其他特性。

普遍的用法是,用第1个cell来表示哪一个引脚,用第2个cell来表示有效电平:

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

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

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

在设备树中指定了GPIO引脚,在驱动代码中如何使用?

也就是GPIO子系统的接口函数是什么?

GPIO子系统有两套接口:基于描述符的(descriptor-based)、老的(legacy)。前者的函数都有前缀“gpiod_”,它使用gpio_desc结构体来表示一个引脚;后者的函数都有前缀“gpio_”,它使用一个整数来表示一个引脚。

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

下表列出常用的函数:

有前缀“devm_”的含义是“设备资源管理”(Managed Device Resource),这是一种自动释放资源的机制。它的思想是“资源是属于设备的,设备不存在时资源就可以自动释放”。

比如在Linux开发过程中,先申请了GPIO,再申请内存;如果内存申请失败,那么在返回之前就需要先释放GPIO资源。如果使用devm的相关函数,在内存申请失败时可以直接返回:设备的销毁函数会自动地释放已经申请了的GPIO资源。

建议使用“devm_”版本的相关函数。

下面来看一个简单的例子:

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

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

下面我们来看看怎么去写一个具体的驱动程序:

编写思路:

GPIO的地位跟其他模块,比如I2C、UART的地方是一样的,要使用某个引脚,需要先把引脚配置为GPIO功能,这要使用Pinctrl子系统,只需要在设备树里指定就可以。在驱动代码上不需要我们做任何事情。

GPIO本身需要确定引脚,这也需要在设备树里指定。

设备树节点会被内核转换为platform_device。

对应的,驱动代码中要注册一个platform_driver,在probe函数中:获得引脚、注册file_operations。

在file_operations中:设置方向、读值/写值。

下图就是一个设备树的例子:

在设备树中添加Pinctrl信息:

有些芯片提供了设备树生成工具,在GUI界面中选择引脚功能和配置信息,就可以自动生成Pinctrl子结点。把它复制到你的设备树文件中,再在client device结点中引用就可以。

有些芯片只提供文档,那就去阅读文档,一般在内核源码目录Documentation\devicetree\bindings\pinctrl下面,保存有该厂家的文档。

如果连文档都没有,那只能参考内核源码中的设备树文件,在内核源码目录arch/arm/boot/dts目录下。

最后一步,网络搜索。

Pinctrl子节点的样式如下:

在设备树中添加GPIO信息:

先查看电路原理图确定所用引脚,再在设备树中指定:添加”[name]-gpios”属性,指定使用的是哪一个GPIO Controller里的哪一个引脚,还有其他Flag信息,比如GPIO_ACTIVE_LOW等。具体需要多少个cell来描述一个引脚,需要查看设备树中这个GPIO Controller节点里的“#gpio-cells”属性值,也可以查看内核文档。

示例如下:

总结起来的话,就是我们需要先把这个引脚复用成gpio模式,也就是先使用软件去配置出Pinctrl,然后在我们自己写的设备树里面,我们需要去写好pinctrl的clien端,然后接着我们还需要去使用gpio子系统,其实也是类似于去写好gpio子系统的clien端:

哦哦哦,在gpio子系统应该叫device

我们知道,我们编写的clien端会生成一个platform_device结构体,所以我们需要有一个compatible属性,去跟我们写的驱动程序去进行匹配:

编程示例:

a. 定义、注册一个platform_driver

b. 在它的probe函数里:

b.1 根据platform_device的设备树信息确定GPIO:gpiod_get

b.2 定义、注册一个file_operations结构体

b.3 在file_operarions中使用GPIO子系统的函数操作GPIO:

gpiod_direction_output、gpiod_set_value

好处:这些代码对所有的板子都是完全一样的!

跟设备树生成的platform_device结构体匹配成功后,就会去调用probe函数:

这里会去调用内核提供的gpiod_get函数去获取设备树中led-gpios=<...>的信息,然后就去获取节点中名为led的gpio子节点:

返回值是一个gpio描述结构体来着,后面我们讲gpio子系统相关的数据结构的时候会讲到

最后就是把file_operations结构体注册给内核,这里面有open close write函数

那么到这里,我们驱动程序就写完了,也算是初识gpio子系统了,下一篇我们来讲解他相关的数据结构,完结,撒花(doge.)

 

 

 

 

 

相关文章:

  • UE5 蓝图里的声音
  • 【区块链安全 | 第三十八篇】合约审计之获取私有数据(二)
  • CentOS 环境下 MySQL 数据库全部备份的操作指南
  • LeetCodeHot100-第三章:数学
  • DeepSeek-V3与DeepSeek-R1全面解析:从架构原理到实战应用
  • 雪花算法、md5加密
  • 罗技K860键盘
  • 【MCP】VSCode Cline配置MongoDB连接
  • 新的“估值锚点”:慧通测控人形(协作)机器人多任务并行
  • Java 大视界 -- 基于 Java 的大数据分布式缓存技术在电商高并发场景下的性能优化(181)
  • 从攻防演练到AI防护:网络安全服务厂商F5的全方位安全策略
  • 文档控件DevExpress Office File API v24.2亮点:不再支持非Windows系统
  • 供应链管理-职业规划:数字化供应链管理专家 / 供应链管理商业模式专家 / 供应链管理方案专家
  • nginx正向代理https
  • Java 大厂面试题 -- JVM 深度剖析:解锁大厂 Offe 的核心密钥
  • 0基础 | 硬件 | LM386芯片
  • 前端面试核心知识点整理:从 JavaScript 到 Vue 全解析
  • Mythical Beings:第八季即将回归,探索新的神话传承
  • 2021-10-26 C++完美身材
  • 记录学习的第二十三天
  • 网站建设 商城/什么是网站推广策略
  • 建设什么网站/怎么制作网页页面
  • 山西做网站多少钱/seo的工具有哪些
  • 凌河锦州网站建设/seo的内容有哪些
  • 做家政的在哪些网站推广/b2b自动发布信息软件
  • 上海人才网站官网入口/大量微信群推广代发广告