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

【北京迅为】《STM32MP157开发板嵌入式开发指南》- 第五十四章 Pinctrl 子系统和 GPIO 子系统

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7+单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板+底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐用,可满足高速信号环境下使用。共240PIN,CPU功能全部引出:底板扩展接口丰富底板板载4G接口(选配)、千兆以太网、WIFI蓝牙模块HDMI、CAN、RS485、LVDS接口、温湿度传感器(选配)光环境传感器、六轴传感器、2路USB OTG、3路串口,CAMERA接口、ADC电位器、SPDIF、SDIO接口等


第五十四章 Pinctrl 子系统和 GPIO 子系统

本章导读

在学习了设备树之后,如果还按照裸板开发的方式配置寄存器来控制IO的方式太过于原始,Linux内核提供了pinctrl子系统和gpio子系统用于GPIO驱动,当然pinctrl子系统负责的就不仅仅是GPIO的驱动了而是所有pin脚的配置。pinctrl子系统是随着设备树的加入而加入的,依赖于设备树。GPIO子系统在之前的内核中也是存在的,但是pinctrl子系统的加入GPIO子系统也是有很大的改变,之前的GPIO子系统需要芯片厂商提供的mach文件,而加入设备树后,GPIO子系统使用设备树来实现。

54.1章节讲解了pinctrl子系统。

54.2章节讲解了GPIO子系统。

本章内容对应视频讲解链接(在线观看):

