Linux GPIO驱动实例及GPIOLib简介

26.1 前言

Linux2.6.35 之后就有了gpiolib,其作用为对所有GPIO进行统一管理,避免多个驱动控制一个IO所带来的混乱,需要在编译内核的时候选上支持gpiolib选项。本文是基于Linux gpiolib库初试GPIO驱动编程的学习记录,供学习参考。

 

26.2 混杂设备

混杂设备主设备号为10,次设备号:0-255共256个设备。minor=MISC_DYNAMIC_MINOR时,表示动态分配次设备号,我们不用管,其会自动分配空闲的次设备号。

 

26.3 驱动ictol参数构建

在编写ioctl函数时,我们需要构建一些命令用以执行不同操作。_IOWR(幻数,基数,变量),_IOW(幻数,基数,变量), _IOR(幻数,基数,变量), _IO (幻数,基数)。

(1)_IOWR:构建读写命令

(2)_IOW:构建带参数的写命令

(3)_IOR:构建读命令

(4)_IO:构建不带读写的普通命令

示例:

#define IGPIO_IOCTL_MAGIC        0XF12
#define IGPIO_IOCTL_RESET        _IO(IGPIO_IOCTL_MAGIC, 0x0)
#define IGPIO_IOCTL_SET          _IO(IGPIO_IOCTL_MAGIC, 0x1)

#define IGPIO_IOCSET            _IOW(IGPIO_IOCTL_MAGIC, 0, 变量)
#define IGPIO_IOCGET            _IOR(IGPIO_IOCTL_MAGIC, 1, 变量)

 

26.4 GPIOLib常用函数

使用gpio接口需要包含#include <linux/gpio.h> ,在驱动中使用延时函数mdelay,需要包含#include <linux/delay.h>文件

gpio_request(gpioNum,gpioName)

申请一个空闲的GPIO

gpio_free(gpioNum)

释放申请到的GPIO

gpio_direction_input(gpioNum)

设置GPIO为输入模式

gpio_direction_output(gpioNum,value)

设置GPIO为输出模式+值

gpio_get_value(gpioNum)

获取GPIO的电平值

gpio_set_value(gpioNum,value)

设置GPIO输出电平值

gpio_to_irq(gpioNum)

返回GPIO对应的中断号

irq_to_gpio(irq)

返回irq对应的GPIO号

 

26.5 GPIOLib实例编程

gpiodrv.c

#include <linux/init.h>  
#include <linux/module.h>  
#include <asm/uaccess.h>  
#include <linux/fs.h>  
#include <linux/errno.h>  
#include <linux/gpio.h>  
#include <linux/sys_config.h>  
#include <linux/miscdevice.h>  
  
  
#define IGPIO_DEVICE_NAME       "igpioDrv"  
#define IGPIO_IOCTL_MAGIC       0XF12  
#define IGPIO_IOCTL_RESET       _IO(IGPIO_IOCTL_MAGIC, 0x0)  
#define IGPIO_IOCTL_SET         _IO(IGPIO_IOCTL_MAGIC, 0x1)  
static DEFINE_MUTEX(igpio_ioctlmutex);          /* 声明并初始化互斥锁 */  
static int gpioNumer = 0;                       /*用以保存申请到的io*/  
  
static int igpio_open(struct inode *node, struct file *filp)  
{  
    return 0;  
}  
  
static long igpio_ioctl(struct file *filp, unsigned int cmd, unsigned long gpioNum)  
{  
    int nRet = 0;  
  
    printk(KERN_EMERG "cmd= %d,gpioNum= %d\n",cmd,gpioNum);  
    mutex_lock(&igpio_ioctlmutex);  
    if(gpioNumer != gpioNum)  
    {     
        nRet = gpio_request(gpioNum, NULL);  
        if(nRet){  
            printk(KERN_EMERG "%d gpio_request failed\n", gpioNum);  
            nRet = -EINVAL;  
            goto iExit;  
        }  
  
        gpio_free(gpioNumer); //如果申请了新的那就释放掉旧的  
        gpioNumer = gpioNum;  
    }  
      
    switch(cmd){  
        case IGPIO_IOCTL_RESET:  
            gpio_direction_output(gpioNumer,0x00);  
            break;  
        case IGPIO_IOCTL_SET:  
            gpio_direction_output(gpioNumer,0x01);  
            break;  
        default:  
        nRet = -EINVAL;  
    }  
      
iExit:  
  
    mutex_unlock(&igpio_ioctlmutex);  
    return nRet;  
}  
  
