首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >RK3576开发板GPIO驱动入门教程,基于触觉智能开发板教学

RK3576开发板GPIO驱动入门教程,基于触觉智能开发板教学

原创
作者头像
Industio_触觉智能
发布2026-07-03 14:57:23
发布2026-07-03 14:57:23
20
举报
文章被收录于专栏:Linux嵌入式Linux嵌入式

触觉智能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)。

从设备树可以看到:

代码语言:txt
复制
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):

代码语言:javascript
复制
// 定义 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 引脚配置

代码语言:javascript
复制
&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

总线保持器

低功耗场景

实际设备树配置示例

代码语言:javascript
复制
&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 操作

代码语言:javascript
复制
#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 中断处理

代码语言:javascript
复制
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)

代码语言:javascript
复制
# 导出 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 状态

代码语言:javascript
复制
# 查看 GPIO 占用情况
cat /sys/kernel/debug/gpio
# 查看 pinmux 配置
cat /sys/kernel/debug/pinctrl/pinctrl-rockchip/pinmux-pins
# 查看 pin 状态
cat /sys/kernel/debug/pinctrl/pinctrl-rockchip/pin

5.2 常用调试命令

代码语言:javascript
复制
# 查看中断统计
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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档