
触觉智能RK3576开发板Purple Pi OH2板载双20Pin的GPIO排针(兼容树莓派),提供了丰富的拓展空间。
本文基于Purple Pi OH2为大家讲解GPIO概念、原理、代码示例、调试方法灯。
一、GPIO 基本概念
1.1 什么是 GPIO?
GPIO(General Purpose Input/Output,通用输入输出)是嵌入式系统中最基础的外设接口。每个 GPIO 引脚可以被配置为:
•输入模式:读取外部信号(如按键、传感器)
•输出模式:控制外部设备(如 LED、继电器)
•中断模式:检测边沿变化触发中断
1.2 RK3576 GPIO 资源
RK3576 芯片共有 5 组 GPIO(GPIO0~GPIO4),每组包含 32 个引脚(A0-A7, B0-B7, C0-C7, D0-D7)。
从设备树可以看到:
gpio0 = &gpio0;
gpio1 = &gpio1;
gpio2 = &gpio2;
gpio3 = &gpio3;
gpio4 = &gpio4;1.3 GPIO 命名规则
RK 平台使用 GPIOx_PYz 的命名方式:
•x: GPIO 组号(0-4)
•Y: 端口(A、B、C、D)
•z: 引脚号(0-7)
例如:GPIO0_PB4 表示 GPIO0 组的 B 端口第 4 号引脚
二、GPIO 工作原理
2.1 内部结构

