Linux GPIO 驱动开发实战:从入门到可部署

在嵌入式开发中,GPIO(通用输入输出口)作为与外设通信的关键接口,是驱动开发的基础能力之一。本文将带你从零开始编写一个 Linux 平台下的 GPIO 驱动模块,包括代码、Makefile 和测试方法,确保你可以实战部署。





一、环境准备



  • 开发板:树莓派 / ARM Cortex-A 系列 / 开发板(含 GPIO 控制器)
  • 内核版本:5.x 或以上(确保开启 GPIO 框架)
  • 编译工具链:交叉编译工具(如 arm-linux-gnueabihf-gcc)
  • 系统接口:使用 Linux 内核自带的 GPIO 子系统(gpiolib)






二、Linux GPIO 子系统简介



Linux 内核通过 gpiolib 框架提供统一接口,使得不同 SoC 的 GPIO 控制器能统一管理。



常见接口:



  • gpio_request():申请 GPIO 引脚
  • gpio_direction_input() / gpio_direction_output():设置引脚方向
  • gpio_set_value() / gpio_get_value():读写 GPIO 值
  • gpio_free():释放引脚






三、编写一个简单的 GPIO 控制驱动




1 驱动功能目标



  • 控制 GPIO 输出电平
  • 通过 /dev/gpio_demo 设备文件控制 GPIO 开关
  • 使用 echo 1 > /dev/gpio_demo 开启,echo 0 > /dev/gpio_demo 关闭






2驱动代码:

gpio_demo.c


#include <linux/module.h>

#include <linux/fs.h>

#include <linux/gpio.h>

#include <linux/uaccess.h>

#include <linux/cdev.h>


#define GPIO_DEMO_PIN 17 // 使用 GPIO17(树莓派)

#define DEVICE_NAME "gpio_demo"


static int major;

static struct class *gpio_class;

static struct cdev gpio_cdev;


static ssize_t gpio_write(struct file *file, const char __user *buf, size_t len, loff_t *off)

{

char val;


if (copy_from_user(&val, buf, 1))

return -EFAULT;


gpio_set_value(GPIO_DEMO_PIN, (val == '1') ? 1 : 0);

return len;

}


static int gpio_open(struct inode *inode, struct file *file)

{

return 0;

}


static int gpio_release(struct inode *inode, struct file *file)

{

return 0;

}


static struct file_operations fops = {

.owner = THIS_MODULE,

.write = gpio_write,

.open = gpio_open,

.release = gpio_release,

};


static int __init gpio_demo_init(void)

{

int ret;

dev_t dev;


// 分配主设备号

ret = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME);

if (ret)

return ret;

major = MAJOR(dev);


// 初始化字符设备

cdev_init(&gpio_cdev, &fops);

gpio_cdev.owner = THIS_MODULE;

cdev_add(&gpio_cdev, dev, 1);


// 创建设备节点

gpio_class = class_create(THIS_MODULE, "gpio_demo_class");

device_create(gpio_class, NULL, dev, NULL, DEVICE_NAME);


// 申请 GPIO 并设为输出

gpio_request(GPIO_DEMO_PIN, "gpio_demo");

gpio_direction_output(GPIO_DEMO_PIN, 0);


printk(KERN_INFO "GPIO demo module loaded\n");

return 0;

}


static void __exit gpio_demo_exit(void)

{

dev_t dev = MKDEV(major, 0);


gpio_set_value(GPIO_DEMO_PIN, 0);

gpio_free(GPIO_DEMO_PIN);


device_destroy(gpio_class, dev);

class_destroy(gpio_class);

cdev_del(&gpio_cdev);

unregister_chrdev_region(dev, 1);


printk(KERN_INFO "GPIO demo module unloaded\n");

}


module_init(gpio_demo_init);

module_exit(gpio_demo_exit);


MODULE_LICENSE("GPL");

MODULE_AUTHOR("OpenAI");

MODULE_DESCRIPTION("Simple GPIO Control Driver");





Makefile 文件


obj-m += gpio_demo.o


KDIR := /lib/modules/$(shell uname -r)/build

PWD := $(shell pwd)


all:

make -C $(KDIR) M=$(PWD) modules


clean:

make -C $(KDIR) M=$(PWD) clean




四、驱动安装与测试




1 编译驱动


make


2 加载驱动模块


sudo insmod gpio_demo.ko


3 查看设备节点


ls /dev/gpio_demo


4 控制 GPIO


echo 1 | sudo tee /dev/gpio_demo # 设置高电平

echo 0 | sudo tee /dev/gpio_demo # 设置低电平


5 卸载驱动模块


sudo rmmod gpio_demo





五、验证逻辑



使用万用表或 LED 连接 GPIO17 引脚:


  • echo 1:LED 亮
  • echo 0:LED 灭



确保实物控制与代码一致。





六、实战建议



  • 驱动中可集成中断响应(gpio_to_irq() + request_irq())
  • 可结合 DTS(设备树)进行更灵活的管理
  • 可对接平台驱动模型(platform_driver)






七、参考文档



  • Linux Kernel Documentation: Documentation/gpio/
  • LDD3(Linux Device Drivers 第三版)
  • 官方驱动源码:drivers/gpio/






总结

本文展示了在 Linux 下开发一个简单 GPIO 控制驱动的完整过程,从源码、Makefile 到测试与部署,适合初学者或嵌入式项目开发者快速入门 GPIO 驱动实战。如果你想进一步掌握更复杂的中断、设备树、平台驱动集成,可在本项目基础上扩展!