使用GPIO子系统操控6盏LED灯的亮灭
1、编写设备树节点:
添加如下所示代码到stm32mp157a-fdmp1a.dts中根节点里面,给LED灯定义名字,并引用GPIO寄存器及相对应的引脚信息;
1
2
3
4
5
6
7
8
9
10myleds{ 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)
具体代码实现:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334#include<linux/init.h> #include<linux/module.h> #include<linux/of.h> #include<linux/of_gpio.h> #include<linux/gpio.h> #include<linux/fs.h> #include<linux/uaccess.h> #include<linux/io.h> #include<linux/cdev.h> #include<linux/slab.h> #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:%dn",__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 errorn"); 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 errorn"); 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:%dn",__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 errorn"); 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 errorn"); ret = -ENOMEM; goto ERR2; } } else { ret=alloc_chrdev_region(&dev1,0,count,GNAME); if(ret!=0) { printk("alloc chrdev region errorn"); ret = -ENOMEM; goto ERR2; } major = MAJOR(dev1); minor = MINOR(dev1); } //驱动的注册 ret = cdev_add(cdev,MKDEV(major,minor),count); if(ret!=0) { printk("cdev add errorn"); ret = -EIO; goto ERR3; } //通过名字获取设备树节点信息 node = of_find_node_by_name(NULL,"myleds"); if(NULL == node) { printk("of find node by name errorn"); 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 errorn"); 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 errorn"); 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 errorn"); 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 errorn"); 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 errorn"); 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 errorn"); 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<count;i++) { devic = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i); if(IS_ERR(devic)) { ret = PTR_ERR(devic); goto ERR5; } } init_waitqueue_head(&wq); return 0; ERR5: for(--i;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; //卸载驱动前熄灭灯LED1 gpiod_set_value(gpiono1,0); //卸载驱动前熄灭灯LED1 gpiod_set_value(gpiono2,0); //卸载驱动前熄灭灯LED1 gpiod_set_value(gpiono3,0); //卸载驱动前熄灭灯LED1 gpiod_set_value(gpiono4,0); //卸载驱动前熄灭灯LED1 gpiod_set_value(gpiono5,0); //卸载驱动前熄灭灯LED1 gpiod_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<count;i++) { device_destroy(cls,MKDEV(major,i)); } class_destroy(cls); //释放驱动 cdev_del(cdev); //释放设备号 unregister_chrdev_region(MKDEV(major,minor),count); //注销字符设备驱动 kfree(cdev); } module_init(mynode_init); module_exit(mynode_exit); MODULE_LICENSE("GPL");
头文件代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#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
应用层测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<stdlib.h> #include<string.h> #include<sys/ioctl.h> #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脚本代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18ARCH ?= 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灯操作实验
最后
以上就是激动火龙果最近收集整理的关于驱动——gpio子系统(LED灯的操控实验) 使用GPIO子系统操控6盏LED灯的亮灭的全部内容,更多相关驱动——gpio子系统(LED灯内容请搜索靠谱客的其他文章。
发表评论 取消回复