2.2 工作模式
模式 | 说明 | 典型应用 |
|---|---|---|
输入模式 | 高阻态,读取外部电平 | 按键检测 |
输出模式 | 驱动外部电路 | LED 控制 |
中断模式 | 边沿 / 电平触发 | 事件通知 |
复用模式 | 作为其他功能(UART/I2C 等) | 引脚复用 |
三、GPIO 设备树配置
3.1 在设备树中添加 GPIO 节点
编辑设备树文件(如ido-evb7609-v1a.dtsi):
// 定义 LED 设备节点
/ {
leds: leds {
status = "okay";
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&leds_gpio>;
work_led: work {
gpios = <&gpio4 RK_PC7 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
hub_rst {
gpios = <&gpio4 RK_PD0 GPIO_ACTIVE_HIGH>;
default-state="on";
};
};
// USB 电源控制
cgpio:cgpios{
status = "okay";
compatible = "cust,cgpio";
usb_pwr { //SD-card、USB-A、Wi-Fi
gpios = <&gpio0 RK_PB6 GPIO_ACTIVE_HIGH>;
init-status = <1>;
};
};
};3.2 pinctrl 引脚配置
&pinctrl {
// LED 引脚配置
led_pins: led-pins {
rockchip,pins =
<0 RK_PB4 RK_FUNC_GPIO &pcfg_pull_none>;
};
// 按键引脚配置
key_pins: key-pins {
rockchip,pins =
<0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
};
};3.3 GPIO 上下拉配置详解
RK3576 的 GPIO 支持多种上下拉配置,通过 rockchip,pins 属性的最后一个参数指定。
上下拉配置类型

配置 | 设备树值 | 说明 | 典型应用 |
|---|---|---|---|
上拉 | &pcfg_pull_up | 引脚默认上拉到高电平 | 按键输入、I2C SDA/SCL |
下拉 | &pcfg_pull_down | 引脚默认下拉到低电平 | 复位信号、使能信号 |
无上下拉 | &pcfg_pull_none | 浮空输入,无上拉电阻 | LED 输出、GPIO 输出 |
保持 | &pcfg_pull_bus | 总线保持器 | 低功耗场景 |
实际设备树配置示例
&pinctrl {
/* LED 引脚 - 无上拉(输出模式不需要) */
leds_gpio: leds-gpio {
rockchip,pins =
<4 RK_PC7 RK_FUNC_GPIO &pcfg_pull_none>, /* work_led */
<4 RK_PD0 RK_FUNC_GPIO &pcfg_pull_none>; /* hub_rst */
};
/* USB 电源 - 无上拉 */
usb_pwr: usb-pwr {
rockchip,pins =
<0 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
};
/* 耳机检测 - 上拉(按键检测) */
hp_det: hp-det {
rockchip,pins =
<3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
};
/* WiFi 唤醒 - 下拉 */
wifi_host_wake_irq: wifi-host-wake-irq {
rockchip,pins =
<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_down>;
};
/* 按键输入 - 上拉 */
adc_keys_pins: adc-keys-pins {
rockchip,pins =
<0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
};
/* I2C 引脚 - 上拉(I2C 标准需要) */
i2c2m0_xfer: i2c2m0-xfer {
rockchip,pins =
<1 RK_PB3 9 &pcfg_pull_up>, /* i2c2_sda_m0 */
<1 RK_PB4 9 &pcfg_pull_up>; /* i2c2_scl_m0 */
};
};上下拉选择原则

注意事项
1.输出模式:通常使用&pcfg_pull_none,因为 GPIO 输出是推挽驱动
2.输入按键:必须使用&pcfg_pull_up,确保按键未按下时读到高电平
3.I2C 总线:必须使用&pcfg_pull_up,I2C 是开漏输出需要上拉电阻
4.中断引脚:根据触发方式选择,上升沿触发用下拉,下降沿触发用上拉
四、GPIO 驱动代码示例
4.1 内核空间 GPIO 操作
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
struct my_gpio_dev {
int gpio_led;
int gpio_key;
};
static int my_gpio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct my_gpio_dev *priv;
int ret;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
/* 从设备树获取 GPIO 描述符 */
priv->gpio_led = of_get_named_gpio(np, "led-gpios", 0);
if (!gpio_is_valid(priv->gpio_led)) {
dev_err(&pdev->dev, "Failed to get LED GPIO\n");
return priv->gpio_led;
}
/* 申请并配置 GPIO */
ret = devm_gpio_request_one(&pdev->dev, priv->gpio_led,
GPIOF_OUT_INIT_LOW, "led");
if (ret) {
dev_err(&pdev->dev, "Failed to request LED GPIO\n");
return ret;
}
/* 设置 GPIO 输出高电平(点亮 LED) */
gpio_set_value(priv->gpio_led, 1);
/* 按键 GPIO 配置为输入 */
priv->gpio_key = of_get_named_gpio(np, "key-gpios", 0);
ret = devm_gpio_request_one(&pdev->dev, priv->gpio_key,
GPIOF_IN, "key");
if (ret)
return ret;
/* 读取 GPIO 输入值 */
int val = gpio_get_value(priv->gpio_key);
dev_info(&pdev->dev, "Key value: %d\n", val);
return 0;
}
static const struct of_device_id my_gpio_of_match[] = {
{ .compatible = "mycompany,my-gpio-device", },
{ }
};
static struct platform_driver my_gpio_driver = {
.probe = my_gpio_probe,
.driver = {
.name = "my-gpio",
.of_match_table = my_gpio_of_match,
},
};4.2 GPIO 中断处理
static irqreturn_t gpio_irq_handler(int irq, void *dev_id)
{
struct my_gpio_dev *priv = dev_id;
/* 消抖处理 */
priv->key_pressed = !priv->key_pressed;
return IRQ_HANDLED;
}
static int setup_gpio_irq(struct platform_device *pdev,
struct my_gpio_dev *priv)
{
int irq, ret;
/* 将 GPIO 转换为 IRQ */
irq = gpio_to_irq(priv->gpio_key);
if (irq < 0)
return irq;
/* 申请中断 */
ret = devm_request_irq(&pdev->dev, irq, gpio_irq_handler,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
"gpio-key", priv);
if (ret)
dev_err(&pdev->dev, "Failed to request IRQ\n");
return ret;
}4.3 用户空间 GPIO 操作(sysfs)
# 导出 GPIO(以 GPIO4_PA2 为例)
# 计算 GPIO 编号:4 * 32 + 1 * 8 + 2 = 138
echo 138 > /sys/class/gpio/export
# 设置方向为输出
echo out > /sys/class/gpio/gpio138/direction
# 设置输出高电平(点亮 LED)
echo 1 > /sys/class/gpio/gpio138/value
# 设置输出低电平(熄灭 LED)
echo 0 > /sys/class/gpio/gpio138/value
# 释放 GPIO
echo 138 > /sys/class/gpio/unexport五、调试方法
5.1 查看 GPIO 状态
# 查看 GPIO 占用情况
cat /sys/kernel/debug/gpio
# 查看 pinmux 配置
cat /sys/kernel/debug/pinctrl/pinctrl-rockchip/pinmux-pins
# 查看 pin 状态
cat /sys/kernel/debug/pinctrl/pinctrl-rockchip/pin5.2 常用调试命令
# 查看中断统计
cat /proc/interrupts | grep gpio
# 使用 devmem 直接读取寄存器
devmem 0xFE740000 # GPIO0 基地址
# 使用 io 命令(如有)
io -r -4 0xFE740000六、常见问题
6.1 GPIO 申请失败
•检查 GPIO 是否已被其他驱动占用
•查看设备树中的status = "disabled" 是否未使能
6.2 GPIO 输出无效
•确认 pinctrl 配置正确
•检查 IO 电压域是否正常
•确认 GPIO 未被复用为其他功能
6.3 GPIO 中断不触发
•检查中断触发方式(上升沿 / 下降沿 / 双边沿 / 高电平 / 低电平)
•确认 GPIO 已正确配置为输入
•检查中断是否被正确映射
七、进阶学习
1.GPIO 子系统:学习 Linux 的 GPIO 子系统架构
2.GPIO 字符设备:使用/dev/gpiochip0 接口
3.libgpiod:用户空间 GPIO 库
4.Device Tree:深入理解设备树语法和绑定文档
参考文档

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。