LinuxGPIO子系统1(基于Linux6.6)---整体框架
一、概述
GPIO(General Purpose Input/Output,通用输入输出)是嵌入式系统中常用的硬件接口,用于与外部设备进行交互。在Linux操作系统中,GPIO是用于管理和控制这些引脚的一种机制。Linux的GPIO子系统为开发者提供了对GPIO引脚的访问接口,并能够通过文件系统接口、sysfs接口、设备驱动接口等多种方式对GPIO进行控制。
1. GPIO的基本概念
GPIO引脚通常是集成电路(如微控制器、单板计算机、SoC等)上提供的、可以配置为输入或输出的数字引脚。GPIO的基本功能包括:
- 输入模式:从外部设备读取信号(例如按钮、开关等)。
- 输出模式:向外部设备发送信号(例如点亮LED灯、控制继电器等)。
2. Linux中的GPIO子系统
在Linux中,GPIO子系统为每个支持GPIO功能的硬件平台提供一个统一的接口。这个接口主要通过设备树(Device Tree)、sysfs、IOCTL等方式进行访问。
3. GPIO的访问方式
设备树(Device Tree)
设备树是Linux内核中用于描述硬件配置的方式,GPIO的定义通常也通过设备树进行配置。通过设备树,内核可以识别GPIO引脚及其功能,进而进行正确的配置。
设备树中通常会定义GPIO的相关信息,例如引脚号、功能、输入输出模式等。
Sysfs接口
在Linux中,GPIO引脚的控制可以通过 sysfs 文件系统访问。每个GPIO引脚会被映射到 /sys/class/gpio/
目录下,通过文件操作的方式进行读写。
IOCTL接口
IOCTL(输入输出控制)接口是一种通过系统调用进行设备控制的方式。对于GPIO,IOCTL接口通常在驱动程序中使用,提供比sysfs更灵活且高效的控制方式。开发者可以通过编写内核驱动来实现对GPIO的高级控制,适用于性能要求较高的场景。
GPIO驱动
GPIO驱动是内核中的设备驱动,通常用于提供硬件抽象层,以便用户空间程序可以通过标准接口(如sysfs、IOCTL等)访问GPIO。GPIO驱动通常会处理硬件的初始化、配置以及输入输出操作。
二、GPIO相关硬差异
每个目标板(target board)上的GPIO引脚配置确实可能存在差异。不同的硬件平台、芯片、开发板甚至不同的硬件版本,其GPIO的引脚数量、功能、映射方式以及支持的特性都有可能不同。下面列举一些典型的差异:
1. GPIO引脚数量和分布
不同的目标板可能支持不同数量的GPIO引脚。一个开发板上可能有几十个GPIO引脚,而另一个开发板上则可能只有少数几个。常见的差异包括:
- 引脚数量:不同的硬件平台(如树莓派、BeagleBone、NVIDIA Jetson等)可能会提供不同数量的GPIO引脚。某些开发板可能有几十个GPIO引脚,而另一些则可能只有几个。
- 引脚位置:即使是相同数量的GPIO引脚,位置和排列顺序也会有所不同。开发板上GPIO引脚的物理排列通常是根据硬件设计来决定的,不同厂商的板子会有不同的排布。
2. GPIO引脚的复用功能
许多现代芯片支持GPIO引脚的复用(Pin Multiplexing),即同一引脚可以根据配置担任不同的功能(如SPI、I2C、UART、PWM等)。不同的目标板可以将同一个GPIO引脚配置为不同的功能。典型的复用功能包括:
- SPI、I2C、UART:很多开发板上的GPIO引脚不仅仅支持普通的输入输出,还可以配置为串行通信接口的信号线(例如SCK、MOSI、MISO、SDA、SCL等)。
- PWM输出:某些GPIO引脚支持PWM(脉冲宽度调制)输出,用于控制马达、灯光等设备。
- 外部中断:GPIO引脚还可以配置为触发外部中断,响应硬件事件。
例如,在树莓派中,某些GPIO引脚同时支持I2C、SPI、UART等多种功能,但这些功能需要通过软件配置来启用。
3. GPIO引脚的电压级别
不同目标板上的GPIO引脚可能支持不同的电压级别。例如:
- 3.3V与5V:一些开发板上的GPIO引脚工作电压为3.3V(如树莓派),而另一些则可能是5V(如Arduino)。这就意味着,在设计电路时需要特别注意电压兼容性,以免损坏GPIO引脚。
- 输入电压范围:不同平台的GPIO引脚支持的输入电压范围不同,某些平台可能支持宽电压范围,而有些则可能更为敏感。
4. GPIO的配置方式
每个目标板的GPIO配置方式也不同。常见的配置方式包括:
- 设备树(Device Tree):在Linux内核中,设备树是一种用来描述硬件平台资源的结构,包括GPIO引脚的功能和配置。在不同的目标板上,设备树的内容可能有所不同。
- 内核驱动配置:某些硬件平台提供特定的内核驱动,用于支持GPIO的初始化和配置。开发者需要根据目标板的文档或驱动来进行正确的GPIO配置。
5. GPIO控制接口
不同的开发板可能提供不同的GPIO控制接口来访问GPIO引脚。常见的控制接口包括:
- sysfs接口:如上文所述,sysfs接口通常适用于简单的GPIO操作(如控制输入输出)。不过,sysfs接口在性能和灵活性上有一定的限制,因此对于更高效的操作,有些平台可能不再推荐使用。
- /dev/gpio控制接口:某些平台提供特定的设备文件(如
/dev/gpio
),用于直接与GPIO引脚进行交互。这通常需要特定的驱动或内核模块。 - IOCTL接口:高级操作通常通过IOCTL接口来完成,可以为GPIO引脚提供更细粒度的控制。
- 用户空间库:如WiringPi(树莓派)、pigpio等库,可以简化GPIO的控制,提供跨平台的GPIO接口。
6. GPIO电流限制
每个目标板的GPIO引脚的电流承载能力也有所不同。一些开发板的GPIO引脚能够驱动较大的负载(如大功率LED或小型继电器),而另一些可能只能驱动微小电流。这对于设计电路时需要特别注意,可能需要添加外部电路(如晶体管或驱动器)来增加电流容量。
7. GPIO与外设的兼容性
一些开发板的GPIO引脚专为某些外设而设计,这意味着它们可能已经有硬件或软件的优化。常见的例子包括:
- 树莓派的GPIO引脚:树莓派的GPIO引脚支持多种外设,包括I2C、SPI、PWM等,并且提供了简单易用的接口。
- Arduino的GPIO引脚:Arduino的GPIO引脚通常被用于控制简单的电子设备,并且支持外部扩展模块的连接。
8. 硬件限制
不同硬件平台(如ARM架构、x86架构、Raspberry Pi、BeagleBone等)可能会对GPIO的实现方式有所不同。例如:
- 树莓派:树莓派使用Broadcom的SoC,其GPIO引脚的控制和使用方法通过官方的Raspberry Pi库和设备树进行管理。
- BeagleBone:BeagleBone使用TI的Sitara处理器,GPIO的访问和配置与树莓派有所不同,提供了更多的硬件控制能力,适合更复杂的嵌入式应用。
三、硬件功能分类
GPIO控制器的硬件描述中,寄存器的功能通常可以分为以下三个主要类别:
1. 配置寄存器 (Configuration Registers)
这些寄存器用于配置每个GPIO引脚的工作模式、功能和属性。这些配置包括设置输入输出模式、复用功能、上拉下拉电阻等。常见的配置寄存器功能有:
- 方向控制:确定GPIO引脚是输入(Input)还是输出(Output)。例如,通过设置特定位,可以将一个GPIO引脚配置为输入模式(读取电平)或输出模式(驱动电平)。
- 功能选择:许多GPIO引脚支持复用功能(Pin Multiplexing),即同一个引脚可以根据配置承担不同的功能,如UART、SPI、I2C、PWM等。配置寄存器控制这些功能的选择。
- 上拉/下拉电阻控制:GPIO引脚通常支持上拉电阻或下拉电阻的启用/禁用,用来确保在没有外部驱动时,输入引脚的电平处于已知状态。配置寄存器允许设置这些电阻的类型或启用状态。
2. 数据寄存器 (Data Registers)
数据寄存器用于读取或写入GPIO引脚的实际数据(电平状态)。常见的数据寄存器功能有:
- 数据输出寄存器:在输出模式下,控制GPIO引脚的电平状态(高或低)。通过写入数据寄存器,可以驱动引脚输出高电平或低电平。
- 数据输入寄存器:在输入模式下,读取GPIO引脚的电平状态。通过读取数据寄存器,系统可以获取外部设备或传感器的电平状态。
- 数据寄存器位操作:对于单个引脚,可以通过位操作设置或读取引脚的状态,而不影响其他引脚。例如,控制GPIO引脚0的输出而不影响GPIO引脚1、2等。
3. 状态/中断寄存器 (Status/Interrupt Registers)
这些寄存器用于控制和查询GPIO的中断功能,以及监控GPIO引脚的状态。常见的状态和中断寄存器功能有:
- 中断使能寄存器:允许启用或禁用特定GPIO引脚的中断功能。当GPIO引脚的状态发生变化时(例如,从低电平变为高电平),可以通过中断触发CPU响应。这些寄存器用来设置哪些引脚需要触发中断。
- 中断状态寄存器:显示哪些GPIO引脚发生了中断,允许操作系统或微控制器处理这些中断信号。例如,可以查询哪个GPIO引脚的电平发生了变化,并决定如何响应。
- 中断触发类型:这些寄存器还允许配置中断触发的类型,如上升沿触发、下降沿触发或电平触发。
- 状态寄存器:用于查看GPIO引脚的当前状态。例如,读取一个状态寄存器,可以获取某个GPIO引脚是否处于高电平或低电平。
四、如何通过软件抽象来掩盖硬件差异
Linux kernel中的GPIO subsystem则用三个软件模块来对应上面三类硬件功能:
(1)pin control subsystem。驱动pin controller硬件的软件子系统。
(2)GPIO subsystem。驱动GPIO controller硬件的软件子系统。
(3)GPIO interrupt chip driver。这个模块是作为一个interrupt subsystem中的一个底层硬件驱动模块存在的。本文主要描述前两个软件模块,具体GPIO interrupt chip driver以及interrupt subsystem请参考本站其他相关文档。
4.1、pin control subsystem 模块图
下图描述了pin control subsystem的模块图:
底层的pin controller driver是硬件相关的模组,初始化的时候会向pin control core模块注册pin control设备(通过pinctrl_register这个bootom level interface)。pin control core模块是一个硬件无关模块,它抽象了所有pin controller的硬件特性,仅仅从用户(各个driver就是pin control subsystem的用户)角度给出了top level的接口函数,这样,各个driver不需要关注pin controller的底层硬件相关的内容。
4.2、GPIO subsystem 模块图
下图描述了GPIO subsystem的模块图:
上面这个软件框架图和pin control subsystem是一样的,其软件抽象的思想也是一样的,当然其内部具体的实现不一样的。