STM32MP157驱动开发——GPIO 和 和 Pinctrl 子系统的概念

news2024/11/25 16:35:36

文章目录

  • Pinctrl 子系统重要概念
    • 概述
    • 重要概念
      • pin controller:
      • client device:
    • 代码中怎么引用 pinctrl
  • GPIO 子系统重要概念
    • 概述
    • 在设备树中指定引脚
    • 在驱动代码中调用 GPIO 子系统
      • 头文件
      • 常用函数
      • 实例:

BSP工程师针对芯片的寄存器写Pinctrl子系统,驱动工程师使用Pinctrl 子系统

Pinctrl 子系统重要概念

概述

无论是哪种芯片,都有类似图的结构, IOMUX 认为是引脚功能选择器,有时候还需要配置引脚,比如上拉、下拉、开漏等等。前面提到的这些操作都可以交给Pinctrl 子系统完成。即把引脚的复用、配置抽出来,做成 Pinctrl 子系统,给 GPIO、I2C 等模块使用

在这里插入图片描述
ps:大多数的芯片,没有单独的 IOMUX 模块,即没有pinctl子系统去管理引脚的复用、配置等等,这些功能都在GPIO 模块内部实现的,所以在硬件上 GPIO 和 Pinctrl 是密切相关,在软件上它们的关系也非常密切

重要概念

涉及 2 个对象:pin controller、client device。

  • 前者提供服务:可以用它来复用引脚、配置引脚。
  • 后者使用服务:声明自己要使用哪些引脚的哪些功能,怎么配置它们。

pin controller:

在芯片手册里你找不到 pin controller,它是一个软件上的概念,你可以认为它对应 IOMUX──用来复用引脚,还可以配置引脚(比如上下拉电阻等)

注意,pin controller 和 GPIO Controller 不是一回事,前者控制的引脚可用于 GPIO 功能、I2C 功能;后者只是把引脚配置为输入、输出等简单的功能。即先用 pin controller 把引脚配置为 GPIO,再用 GPIO Controler 把引脚配置为输入或输出

client device:

Pinctrl 系统的客户,那就是使用 Pinctrl 系统的设备,使用引脚的设备。它在设备树里会被定义为一个节点,在节点里声明要用哪些引脚

关系图,右边device是设备树的一个节点,它是Pinctrl 系统的客户

在这里插入图片描述

首先是介绍一个概念引脚的状态:pin state

  • 对于一个“client device”来说,比如对于一个 UART 设备,它有多个“状态”:default、sleep 等,如默认状态下,UART 设备是工作的,那么所用的引脚就要复用为 UART功能。在休眠状态下,为了省电,可以把这些引脚复用为 GPIO 功能;或者直接把它们配置输出高电平。上图中,pinctrl-names 里定义了 2 种状态:default、sleep。

某种状态下对应的引脚配置有如下关联:

  • 第 0 种状态用到的引脚在 pinctrl-0 中定义,它是 state_0_node_a,位于 pincontroller 节点中。当这个设备处于 default 状态时,pinctrl 子系统会自动根据上述信息把所用引脚复用为 uart0 功能
  • 第 1 种状态用到的引脚在 pinctrl-1 中定义,它是 state_1_node_a,位于 pincontroller 节点中。当这这个设备处于 sleep 状态时,pinctrl 子系统会自动根据上述信息把所用引脚配置为高电平

左图 pin controller 节点中,是给client device 使用的。

  • 可以用来描述复用信息:哪组(group)引脚复用为哪个功能(function);
  • 可以用来描述配置信息:哪组(group)引脚配置为哪个设置功能(setting),比如上拉、下拉等。

注意:pin controller 节点的格式,没有统一的标准,每家芯片都不一样。甚至上面的 group、function关键字也不一定有,但是概念是有的。

代码中怎么引用 pinctrl

当设备切换状态时,对应的pinctrl 就会被调用。比如在 platform_device 和 platform_driver 的枚举过程中,流程如下:
在这里插入图片描述

当系统休眠时,也会去设置该设备 sleep 状态对应的引脚,不需要我们自己去调用代码。非要自己调用,也有函数:

