驱动——gpio子系统(LED灯的操控实验)
创始人
2024-02-11 20:36:48
0

 使用GPIO子系统操控6盏LED灯的亮灭

1、编写设备树节点:

添加如下所示代码到stm32mp157a-fdmp1a.dts中根节点里面,给LED灯定义名字,并引用GPIO寄存器及相对应的引脚信息;

     myleds{myled1 = <&gpioe 10 0>;myled2 = <&gpiof 10 0>;myled3 = <&gpioe 8 0>;myled4 = <&gpioz 5 0>;myled5 = <&gpioz 6 0>;myled6 = <&gpioz 7 0>;          };

 2、实现字符设备驱动并创建与LED灯相应的6个设备节点(具体详情见驱动——串口点灯实验内容)

3、获取设备树节点信息(获取方式不唯一,本次采用通过节点名字获取)

struct device_node *of_find_node_by_path(const char *path)

功能:获取设备树节点信息通过路径

参数: path:节点路径

返回值:成功返回目标节点的信息结构体地址,失败返回NULL

 struct device_node *of_find_node_by_name(struct device_node *from, const char *name)

功能:通过节点名字获取节点信息

参数:from:已知设备树节点的首地址 (填NULL,默认从根节点解析)

name:设备树节点的名字 "myleds"

返回值:成功返回目标节点的信息结构体地址,失败返回NULL

 4、根据GPIO子系统函数API对LED灯进行操作(子系统函数有新旧两个版本,本次采用新版本)

 ①在在设备树节点信息结构体中获取并申请要使用的gpio编号

旧版本:

 int of_get_named_gpio(struct device_node *np, const char *propname, int index)

功能:根据gpio节点解析获取GPIO编号

参数:

np:节点结构体首地址

proname:键名

index:索引号

返回值:成功返回GPIO编号,失败返回错误码

int gpio_request(unsigned gpio, const char *label)

作用:申请指定GPIO编号的使用权

参数:

gpio:目标GPIO编号

label:一般填写NULL

成功返回0,失败返回错误码

新版本:

struct gpio_desc *gpiod_get_from_of_node(struct device_node *node, const char *propname, int index, enum gpiod_flags dflags, const char *label)

功能:在设备树节点信息结构体中获取并申请要使用的gpio编号

参数:

node:设备树节点信息结构体指针

propname:键名

index:索引

dflags:gpio状态值

GPIOD_OUT_LOW

GPIOD_OUT_HIGH

label:标签,填写NULL

返回值:成功返回gpio描述结构体指针,失败返回错误码指针

②设置管脚为输出模式

 int gpio_direction_output(unsigned gpio, int value)

作用:设置GPIO为输出

参数:

gpio:GPIO编号 value:1:高电平 0:低电平

返回值:成功返回0,失败返回错误码

int gpio_direction_input(unsigned gpio)

作用:设置GPIO为输入

参数:gpio:GPIO编号

返回值:成功返回0,失败返回错误码

新版本:

 int gpiod_direction_input(struct gpio_desc *desc) -----》输入模式

int gpiod_direction_output(struct gpio_desc *desc, int value)------》输出模式

 ③通过ioctl函数传参获取信息,根据应用层逻辑让LED灯输出高低电平,达到操控灯亮灭的过程

旧版本:

int gpio_get_value(unsigned int gpio)

功能:获取GPIO电平状态

参数:GPIO编号

返回值: 1:高电平 0:低电平

void gpio_set_value(unsigned int gpio, int value)

作用:让GPIO输出高低电平

参数: gpio:GPIO编号

value:1:高电平 0:低电平

返回值:无

新版本 

int gpiod_get_value(const struct gpio_desc *desc)

void gpiod_set_value(struct gpio_desc *desc, int value)

 ④释放申请的GPIO编号

旧版本

void gpio_free(unsigned gpio)

作用:释放申请的GPIO编号

参数:目标GPIO编号

新版本

void gpiod_put(struct gpio_desc *desc)

 具体代码实现:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include"./six.h"