static const struct file_operations gpio_fops ={  
    .owner  = THIS_MODULE,  
    .open   = igpio_open,  
    .unlocked_ioctl = igpio_ioctl,  
};  
  
static struct miscdevice gpioMiscDevSt ={  
    .minor = MISC_DYNAMIC_MINOR,  
    .name  = IGPIO_DEVICE_NAME,  
    .fops  = &gpio_fops,  
};  
  
static int __init gpioDrv_init(void)  
{  
    int nRet = 0;  
    /*注册设备*/  
    nRet = misc_register(&gpioMiscDevSt);  
    printk(KERN_EMERG "%s misc_deregister nRet=%d \n",__FUNCTION__,nRet);  
  
    return nRet;  
}  
  
static void __exit gpioDrv_exit(void)  
{  
    int nRet = -1;  
  
    gpio_free(gpioNumer);  
    nRet = misc_deregister(&gpioMiscDevSt);  
    if(nRet<0)  
        printk(KERN_EMERG "%s misc_deregister failed\n",__FUNCTION__);  
}  
  
module_init(gpioDrv_init);  
module_exit(gpioDrv_exit);  
MODULE_LICENSE("GPL");  

iotest.c

#include <stdio.h>  
#include <unistd.h>  
#include <sys/ioctl.h>  
#include <fcntl.h>  
#include <string.h>  
  
#define IGPIO_IOCTL_MAGIC       0XF12  
#define IGPIO_IOCTL_RESET       _IO(IGPIO_IOCTL_MAGIC, 0x0)  
#define IGPIO_IOCTL_SET         _IO(IGPIO_IOCTL_MAGIC, 0x1)  
  
int main(int argc, char **argv)  
{  
    unsigned int id = 0;  
    unsigned int value = 0;  
    int fd = -1;  
    int ret;  
  
    if(argc <4){  
        printf("Usage:./app -s 194 0\n");  
        return -1;  
    }  
  
    sscanf(argv[2], "%d", &id);  
    sscanf(argv[3], "%x", &value);  
  
    fd = open("/dev/igpioDrv", O_RDWR, 0);  
    if (fd < 0) {  
        printf("open fail\n");  
        return -1;  
    }  
  
    if (0 == strncmp(argv[1], "-s", strlen(argv[1])))  
    {  
        if(value == 0)  
            ret = ioctl(fd, IGPIO_IOCTL_RESET, id);  
        else   
            ret = ioctl(fd, IGPIO_IOCTL_SET, id);  
        if (ret < 0) {  
            perror("ioctl fail\n");  
        }  
    }  
  
    close(fd);  
    return 0;  
}  

Makefile

ifneq ($(KERNELRELEASE),)  # linux内核源代码中的顶层makefile中有定义
	obj-m += gpiolibdrv.o
else
	ARCH = arm
	CROSS_COMPILER = $(CROSS_COMPILE)
	CC = $(CROSS_COMPILER)gcc
	LD = $(CROSS_COMPILER)ld

CURRENT_PATH := $(shell pwd)

KERNEL_PATH := ../../kernel/linux-3.10

CFLAGS+= -O2 -Wall
all:
	make -C $(KERNEL_PATH) M=$(CURRENT_PATH) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILER) modules

clean:
	rm -rf .tmp_versions
	rm -rf *.o *.ko *.mod.* test
	rm -rf .*.cmd*
	rm -rf modules* Module*