devm_pinctrl_get_select_default(struct device *dev); // 使用"default" 状态的引脚
pinctrl_get_select(struct device *dev, const char *name); // 根据 name 选择某种状态的引脚
pinctrl_put(struct pinctrl *p); // 不再使用, 退出时调用

GPIO 子系统重要概念

概述

ps:大多数的芯片,没有单独的 IOMUX 模块,即没有pinctl子系统去管理引脚的复用、配置等等,这些功能都在GPIO 模块内部实现的,所以在硬件上 GPIO 和 Pinctrl 是密切相关,在软件上它们的关系也非常密切

在这里插入图片描述
通过 Pinctrl 子系统,先把所用引脚配置为 GPIO 功能,然后就可以根据设置引脚方向(输入还是输出)、读值──获得电平状态,
写值──输出高低电平。

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

  • 在设备树里指定 GPIO 引脚
  • 在驱动代码中:使用 GPIO 子系统的标准函数获得 GPIO、设置 GPIO 方向、读取/设置 GPIO 值。

这样的驱动代码,将是单板无关的,更换单板只需要修改设备树文件,指定GPIO引脚

在设备树中指定引脚

指定引脚就要先确定:它是哪组的?组里的哪一个?

在设备树中,“GPIO 组”就是一个 GPIO Controller,这通常都由芯片厂家设置好。我们要做的是找到它名字,一般都是厂家定
义好,在 xxx.dtsi 文件中:该节点中有关键属性gpio-controller#gpio-cells

  • “gpio-controller”表示这个节点是一个 GPIO Controller,它下面有很多引脚。
  • “#gpio-cells = <2>”表示这个控制器下每一个引脚要用 2 个 32 位的数(cell)来描述。普遍的用法是,用第 1 个 cell 来表示哪一个引脚,用第 2 个 cell 来表示有效电平:
GPIO_ACTIVE_HIGH : 高电平有效
GPIO_ACTIVE_LOW : 低电平有效

在自己的设备节点中使用属性"[<name>-]gpios",引用某个引脚,可以使用 gpios 属性,也可以使用 name-gpios 属性,示例如下:
在这里插入图片描述
name:描述符,在GPIO标准函数中作为参数
在这里插入图片描述

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

GPIO 子系统有两套接口:

  • 基于描述符的(descriptor-based)。函数都有前缀“gpiod_”,它使用 gpio_desc 结构体来表示一个引脚;
  • 老的(legacy)。函数都有前缀“gpio_”,它使用一个整数来表示一个引脚。

头文件

#include <linux/gpio/consumer.h> // descriptor-based#include <linux/gpio.h> // legacy

常用函数

descriptor-basedlegacy
获得 GPIO
gpiod_getgpio_request
gpiod_get_index
gpiod_get_arraygpio_request_array
devm_gpiod_get
devm_gpiod_get_index
devm_gpiod_get_array
设置方向
gpiod_direction_inputgpio_direction_input
gpiod_direction_outputgpio_direction_output
读值、写值
gpiod_get_valuegpio_get_value
gpiod_set_valuegpio_set_value
释放 GPIO
gpio_freegpio_free
gpiod_putgpio_free_array
gpiod_put_array
devm_gpiod_put
devm_gpiod_put_array

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

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

实例:

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

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

那么可以使用下面的函数获得引脚,并设置电平:

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 时会确定它的“basenumber”,那么这个控制器里的第 n 号引脚的号码就是:base number + n。但是如果硬件有变化、设备树有变化,这个 base number 并不能保证是固定的,应该查看 sysfs 虚拟文件系统中来确定 base number。

先在开发板的/sys/class/gpio 目录下,找到各个 gpiochipXXX 目录,每个目录对应一个GPIO控制器,然后进入某个 gpiochip 目录,查看文件 label 的内容,根据 label 的内容对比设备树,label 内容来自设备树,比如它的寄存器基地址。用来跟设备树(dtsi 文件)比较,就可以知道这对应哪一个 GPIO Controller。

