利用Linux GPIO子系统设置一个引脚复用为gpio,设置为输出模式,并且读取引脚的值

在Linux中,通过GPIO子系统设置引脚复用、配置输出模式并读取值需分两步:pinctrl配置物理引脚功能 + GPIO子系统逻辑操作。以下是详细实现:


一、内核驱动实现

1. 设备树配置(pinctrl)

// arch/arm/boot/dts/your-board.dts
my_device {
    compatible = "mycompany,mydevice";
    pinctrl-names = "default";
    pinctrl-0 = <&my_gpio_pin>;
    gpios = <&gpio1 17 GPIO_ACTIVE_HIGH>;  // 引用gpiochip1的17号引脚
    status = "okay";
};

// 定义GPIO引脚配置
my_gpio_pin: my_gpio_pin {
    pins = "GPIO17";
    function = "gpio";    // 复用为GPIO功能
    bias-disable;         // 禁用上拉/下拉(可选)
};
2. 内核模块代码

#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_gpio.h>

static int gpio_num;

static int __init my_gpio_init(void) {
    int ret;
    struct device_node *np;

    // 从设备树获取GPIO编号
    np = of_find_compatible_node(NULL, NULL, "mycompany,mydevice");
    if (!np) {
        printk(KERN_ERR "Failed to find device node\n");
        return -ENODEV;
    }

    gpio_num = of_get_gpio(np, 0);  // 获取第一个GPIO
    if (!gpio_is_valid(gpio_num)) {
        printk(KERN_ERR "Invalid GPIO\n");
        of_node_put(np);
        return -EINVAL;
    }

    // 申请GPIO
    ret = gpio_request(gpio_num, "my_gpio");
    if (ret) {
        printk(KERN_ERR "Failed to request GPIO%d\n", gpio_num);
        of_node_put(np);
        return ret;
    }

    // 设置为输出模式(初始值0)
    ret = gpio_direction_output(gpio_num, 0);
    if (ret) {
        printk(KERN_ERR "Failed to set direction\n");
        gpio_free(gpio_num);
        of_node_put(np);
        return ret;
    }

    // 读取当前值(输出模式返回设置的电平)
    int value = gpio_get_value(gpio_num);
    printk(KERN_INFO "GPIO%d output value: %d\n", gpio_num, value);

    of_node_put(np);
    return 0;
}

static void __exit my_gpio_exit(void) {
    gpio_set_value(gpio_num, 0);  // 确保退出时为低电平
    gpio_free(gpio_num);
}

module_init(my_gpio_init);
module_exit(my_gpio_exit);
MODULE_LICENSE("GPL");

二、用户空间实现(libgpiod)

1. 安装库
sudo apt-get install libgpiod-dev
2. C程序示例

#include <gpiod.h>
#include <stdio.h>
#include <stdlib.h>

int main() {
    struct gpiod_chip *chip;
    struct gpiod_line *line;
    int value;

    // 打开GPIO芯片(如gpiochip0)
    chip = gpiod_chip_open_by_name("gpiochip0");
    if (!chip) {
        perror("Failed to open GPIO chip");
        return 1;
    }

    // 获取GPIO线(17号引脚)
    line = gpiod_chip_get_line(chip, 17);
    if (!line) {
        perror("Failed to get GPIO line");
        gpiod_chip_close(chip);
        return 1;
    }

    // 申请输出模式,初始值0
    int ret = gpiod_line_request_output(line, "user_gpio", 0);
    if (ret) {
        perror("Failed to request output");
        gpiod_line_release(line);
        gpiod_chip_close(chip);
        return 1;
    }

    // 读取当前值(返回设置的输出值)
    value = gpiod_line_get_value(line);
    printf("GPIO17 output value: %d\n", value);

    // 清理资源
    gpiod_line_release(line);
    gpiod_chip_close(chip);
    return 0;
}

三、关键说明

  1. 引脚复用
    • 通过pinctrl在设备树中配置引脚为GPIO功能(function = "gpio")。
    • 确保驱动或用户空间程序引用的GPIO编号与硬件匹配。
  2. 输出模式与读取
    • gpio_direction_output()gpiod_line_request_output()设置输出模式。
    • 读取操作(gpio_get_value()gpiod_line_get_value())返回的是输出寄存器的值,而非实际引脚电平。如需检测外部电平,需临时切换为输入模式:

      gpio_direction_input(gpio_num);  // 内核空间
      // 或
      gpiod_line_set_direction(line, GPIOD_LINE_DIRECTION_INPUT);  // 用户空间
  3. 权限与兼容性
    • 用户空间程序需root权限或配置udev规则。
    • GPIO编号可能因平台而异(如树莓派使用BCM编号,需通过gpiod工具转换)。

四、验证步骤

  1. 编译并加载内核模块

    make -C /lib/modules/$(uname -r)/build M=$PWD modules
    sudo insmod my_gpio.ko
    dmesg | tail  # 查看日志
  2. 运行用户空间程序

    sudo ./gpio_read
  3. 使用工具验证

    gpiodetect # 查看GPIO控制器
    gpioinfo gpiochip0 # 查看GPIO17详细信息

通过上述步骤,您可以在Linux系统中安全地配置GPIO引脚并读取其值。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值