/*myleds{                       myled1 = <&gpioe 10 0>;myled2 = <&gpiof 10 0>;myled3 = <&gpioe 8 0>;myled4 = <&gpioz 5 0>;myled5 = <&gpioz 6 0>;myled7 = <&gpioz 7 0>;*/
#define GNAME "mydev"
unsigned int major =0;
char kbuf[128]={0};
struct cdev* cdev;
struct class * cls;
struct device *devic;
dev_t dev1;
int minor = 0;
unsigned count=6;
wait_queue_head_t wq;
int condition=0;int mydev_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}
long mydev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{int addr;switch(cmd){case LED_ON:{ret = copy_from_user(&addr,(void*)arg,sizeof(int));if(ret){printk("copy from user on is error\n");return -EIO;}switch(addr){case LED1:{gpiod_set_value(gpiono1,1);break;}case LED2:{gpiod_set_value(gpiono2,1);break;}case LED3:{gpiod_set_value(gpiono3,1);break;}case LED4:{gpiod_set_value(gpiono4,1);break;}case LED5:{gpiod_set_value(gpiono5,1);break;}case LED6:{gpiod_set_value(gpiono6,1);break;}}    break;}case LED_OFF:{ret = copy_from_user(&addr,(void*)arg,sizeof(int));if(ret){printk("copy from user on is error\n");return -EIO;}switch(addr){case LED1:{gpiod_set_value(gpiono1,0);break;}case LED2:{gpiod_set_value(gpiono2,0);break;}case LED3:{gpiod_set_value(gpiono3,0);break;}case LED4:{gpiod_set_value(gpiono4,0);break;}case LED5:{gpiod_set_value(gpiono5,0);break;}case LED6:{gpiod_set_value(gpiono6,0);break;}}    break;}}return 0;
}
int mydev_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}
struct file_operations fops={.open=mydev_open,.unlocked_ioctl=mydev_ioctl,.release=mydev_close,
};
static int __init mynode_init(void)
{int i;int ret;//分配字符设备驱动cdev=cdev_alloc();if(NULL==cdev){printk("cdev alloc error\n");goto ERR1;}//设备驱动初始化cdev_init(cdev,&fops);//申请设备号if(major>0){ret=register_chrdev_region(MKDEV(major,minor),count,GNAME);if(ret!=0){printk("register chrdev region error\n");ret = -ENOMEM;goto ERR2;}}else{ret=alloc_chrdev_region(&dev1,0,count,GNAME);if(ret!=0){printk("alloc chrdev region error\n");ret = -ENOMEM;goto ERR2;}major = MAJOR(dev1);minor = MINOR(dev1);}//驱动的注册ret = cdev_add(cdev,MKDEV(major,minor),count);if(ret!=0){printk("cdev add error\n");ret = -EIO;goto ERR3;}//通过名字获取设备树节点信息node = of_find_node_by_name(NULL,"myleds");if(NULL == node){printk("of find node by name error\n");return -EFAULT;}//获取并申请LED1的gpio编号gpiono1 = gpiod_get_from_of_node(node,"myled1",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono1)){printk("1gpiod get from of node error\n");return PTR_ERR(gpiono1);}//获取并申请LED2的gpio编号gpiono2 = gpiod_get_from_of_node(node,"myled2",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono2)){printk("2gpiod get from of node error\n");return PTR_ERR(gpiono2);}//获取并申请LED3的gpio编号gpiono3 = gpiod_get_from_of_node(node,"myled3",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono3)){printk("3gpiod get from of node error\n");return PTR_ERR(gpiono3);}//获取并申请LED4的gpio编号gpiono4 = gpiod_get_from_of_node(node,"myled4",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono4)){printk("4gpiod get from of node error\n");return PTR_ERR(gpiono4);}//获取并申请LED5的gpio编号gpiono5 = gpiod_get_from_of_node(node,"myled5",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono5)){printk("5piod get from of node error\n");return PTR_ERR(gpiono5);}//获取并申请LED6的gpio编号gpiono6 = gpiod_get_from_of_node(node,"myled6",0,GPIOD_OUT_LOW,NULL);if(IS_ERR(gpiono6)){printk("6gpiod get from of node error\n");return PTR_ERR(gpiono6);}//设置LED1管脚为输出gpiod_direction_output(gpiono1,0);//设置LED2管脚为输出gpiod_direction_output(gpiono2,0);//设置LED3管脚为输出gpiod_direction_output(gpiono3,0);//设置LED4管脚为输出gpiod_direction_output(gpiono4,0);//设置LED5管脚为输出gpiod_direction_output(gpiono5,0);//设置LED6管脚为输出gpiod_direction_output(gpiono6,0);//自动创建设备节点cls = class_create(THIS_MODULE,GNAME);if(IS_ERR(cls)){ret = PTR_ERR(cls);goto ERR4;}for(i=0;i=0;i--){device_destroy(cls,MKDEV(major,i));}class_destroy(cls);
ERR4:cdev_del(cdev);
ERR3:unregister_chrdev_region(MKDEV(major,minor),count);
ERR2:kfree(cdev);
ERR1:return -EIO;}static void __exit mynode_exit(void)
{int i;//卸载驱动前熄灭灯LED1gpiod_set_value(gpiono1,0);//卸载驱动前熄灭灯LED1gpiod_set_value(gpiono2,0);//卸载驱动前熄灭灯LED1gpiod_set_value(gpiono3,0);//卸载驱动前熄灭灯LED1gpiod_set_value(gpiono4,0);//卸载驱动前熄灭灯LED1gpiod_set_value(gpiono5,0);//卸载驱动前熄灭灯LED1gpiod_set_value(gpiono6,0);//释放申请得到的LED1gpio编号gpiod_put(gpiono1);//释放申请得到的LED2gpio编号gpiod_put(gpiono2);//释放申请得到的LED3gpio编号gpiod_put(gpiono3);//释放申请得到的LED4gpio编号gpiod_put(gpiono4);//释放申请得到的LED5gpio编号gpiod_put(gpiono5);//释放申请得到的LED6gpio编号gpiod_put(gpiono6);//销毁设备节点信息for(i=0;i

 头文件代码

#ifndef __LED_H__
#define __LED_H__#define LED_ON _IOW('a',1,int)
#define LED_OFF _IOW('a',0,int)struct device_node *node;
struct gpio_desc *gpiono1;
struct gpio_desc *gpiono2;
struct gpio_desc *gpiono3;
struct gpio_desc *gpiono4;
struct gpio_desc *gpiono5;
struct gpio_desc *gpiono6;
int ret;typedef enum{LED1,LED2,LED3,LED4,LED5,LED6
}led_t;#endif

 

 应用层测试代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include"./six.h"int main(int argc, char const *argv[])
{int fd1 = -1;int fd2 = -1;int fd3 = -1;int fd4 = -1;int fd5 = -1;int fd6 = -1;int i=0;int whitch;fd1 = open("/dev/myled1",O_RDWR);if(-1 == fd1){perror("open is error");exit(1);}fd2 = open("/dev/myled2",O_RDWR);if(-1 == fd2){perror("open is error");exit(1);}fd3 = open("/dev/myled3",O_RDWR);if(-1 == fd3){perror("open is error");exit(1);}fd4 = open("/dev/myled4",O_RDWR);if(-1 == fd4){perror("open is error");exit(1);}fd5 = open("/dev/myled5",O_RDWR);if(-1 == fd5){perror("open is error");exit(1);}fd6 = open("/dev/myled0",O_RDWR);if(-1 == fd6){perror("open is error");exit(1);}while(1){whitch=LED1;ioctl(fd1,LED_ON,&whitch);sleep(1);ioctl(fd1,LED_OFF,&whitch);whitch=LED2;ioctl(fd2,LED_ON,&whitch);sleep(1);ioctl(fd2,LED_OFF,&whitch);whitch=LED3;ioctl(fd3,LED_ON,&whitch);sleep(1);ioctl(fd3,LED_OFF,&whitch);whitch=LED4;ioctl(fd4,LED_ON,&whitch);sleep(1);ioctl(fd4,LED_OFF,&whitch);whitch=LED5;ioctl(fd5,LED_ON,&whitch);sleep(1);ioctl(fd5,LED_OFF,&whitch);whitch=LED6;ioctl(fd6,LED_ON,&whitch);sleep(1);ioctl(fd6,LED_OFF,&whitch);}close(fd1);close(fd2);close(fd3);close(fd4);close(fd5);close(fd6);return 0;
}

 makefile脚本代码:

ARCH ?= arm
FILE ?= led
ARM:=arm
X86:=x86
ifeq ($(ARCH),$(ARM))
KERNEDIR:=/home/ubuntu/linux-5.10.61
endif
ifeq ($(ARCH),$(X86))
KERNEDIR:=/lib/modules/$(shell uname -r)/build
endif
PWD:=$(shell pwd)
KBUILD_EXTRA_SYMBOLS:=/home/ubuntu/ww/driver/01_linux/03_sym/01_demo/Module.symvers
all:make -C $(KERNEDIR) M=$(PWD) modules
clean:make -C $(KERNEDIR) M=$(PWD) clean
obj-m:=$(FILE).o

实验现象:

gpio子系统6盏LED灯操作实验

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...