例如,下图是在 stm32mp157 上运行的结果,通过对比设备树可知 gpiochip112对应 gpioH,所以 gpioH 这组引脚的基准引脚号就是 112,cat base 指令得到的也是基准引脚,cat ngpio得到的是这组引脚里面有多少个引脚
在这里插入图片描述
打开ubuntu,进入内核的设备树文件目录,cd /home/book/100ask_stm32mp157_pro-sdk/Linux-5.4/arch/arm64/boot/dts,打开设备树文件:vi stm32mp15xxx-100ask.dtsi,根据label值找到对应的那组寄存器

如图,如果想要操作PG2引脚,可知该引脚属于GPIOG那一组,通过设备树和控制器的对比,找到该组的引脚的基准引脚号,然后在该基准引脚号的基础上加2得到该引脚的引脚号
在这里插入图片描述

那么,我们可以在终端输入如下指令操作该引脚:

将引脚暴露在/sys/class/gpio 目录下

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

对于输出引脚,我们可以调用如下指令使其输入1

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/782556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录day25

216. 组合总和 III 这道题和昨天的相似的地方&#xff0c;但是也有不同的特点。这道题规定了数字范围是从1-9&#xff0c;并且一个组合中&#xff0c;不能出现同样的元素&#xff0c;比如说[1&#xff0c;2&#xff0c;2]这个就不可以&#xff0c;如果取过2之后&#xff0c;就只…

在Visual C++中进行类设计的通行做法(下)——类的运行

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来重新审视一下在Visual C中进行类设计的通行做法&#xff0c;这一篇帖子来看看在搭建好基本架构并调整好重复定义问题后&#xff0c;怎么个运行法。程序员新手会去看很多书&#xff0c;但是书中往往…

安装centos7 ping不通宿主机

1、安装Virbox虚拟机 2、安装centos 7镜像 主要有两点配置需要注意&#xff1a; A:磁盘分区 B:网络设置&#xff0c;今天的实验主要是卡在网络配置这里 网络设置&#xff0c;使用的是仅主机模式且是手动分配静态IP,要点说明 看宿主机所用的网络是哪个&#xff0c;查看window的…

OC时钟/BC时钟介绍、Windows/Linux环境查看时钟频率

一、OC时钟和BC时钟介绍 OC时钟和BC时钟是指计算机体系结构中的两种不同的时钟信号。 OC时钟&#xff08;Off-chip clock&#xff09;是指在计算机系统的主板或外部设备上产生的时钟信号&#xff0c;它通过总线传输到CPU中&#xff0c;控制着CPU与主板或外部设备之间的数据传…

Vue简介、生命周期、模版语法、条件渲染、列表渲染、style和class绑定

目录 简介 Vue基本渲染-插值和数据模型 MVVM 生命周期 模版语法 条件渲染 v-if ​编辑 v-show 列表渲染 key style绑定 class绑定 简介 Vue是一套用于构建用户界面的渐进式框架。与其他大型框架不同的是&#xff0c;Vue被设计为可以自底向上逐层应用。Vue的核心库只…

Docker 多主机部署:构建容器集群的最佳实践,助力高可用性与负载均衡

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

加载Ubuntu开发环境-iTOPRK3568开发板

配套视频&#xff1a; 安装虚拟机 ubuntu 系统&#xff1a;B站搜索北京迅为RK3568开发板 在 2.3 小节解压了迅为提供的 ubuntu 镜像&#xff0c;然后打开虚拟机&#xff0c;如下图所示&#xff1a; 点击上图中的红色框&#xff0c;选择在 2.3 小节中解压的 Ubuntu18 文件夹下…

oracle单个用户最大连接数限制

项目经理反馈&#xff0c;现场已做了单个用户的最大连接数2000的限制&#xff0c;但数据库还是报无法连接&#xff0c;故障用户的连接数已3800多了。 查看日志报错如下 2023-07-20T13:07:57.79465308:00 Process m000 submission failed with error 20 Process m000 submiss…

Matlab对FS32K144编程--串口通讯

1、配置系统运行周期10ms 2、设置串口通讯通道为通道1&#xff0c;波特率设为9600 3、设置串口发送-100ms发送一次 4、设置接收中断接收数据 5、编译下载&#xff0c;串口发送消息

