GPIO

简介

GPIO, 全称 General-Purpose Input/Output(通用输入输出),是一种软件运行期间能够动态配置和控制的通用引脚。 所有的 GPIO 在上电后的初始状态都是输入模式,可以通过软件设为上拉或下拉,也可以设置为中断脚,驱动强度都是可编程的,其核心是填充 GPIO bank 的方法和参数,并调用 gpiochip_add 注册到内核中。

GPIO引脚计算

LKD3566 有 5 组 GPIO bank:GPIO0~GPIO4,每组又以 A0~A7, B0~B7, C0~C7, D0~D7 作为编号区分,常用以下公式计算引脚:

GPIO pin脚计算公式:pin = bank * 32 + number

GPIO 小组编号计算公式:number = group * 8 + X

下面演示GPIO4_D5 pin脚计算方法: bank = 4;      //GPIO4_D5 => 4, bank ∈ [0,4]

group = 3;      //GPIO4_D5 => 3, group ∈ {(A=0), (B=1), (C=2), (D=3)}

X = 5;       //GPIO4_D5 => 5, X ∈ [0,7]

number = group * 8 + X = 3 * 8 + 5 = 29

pin = bank*32 + number= 4 * 32 + 29 = 157;

GPIO 编号 引脚 编号 引脚 编号 引脚 编号 引脚
GPIO0 A0 0 B0 8 C0 16 D0 24
A1 1 B1 9 C1 17 D1 25
A2 2 B2 10 C2 18 D2 26
A3 3 B3 11 C3 19 D3 27
A4 4 B4 12 C4 20 D4 28
A5 5 B5 13 C5 21 D5 29
A6 6 B6 14 C6 22 D6 30
A7 7 B7 15 C7 23 D7 31
GPIO1 A0 32 B0 40 C0 48 D0 56
A1 33 B1 41 C1 49 D1 57
A2 34 B2 42 C2 50 D2 58
A3 35 B3 43 C3 51 D3 59
A4 36 B4 44 C4 52 D4 60
A5 37 B5 45 C5 53 D5 61
A6 38 B6 46 C6 54 D6 62
A7 39 B7 47 C7 55 D7 63
GPIO2 A0 64 B0 72 C0 80 D0 88
A1 65 B1 73 C1 81 D1 89
A2 66 B2 74 C2 82 D2 90
A3 67 B3 75 C3 83 D3 91
A4 68 B4 76 C4 84 D4 92
A5 69 B5 77 C5 85 D5 93
A6 70 B6 78 C6 86 D6 94
A7 71 B7 79 C7 87 D7 95
GPIO3 A0 96 B0 104 C0 112 D0 120
A1 97 B1 105 C1 113 D1 121
A2 98 B2 106 C2 114 D2 122
A3 99 B3 107 C3 115 D3 123
A4 100 B4 108 C4 116 D4 124
A5 101 B5 109 C5 117 D5 125
A6 102 B6 110 C6 118 D6 126
A7 103 B7 111 C7 119 D7 127
GPIO4 A0 128 B0 136 C0 144 D0 152
A1 129 B1 137 C1 145 D1 153
A2 130 B2 138 C2 146 D2 154
A3 131 B3 139 C3 147 D3 155
A4 132 B4 140 C4 148 D4 156
A5 133 B5 141 C5 149 D5 157
A6 134 B6 142 C6 150 D6 158
A7 135 B7 143 C7 151 D7 159

GPIO4_D5 对应的设备树属性描述为:<&gpio4 29 IRQ_TYPE_EDGE_RISING>,由kernel/include/dt-bindings/pinctrl/rockchip.h的宏定义可知,也可以将GPIO4_D5描述为<&gpio4 RK_PD5 IRQ_TYPE_EDGE_RISING>。

#define RK_PA0		0
#define RK_PA1		1
#define RK_PA2		2
#define RK_PA3		3
#define RK_PA4		4
#define RK_PA5		5
#define RK_PA6		6
#define RK_PA7		7
#define RK_PB0		8
#define RK_PB1		9
#define RK_PB2		10
#define RK_PB3		11
......

GPIO4_D5 可能被其他功能占用,以下仅是举例说明。当引脚没有被其它外设复用时, 我们可以通过export导出该引脚去使用

:/ # ls /sys/class/gpio/
export     gpiochip128  gpiochip32   gpiochip64  unexport
gpiochip0  gpiochip255  gpiochip500  gpiochip96
:/ # echo 157 > /sys/class/gpio/export
:/ # ls /sys/class/gpio/
export   gpiochip0    gpiochip255  gpiochip500  gpiochip96
gpio157  gpiochip128  gpiochip32   gpiochip64   unexport
:/ # ls /sys/class/gpio/gpio157
active_low  device  direction  edge  power  subsystem  uevent  value
:/ # cat /sys/class/gpio/gpio157/direction
in
:/ # cat /sys/class/gpio/gpio157/value
0

FAQs

Q1: 如何将 PIN 的 MUX 值切换为一般的 GPIO?

A1: 当使用 GPIO request 时候,会将该 PIN 的 MUX 值强制切换为 GPIO,所以使用该 PIN 脚为 GPIO 功能的时候确保该 PIN 脚没有被其他模块所使用。

Q2: 为什么我用 IO 指令读出来的值都是 0x00000000?

A2: 如果用 IO 命令读某个 GPIO 的寄存器,读出来的值异常,如 0x00000000 或 0xffffffff 等,请确认该 GPIO 的 CLK 是不是被关了,GPIO 的 CLK 是由 CRU 控制,可以通过读取 datasheet 下面 CRU_CLKGATE_CON* 寄存器来查到 CLK 是否开启,如果没有开启可以用 io 命令设置对应的寄存器,从而打开对应的 CLK,打开 CLK 之后应该就可以读到正确的寄存器值了。

Q3: 测量到 PIN 脚的电压不对应该怎么查?

A3: 测量该 PIN 脚的电压不对时,如果排除了外部因素,可以确认下该 PIN 所在的 IO 电压源是否正确,以及 IO-Domain 配置是否正确。

Q4: gpio_set_value() 与 gpio_direction_output() 有什么区别?

A4: 如果使用该 GPIO 时,不会动态的切换输入输出,建议在开始时就设置好 GPIO 输出方向,后面拉高拉低时使用 gpio_set_value() 接口,而不建议使用 gpio_direction_output(), 因为 gpio_direction_output 接口里面有 mutex 锁,对中断上下文调用会有错误异常,且相比 gpio_set_value,gpio_direction_output 所做事情更多,浪费。