endif

 

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: GPIO是英文General Purpose Input/Output的缩写,翻译过来就是通用输入输出。Linux内核提供了GPIO驱动框架,可以通过该框架来控制硬件上的GPIO,实现对外设的控制。 在Linux内核中,GPIO驱动可以分为两类:基于平台的GPIO驱动和基于设备的GPIO驱动。基于平台的GPIO驱动是针对整个平台的GPIO控制,而基于设备的GPIO驱动则是针对单个设备的GPIO控制。 在使用GPIO驱动时,需要先找到所使用的GPIO引脚的编号,并将其映射到内存中的地址。然后通过读写内存中的寄存器来控制GPIO的状态。 对于GPIO的操作可以通过Linux内核提供的sysfs接口来实现。在sysfs中,每个GPIO都被表示为一个文件,可以通过读写文件来进行GPIO的操作。 需要注意的是,在使用GPIO驱动时,需要谨慎操作,避免对硬件造成损坏。同时,还需要了解所使用的硬件设备的特性和限制,以确保GPIO驱动的正确使用。补充说明: 在Linux内核中,GPIO驱动主要由GPIO子系统和GPIO控制驱动两部分组成。GPIO子系统提供了一个通用的接口,用于操作GPIO控制驱动,而GPIO控制驱动则是实际控制硬件的部分。 GPIO子系统可以分为两个部分:GPIO框架和GPIO API。GPIO框架是一个通用的框架,用于管理GPIO控制器和GPIO设备,它定义了一些数据结构和函数接口,用于注册和管理GPIO控制器和GPIO设备。GPIO API是一个用户空间的API,提供了一些函数接口,用于操作GPIOGPIO控制驱动是针对特定的GPIO控制器的驱动程序,它负责实际控制GPIO的硬件操作。在Linux内核中,每种GPIO控制器都有一个对应的GPIO控制驱动程序。当使用GPIO时,首先需要通过GPIO子系统将GPIO控制驱动注册到系统中,然后才能使用GPIO API对GPIO进行操作。 需要注意的是,在使用GPIO驱动时,需要注意GPIO的电气特性,避免对硬件造成损坏。同时,在进行GPIO操作时,还需要注意GPIO的并发访问和竞争问题,以确保系统的正确性和稳定性。 ### 回答2: Linux GPI驱动指的是Linux系统中通过General Purpose Input/Output(GPIO)接口与硬件设备进行交互的驱动程序。GPIO接口是一组通用的、可编程的多功能引脚,可用于连接各种外部设备,例如开关、LED、传感器、驱动器等。 Linux GPIO驱动可以实现对GPIO引脚的读写操作、中断处理等功能。它不仅可以与单片机等嵌入式设备进行通信,还可与各种外接硬件设备进行连接和通信。 在Linux系统中,用户可以通过/sys/class/gpio文件系统来访问GPIO引脚。在使用GPIO驱动时,用户需要首先加载相应的内核模块,然后使用GPIO API来对引脚进行读写操作或开启中断。 GPIO驱动程序需要实现以下功能: 1. 查询GPIO可用性及分配资源。通常,由于GPIO是多路的,因此设备需要分配资源共享GPIO。 2. 初始化GPIO引脚,包括定义方向及设置上下拉电阻等。 3. 实现GPIO引脚的读写操作。 4. 解除分配资源并释放相关资源。 正常情况下,GPIO驱动程序会提供一个设备文件,用户可以通过读写该文件实现GPIO引脚的操作。 总之,Linux GPIO驱动具有良好的可移植性和稳定性,可以方便地与其他硬件设备进行交互,因此被广泛应用于各种嵌入式设备和嵌入式系统中。 ### 回答3: Linux GPIO驱动是一种在嵌入式系统中实现通用输入输出(GPIO,General Purpose Input/Output)功能的软件驱动GPIO是一种非常有用的硬件资源,它可以连接到外部设备,例如LED灯、按键和触摸屏等。 Linux内核支持GPIO操作,当你的嵌入式系统上有GPIO设备时,你可以利用GPIO来读取或设置其状态。驱动程序能够将GPIO标记为输入或输出,并且它们可以在运行时进行配置。 在Linux中,一般有两种方式将GPIO驱动程序添加到内核中:一种是将其编译到内核中,另一种是将其作为模块加载。 GPIO驱动程序等价于操作系统提供的设备文件,例如/dev/gpiochip0,它允许用户空间应用程序访问GPIO。这些设备文件可用于读取或写入GPIO状态。例如,要控制一个LED,需要将GPIO设置为输出模式,然后将其电平设置为高或低即可。 除此之外,GPIO驱动程序也可以实现中断(interrupt)机制,GPIO的状态变化时可以产生中断事件,这常用于处理GPIO键盘或GPIO中断信号的应用场景。 总结来说,Linux内核支持GPIO驱动需要有以下几个步骤:配置GPIO硬件;添加驱动程序;编写用户空间应用程序,按需要读取或设置GPIO状态来和外设交互。GPIO驱动程序是嵌入式系统中非常必要的组成部分,它们能够随时提供接口以方便对外部设备的读写访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值