go使用gin结合jwt做登录功能

1、安装gin go get -u github.com/gin-gonic/gin 2、安装session go get github.com/gin-contrib/sessions 3、安装JWT鉴权 go get "github.com/golang-jwt/jwt/v4" 4、创建一个jwt的工具文件 package utilsimport ("errors""github.com/golan…

共享汽车管理系统nodejs+vue

语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode 前端nodejsvueelementui, 共享汽车管理系统的系统管理员可以管理用户&#xff0c;可以对用户信息修改删除以及查询操作。具体界面的展…

JQ-3 jQuery事件处理(click和on的区别、事件冒泡、事件对象、事件委托、小案例); jQuery动画(常见动画函数、动画队列、小案例)

目录 1_ jQuery事件处理1.1_认识事件&#xff08;Event&#xff09;1.2_click和on的区别1.3_ jQuery的事件冒泡1.4_jQuery的事件对象( Event Object)1.5_ jQuery的事件委托&#xff08;event delegation&#xff09;1.6_ jQuery常见的事件1.7_小案例 2_ jQuery 动画2.1_介绍2.2…

【力扣每日一题】2023.7.23 接雨水

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 接雨水是力扣里非常经典的一道单调栈的题目&#xff0c;使用单调栈的做法就是从左到右将高度依次入栈&#xff0c;保持栈内从栈顶…

《零基础入门学习Python》第060讲:论一只爬虫的自我修养8:正则表达式4

有了前面几节课的准备&#xff0c;我们这一次终于可以真刀真枪的干一场大的了&#xff0c;但是呢&#xff0c;在进行实战之前&#xff0c;我们还要讲讲正则表达式的实用方法和扩展语法&#xff0c;然后再来实战&#xff0c;大家多把持一会啊。 我们先来翻一下文档&#xff1a;…

【iOS安全】iOS 14.3越狱教程

iOS 14.3越狱教程 通过MacBook越狱iPhone 8 方案&#xff1a;AltStore unc0ver 实验环境 手机&#xff1a;iPhone 8 OS版本&#xff1a;iOS 14.3 型号号码&#xff1a;A1863 PC型号&#xff1a;MacBook 实验步骤 Mac安装AltServer https://altstore.io/ 解压后启动 …

【ES】---ES的聚合(aggregations)

目录 一、前言1、聚合分类2、聚合的实现方式二、RestAPI--bucket聚合案例11、按照类型分bucket2、按照(String)时间分bucket三、RestAPI-- metric聚合案例11、metric指标统计四、RestAPI-- pipeline聚合案例1一、前言 聚合是对文档数据的统计、分析、计算。 注意:参与聚合的字…

Clion开发STM32之W5500系列(NTP服务封装)

概述 在w5500基础库中进行封装&#xff0c;获取服务端的时间&#xff0c;来校准本地时间。本次使用的方案是通过ntp获取时间定时器更新保证时间准确。 NTP封装 头文件 /*******************************************************************************Copyright (c) [sc…

【动态规划part03】| 343.整数拆分、96.不同的二叉搜索树

目录 &#x1f388;LeetCode343.整数拆分 &#x1f388; LeetCode96.不同的二叉搜索树 &#x1f388;LeetCode343.整数拆分 链接&#xff1a;343.整数拆分 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些…

S32K1xx SDK(版本:S32_SDK_S32K1xx_RTM_4.0.3 )详细介绍

前言 在学习一款MCU之前&#xff0c;一般我的习惯是先下载官方提供的SDK包进行学习。然后学习了解SDK提供的资源、框架、以及各目录结构文件作用等&#xff0c;下面边学边做笔记记录。 S32K1系列SDK我们可以到下面的NXP官网去获取&#xff1a; https://www.nxp.com.cn/design…

数据库备份还原-mysqldump、mydumper、xtrabackup、压缩

数据库备份&#xff0c;数据库为school&#xff0c;素材如下 一、创建student和score表 CREATE TABLE student ( id INT(10) NOT NULL UNIQUE PRIMARY KEY , name VARCHAR(20) NOT NULL , sex VARCHAR(4) , birth YEAR, department VARCHAR(20) , address VARC…