pinctl和gpio子系统 ( https://www.bilibili.com/video/BV1Vy4y1B7ta?p=29

 

54.1 Pinctrl子系统 

大多数SOC的PIN都是支持复用的,此外我们还需要配置 pin 的电气特性,比如上/下拉、速度、驱动能力等等。传统的配置 pin 的方式就是直接操作相应的寄存器,但是这种配置方式比较繁琐、而且容易出问题(比如 pin 功能冲突)。pinctrl 子系统就是为了解决这个问题而引入的,pinctrl 子系统主要工作内容如下

  • 获取设备树中pin信息,管理系统中所有的可以控制的pin,在系统初始化的时候,枚举所有可以控制的pin,并标识这些pin。
  • 根据获得到的pin信息来设置pin的复用功能,对于SOC而言,其引脚除了配置成普通的GPIO之外,若干个引脚还可以组成一个pin group,形成特定的功能。
  • 根据获得到的pin信息来设置pin的电气特性,比如上下拉、速度、驱动能力。

对于我们使用者来说,只需要在设备树里面设置好某个pin的相关属性即可,其他的初始化工作均由pinctrl子系统来完成,pinctrl 子系统源码目录drivers/pinctrl。

不同soc厂家的pin controller的节点是不一样的,但是这些节点里都是把某些引脚复用成某些功能。如

NXP的pinctrl子系统如下所示:

 三星pinctrl子系统如下所示:

 瑞星微pinctrl子系统如下所示:

ST的pinctrl子系统如下所示: 

不同soc厂家的pin controller的节点里面的属性都可以通过内核源码/Documentation/devicetree/bindings下的txt文档查看。

下面我们来看一下 pinctrl 子系统在 stm32mp157的设备树中是如何实现并使用的。

首先来到linux内核目录下,如图所示:

 

然后我们使用以下命令进入stm32mp151.dtsi文件中,找到 pinctrl: pin-controller@50002000节点,如下图所示:

vim arch/arm/boot/dts/stm32mp151.dtsi

部分截图如下图所示:

 pinctrl: pin-controller@50002000 {#address-cells = <1>;#size-cells = <1>;compatible = "st,stm32mp157-pinctrl";ranges = <0 0x50002000 0xa400>;interrupt-parent = <&exti>;st,syscfg = <&exti 0x60 0xff>;hwlocks = <&hsem 0 1>;pins-are-numbered;

#address-cells 属性值为 1 和#size-cells 属性值为 1第 1818 行,

ranges 属性表示 STM32MP1 的 GPIO 相关寄存器起始地址,0x50002000 表示起始地址,0xa400 表示寄存器地址范围。

interrupt-parent 属性值为“&exti”,父中断为 exti。

然后在该内容的下方可以找到如下内容:

  gpioa: gpio@50002000 {gpio-controller;#gpio-cells = <2>;interrupt-controller;#interrupt-cells = <2>;reg = <0x0 0x400>;clocks = <&rcc GPIOA>;st,bank-name = "GPIOA";status = "disabled";};..........................................................

这些是关于gpio相关的,我们在稍后的GPIO子系统相关小节中会进行说明。绑定文档 Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml 描述了如何在设备树中设置 STM32 的 PIN 信息,截取出的一段例程如下

pinctrl@60020000 {usart1_pins_a: usart1-0 {pins1 {pinmux = <STM32_PINMUX('A', 9, AF7)>;bias-disable;drive-push-pull;slew-rate = <0>;};pins2 {pinmux = <STM32_PINMUX('A', 10, AF7)>;bias-disable;};};};

以上内容对usart1-0节点进行定义, usart1_pins_a是usart1-0的别名,然后对两个引脚使用 pinmux属性进行分别的功能复用。其中pinmux属性的宏定义在include/dt-bindings/pinctrl/stm32-pinfunc.h 文件中,具体内容如下

/* define Pins number*/
#define PIN_NO(port, line)      (((port) - 'A') * 0x10 + (line))
#define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode))

port:表示用那一组 GPIO。

line:表示这组 GPIO 的第几个引脚。

mode:表示当前引脚要做那种复用功能

pinmux = <STM32_PINMUX('A', 9, AF7)>;

在这里以pins1的 pinmux属性为例子,进行讲解。首先前面的A代表GPIOA组别,而9代表该组别的第9个io口,之后的AF7为对应的复用功能,我们打开iTOP-STM32MP157开发板\iTOP-STM32MP157开发板光盘资料\20220223\01_开发板硬件资料\官方数据手册\STM32MP157A&D 数据手册.pdf ,然后我们来到4 Pinouts, pin description and alternate functions小节,即引脚输出、引脚描述和功能复用,找到PA9相关的功能描述如下图所示:

在找到PA9功能之后,然后找到对应的AF7,可以发现对应的复用功能为USART1_TX。

而如何对我们的pinctrl子系统进行调用呢,我们将我们在st,stm32-pinctrl.yaml例子中没列举的内容进行展示,内容如下

    usart1 {pinctrl-0 = <&usart1_pins_a>;pinctrl-names = "default";};

我们只需要将对应的节点内容,添加到&pinctrl 节点下,即可,这里我们在内核移植章节中进行了演示。

接下来我们进行gpio子系统的讲解。

54.2 GPIO子系统

当我们使用pinctrl子系统将引脚的复用关系设置为GPIO以后,我们就可以使用GPIO子系统来操作我们的GPIO了,Linux 内核提供了 pinctrl 子系统和 gpio 子系统用于 GPIO 驱动。当然 pinctrl 子系统负责的就不仅仅是 GPIO 的驱动了而是所有 pin 脚的配置。pinctrl 子系统是随着设备树的加入而加入的,依赖于设备树。GPIO 子系统在之前的内核中也是存在的,但是 pinctrl 子系统的加入 GPIO 子系统也是有很大的改变。为什么他会发生非常大的变化呢?之前我们控制一个GPIO可以直接来操作我们的寄存器,还有一种方法是使用SOC厂家实现的配置函数,例如三星的配置函数为s3c_gpio_cfgpin等,这样带来的问题就是各家有各家的接口函数与实现方式,不但内核的代码复用率低而且开发者很难记住这么多的函数,如果要使用多种平台的话背函数都是很麻烦的,所以在引入设备树后对GPIO子系统进行了大的改造,使用设备树来实现并提供统一的接口。通过 GPIO 子系统功能要实现:

  • 引脚功能的配置(设置为 GPIO,特殊功能,GPIO 的方向,设置为中断等)
  • 实现软硬件的分离(分离出硬件差异,有厂商提供的底层支持;软件分层。驱动只需要调用接口 API 即可操作 GPIO)
  • iommu 内存管理(直接调用宏即可操作 GPIO)

经过 GPIO 子系统,我们可以通过如下的方式来配置 GPIO

下面具体讲解一下这几个函数的用法:

1 gpio_request 函数

函数

int gpio_request(unsigned gpio, const char *label)

gpio

要申请的 gpio 标号,使用 of_get_named_gpio 函数从设备树获取指定 GPIO 属性信息,此函数会返回这个 GPIO 的标号。

label

给 gpio 设置个名字

返回值

0,申请成功;其他值,申请失败

功能

gpio_request 函数用于申请一个 GPIO 管脚

2 gpio_free函数 

函数

void gpio_free(unsigned gpio)

gpio

要释放的 gpio 标号

返回值

功能

如果不使用某个 GPIO 了,那么就可以调用 gpio_free 函数进行释放。

3 gpio_direction_input 函数

函数

int gpio_direction_input(unsigned gpio)

gpio

要设置为输入的 GPIO 标号

返回值

设置成功返回0;设置失败返回负值

功能

此函数用于设置某个 GPIO 为输入

4 gpio_direction_output 函数 

函数

int gpio_direction_output(unsigned gpio, int value)

gpio

要设置为输出的 GPIO 标号

value

GPIO 默认输出值

返回值

设置成功返回0;设置失败返回负值

功能

此函数用于设置某个 GPIO 为输出,并且设置默认输出值

5 gpio_get_value函数 

函数

int __gpio_get_value(unsigned gpio)

gpio

要获取的 GPIO 标号

返回值

成功返回GPIO值,失败返回负值

功能

此函数用于获取某个 GPIO 的值(0 或 1)

 6 gpio_set_value函数

函数

void __gpio_set_value(unsigned gpio, int value)

gpio

要设置的 GPIO 标号

value

要设置的值

返回值

功能

此函数用于设置某个 GPIO 的值

 7 of_get_named_gpio 函数

函数

int of_get_named_gpio(struct device_node *np,const char *propname,int index)

np

设备节点

propname

包含要获取 GPIO 信息的属性名

index

因为一个属性里面可能包含多个 GPIO,此参数指定要获取哪个 GPIO的编号,如果只有一个 GPIO 信息的话此参数为 0

返回值

成功返回到的 GPIO 编号,失败返回一个负数

功能

此函数获取 GPIO 编号,因为 Linux 内核中关于 GPIO 的 API 函数都要使用 GPIO 编号,此函数会将设备树中类似<&gpio1 3 GPIO_ACTIVE_LOW>的属性信息转换为对应的 GPIO 编号

 


http://www.mrgr.cn/news/53907.html

相关文章:

  • JAVA二手交易发布闲置好物回收系统小程序源码
  • 1.前提配置 关防火墙 关selinux
  • 炒股看分时图,这些知识你知道吗?
  • AI大模型是否有助于攻克重大疾病?
  • 智能安全配电装置在老旧建筑防火中的应用
  • smbms(2)
  • D-PAD论文解析
  • 虚拟机nacos部署报错数据源未设置问题解决方案
  • 逻辑之舞:C++ 内存分配与释放,在程序的舞台上,演绎着资源的分配与回收
  • 解决SolidWorks装配体无法更改透明度问题
  • 【数据结构】栈
  • 数仓建设:如何设计数据治理考评规则?
  • 类和对象(中)后面部分
  • 【note】GNN
  • Dropout为何能防止过拟合?dropout和BN 在前向传播和方向传播阶段的区别?
  • 「图::连通」详解并查集并实现对应的功能 / 手撕数据结构(C++)
  • 挑战自闭症儿童康复:探索有效治疗方法
  • C#从零开始学习(类型和引用)(4)
  • 解锁C++多态的魔力:灵活与高效的编码艺术(下)
  • 每日一题——第一百一十七题
  • 【部署篇】rabbitmq-01介绍
  • 【openGauss】OPENGAUSS/POSTGRESQL 中float类型到int类型的隐式转换
  • 直播带货APP开发指南:基于多商户商城系统源码的方案实战
  • vscode 预览markdown 文件
  • 竹壳天气时钟(三)TFT屏幕显示中文
  • 量价关系总结