GPIO 驱动与控制
本文档介绍 RK3588 GPIO 控制器在 Linux 6.1 内核中的配置方法,以及如何用 sysfs(内核把设备状态映射成 /sys 目录下普通文件的接口,读写文件就等于操作硬件)来调试 GPIO。
适用范围: RK3588 Linux 6.1 Debian 12 / Ubuntu 22.04 系统,C-3588LQ V1.0 + SHIMETAPI-M5-R2A V1.0 底板。
1. 概念基础
1.1 GPIO 是什么
GPIO(General Purpose Input/Output,通用输入输出)是嵌入式系统中最基本的外设接口:把引脚配置成输出,就能通过寄存器控制它的电平高低;配置成输入,就能读回引脚当前的电平。
RK3588 共有 5 组 GPIO 控制器(GPIO0~GPIO4),每组 32 个引脚,合计 160 个 GPIO。所有 GPIO 均已从 LGA 封装引出,都可以用作中断引脚。
GPIO 编号计算公式:
组号 × 32 + 组内偏移(A 组 0-7、B 组 8-15、C 组 16-23、D 组 24-31)。例如GPIO4_A3 = 4 × 32 + 3 = 131。
1.2 主要应用
| 用途 | 说明 |
|---|---|
| LED 控制 | GPIO 输出高低电平 |
| 按键检测 | GPIO 输入模式 + 中断 |
| 外设使能 | 控制外部芯片的 EN / RST |
| 中断信号 | 配置为中断模式触发外部事件 |
| 协议模拟 | 软件模拟 I2C、SPI、1-Wire 等时序 |
1.3 内核子系统
RK3588 的 GPIO 由 Pin-Ctrl(引脚控制,负责复用、上下拉、驱动能力等引脚属性)子系统统一管理,相关的寄存器有:
- 方向寄存器(DDR):输入 / 输出
- 数据寄存器(DR):读 / 写电平
- 复用寄存器(IOMUX):GPIO / I2C / UART 等功能切换
- 驱动能力(DS):输出电流大小
- 上下拉(PU/PD):内部电阻
2. 准备工作
2.1 硬件清单
| 组件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| 主控板 | C-3588LQ 核心板 + SHIMETAPI-M5-R2A 底板 | 1 | |
| 调试串口线 | USB 转 TTL(3.3V) | 1 | 波特率 1500000 |
| LED 模块 | 5mm 发光二极管 + 330Ω 限流电阻 | 1 | 或面包板搭建 |
| 杜邦线 | 母对母 | 若干 | |
| 按键模块(可选) | 轻触按键 | 1 | 用于输入检测 |
2.2 引脚连接示例
以 GPIO4_A3(底板原理图 USB Host 使能引脚)为例:
| 主控板引脚 | 外设引脚 | 功能说明 |
|---|---|---|
| GPIO4_A3(Sheet 3/21) | LED 正极(经 330Ω 电阻) | GPIO 输出控制 LED |
| GND | LED 负极 | 共地 |
| GPIO4_A3(Sheet 3/21) | 按键一端 | GPIO 输入检测 |
| GND | 按键另一端 | 共地 |
动手接线前先确认 GPIO 电压域(3.3V 或 1.8V),接错可能损坏引脚。C-3588LQ 核心板具体电压域信息参考核心板规格书。
3. 软件确认
3.1 内核配置
RK3588 GPIO 驱动在 SDK 中默认启用:
CONFIG_GPIOLIB=y
CONFIG_GPIO_GENERIC=y
CONFIG_PINCTRL=y
CONFIG_PINCTRL_RK3588=y
CONFIG_OF_GPIO=y
CONFIG_PINCTRL_RK3588是 RK3588 专用 Pin-Ctrl 驱动(与 RK3568 的CONFIG_PINCTRL_RK3568不同)。
想确认开发板上的实际配置,执行下面的命令,能看到前面几项都是 y 就说明驱动已编进内核:
zcat /proc/config.gz | grep -E 'GPIOLIB|PINCTRL_RK3588|OF_GPIO'3.2 GPIO 控制器基地址(设备树)
设备树(Device Tree,内核用来描述「板子上有哪些硬件、怎么接」的数据结构)里为 RK3588 的 5 个 GPIO 控制器各建了一个节点,基地址如下:
| 控制器 | 基地址 | 备注 |
|---|---|---|
| GPIO0 | 0xfdd60000 | 来源 RTC 域 |
| GPIO1 | 0xfec20000 | PMU 域 |
| GPIO2 | 0x38810000 | 复用域 |
| GPIO3 | 0xfe740000 | |
| GPIO4 | 0xfe740000 | 与 GPIO3 不同寄存器组 |
设备树示例:
gpio0: gpio@fdd60000 {
compatible = "rockchip,gpio-bank";
reg = <0x0 0xfdd60000 0x0 0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_GPIO0>;
gpio-controller;
#gpio-cells = <2>;
gpio-ranges = <&pinctrl 0 0 32>;
interrupt-controller;
#interrupt-cells = <2>;
};4. 设备端 GPIO 操作
4.1 查看 GPIO 控制器
先看看系统里有哪些 GPIO 控制器可用:
ls /sys/class/gpio/实机输出如下:
export
gpiochip0
gpiochip128
gpiochip256
gpiochip32
gpiochip509
gpiochip64
gpiochip96
unexport本机有 7 个 gpiochip(编号 0/32/64/96/128/256/509),每个 gpiochip 对应一个控制器。想知道每个编号是谁,用
cat /sys/class/gpio/gpiochip*/label查看。
4.2 导出与控制 GPIO(示例:GPIO4_A3,编号 131)
sysfs 的用法是:先把想操作的 GPIO「导出」,系统会生成 /sys/class/gpio/gpio131/ 目录,之后对目录里的文件读写即可:
# 导出 GPIO(一次性,需先计算编号)
echo 131 > /sys/class/gpio/export
# 设置为输出
echo out > /sys/class/gpio/gpio131/direction
# 输出高 / 低电平
echo 1 > /sys/class/gpio/gpio131/value
echo 0 > /sys/class/gpio/gpio131/value
# 设置为输入
echo in > /sys/class/gpio/gpio131/direction
# 读取电平(会得到 0 或 1)
cat /sys/class/gpio/gpio131/value
# 释放
echo 131 > /sys/class/gpio/unexport注意:内核默认开启严格 GPIO 管控。若
echo ... > export提示busy,说明该引脚被驱动占用,需先在设备树将对应节点status = "disabled"。
4.3 通过 debugfs 查看全局 GPIO 状态
debugfs 是内核专门为调试准备的文件系统,通常挂在 /sys/kernel/debug,能一次看到所有引脚的占用情况:
# 查看所有 GPIO 控制器的 pin 状态
cat /sys/kernel/debug/gpio输出示例(节选):
gpiochip0: GPIOs 0-31, parent: platform/fdd60000.gpio, GPIO0:
gpio-0 ( |led-green ) out hi
gpio-3 ( |usb-host-pwr-en ) out hi4.4 通过 pinctrl 查看引脚复用状态
# 查看 pin 复用关系
cat /sys/kernel/debug/pinctrl/fdd60000.pinctrl/pinmux-pins
# 查看 pin 空闲 / 占用状态
cat /sys/kernel/debug/pinctrl/fdd60000.pinctrl/pins5. 设备树中使用 GPIO
设备树中通过 gpios 属性引用:
my_device {
compatible = "my,device";
// GPIO4_A3(group=4, offset=3),高电平有效
enable-gpios = <&gpio4 3 GPIO_ACTIVE_HIGH>;
// GPIO0_B6(group=0, offset=14),低电平有效
reset-gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
};| 字段 | 含义 |
|---|---|
&gpio4 | GPIO4 控制器引用 |
3 | group 内偏移(0-31) |
GPIO_ACTIVE_HIGH / LOW | 有效电平 |
修改设备树要在 PC 端完成:
./build.sh kernel重新编译并烧录。开发板端无法直接改 GPIO 设备树。
6. 代码解读
6.1 内核驱动注册
// drivers/pinctrl/pinctrl-rk3588.c(简化)
static struct rockchip_pin_bank rk3588_pin_banks[] = {
RK3588_PIN_BANK_FLAGS(0, 32, "gpio0"),
RK3588_PIN_BANK_FLAGS(1, 32, "gpio1"),
RK3588_PIN_BANK_FLAGS(2, 32, "gpio2"),
RK3588_PIN_BANK_FLAGS(3, 32, "gpio3"),
RK3588_PIN_BANK_FLAGS(4, 32, "gpio4"),
};
static struct rockchip_pinctrl_info rk3588_pinctrl_info = {
.pin_banks = rk3588_pin_banks,
.nr_banks = ARRAY_SIZE(rk3588_pin_banks),
};6.2 sysfs 操作调用链
用户空间: echo 131 > /sys/class/gpio/export
→ gpio_export() /* 内核 GPIO core */
→ gpio_request_one()
→ gpio_direction_output()
→ rockchip_gpio_direction_output() /* Rockchip 平台实现 */
→ 设置 GPIO 寄存器 DDR / DR7. 故障排除
7.1 GPIO 被占用
现象:echo ... > export 提示 busy。
先用下面的命令查出是谁占用了引脚:
cat /sys/kernel/debug/gpio
cat /sys/kernel/debug/pinctrl/fdd60000.pinctrl/pinmux-pins解决:编辑设备树,把占用该引脚的设备节点 status = "disabled" 后重新编译烧录。
7.2 编号计算错误
现象:控制了错误的 GPIO 引脚。
先核对编号,再操作:
cat /sys/kernel/debug/gpio # 查 gpio-编号 对应的 label或直接读 cat /sys/class/gpio/gpiochipN/label 确认。
7.3 电压域不匹配
现象:输出电平不正确,或外设无响应。
解决:确认 GPIO 电压域(1.8V / 3.3V / 1.8V+3.3V)与外设匹配。错误连电可能烧毁引脚或外设。具体电压域见核心板规格书。
