1.基于GPIO子系统编写LED驱动,编写应用程序进行测试
stm32mp157a-fsmp1a.dts

内核程序:ledk.c
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_gpio.h>
- #include <linux/delay.h>
- #include <linux/timer.h>
-
- struct device_node *dnode1;
- struct gpio_desc *gpiono1;
- struct gpio_desc *gpiono2;
- struct gpio_desc *gpiono3;
- struct timer_list mytimer;
-
- unsigned int *vir_rcc;
- struct class *cls;
- struct device *dev;
- int major;
-
- char kbuf[128] = {0};
-
- //定义操作方法
- int mycdev_open(struct inode *inode, struct file *file)
- {
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
- ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
- {
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- int ret1=copy_to_user(ubuf,kbuf,size);
- if(ret1)
- {
- printk("copy_to_user filed\n");
- return -EIO;
- }
- return 0;
- }
- ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
- {
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- int ret=copy_from_user(kbuf,ubuf,size);
- if(ret)
- {
- printk("copy_from_user filed\n");
- return -EIO;
- }
- //设定该GPIO管脚的输出值
- if(!strcmp(kbuf,"off"))
- {
- gpiod_set_value(gpiono1,0);
- gpiod_set_value(gpiono2,0);
- gpiod_set_value(gpiono3,0);
- }
- else if(!strcmp(kbuf,"on"))
- {
- gpiod_set_value(gpiono1,1);
- gpiod_set_value(gpiono2,1);
- gpiod_set_value(gpiono3,1);
- }
- return 0;
- }
- int mycdev_close(struct inode *inode, struct file *file)
- {
-
- printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
- return 0;
- }
- //定义操作方法结构体变量并赋值
- struct file_operations fops = {
- .open = mycdev_open,
- .read = mycdev_read,
- .write = mycdev_write,
- .release = mycdev_close,
- };
-
- static int __init mycdev_init(void)
- {
- // 字符设备驱动注册
- major = register_chrdev(0, "mychrdev", &fops);
- if (major < 0)
- {
- printk("字符设备驱动注册失败\n");
- return major;
- }
- printk("字符设备驱动注册成功:major=%d\n", major);
- // 向上提交目录
- cls = class_create(THIS_MODULE, "mychrdev");
- if (IS_ERR(cls))
- {
- printk("向上提交目录失败\n");
- return -PTR_ERR(cls);
- }
- printk("向上提交目录成功\n");
- // 向上提交设备节点信息
- int i; // 向上提交三次设备节点信息
- for (i = 0; i < 3; i++)
- {
- dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
- if (IS_ERR(dev))
- {
- printk("向上提交设备节点失败\n");
- return -PTR_ERR(dev);
- }
- }
- printk("向上提交设备节点成功\n");
-
-
- //解析设备树节点信息
- dnode1 = of_find_node_by_path("/myled");
- if(dnode1 == NULL)
- {
- printk("path_find failed \n");
- return -ENXIO;
- }
- //根据GPIO相关节点得到GPIO编号
- gpiono1 = gpiod_get_from_of_node(dnode1,"led1-gpio",0,GPIOD_OUT_LOW,NULL);
- if(IS_ERR(gpiono1))
- {
- printk("申请gpiono1信息失败 \n");
- }
- printk("申请gpiono1信息成功 \n");
- gpiono2 = gpiod_get_from_of_node(dnode1,"led2-gpio",0,GPIOD_OUT_LOW,NULL);
- if(IS_ERR(gpiono2))
- {
- printk("申请gpiono2信息失败 \n");
- }
- printk("申请gpiono2信息成功 \n");
- gpiono3 = gpiod_get_from_of_node(dnode1,"led3-gpio",0,GPIOD_OUT_LOW,NULL);
- if(IS_ERR(gpiono3))
- {
- printk("申请gpiono3信息失败 \n");
- }
- printk("申请gpiono3信息成功 \n");
-
-
- //GPIO的状态
-
- return 0;
- }
- static void __exit mycdev_exit(void)
- {
- //设定该GPIO管脚的输出值
- gpiod_set_value(gpiono1,0);
- gpiod_set_value(gpiono2,0);
- gpiod_set_value(gpiono3,0);
- //释放GPIO编号
- gpiod_put(gpiono1);
- gpiod_put(gpiono2);
- gpiod_put(gpiono3);
-
- // 销毁设备节点信息
- int i;
- for (i = 0; i < 3; i++)
- {
- device_destroy(cls, MKDEV(major, i));
- }
- // 销毁目录
- class_destroy(cls);
- // 注销字符设备驱动
- unregister_chrdev(major, "mychrdev");
-
- }
- module_init(mycdev_init);
- module_exit(mycdev_exit);
- MODULE_LICENSE("GPL");
应用程序:ledu.c
- #include <stdlib.h>
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <string.h>
-
- int main(int argc,const char * argv[])
- {
- int a=0;
- char buf[128] = "";
- char buf1[128] = "";
- int fd1=open("/dev/myled0",O_RDWR);
- int fd2=open("/dev/myled1",O_RDWR);
- int fd3=open("/dev/myled2",O_RDWR);
- if(fd1<0)
- {
- printf("打开设备文件1失败\n");
- exit(-1);
- }
- if(fd2<0)
- {
- printf("打开设备文件2失败\n");
- exit(-1);
- }
- if(fd3<0)
- {
- printf("打开设备文件3失败\n");
- exit(-1);
- }
-
- memset(buf,0,sizeof(buf));
- while(1)
- {
- printf("请输入灯的控制(1开灯/0关灯) => ");
- scanf("%d",&a);
-
- write(fd1,buf,sizeof(buf));
- write(fd2,buf,sizeof(buf));
- write(fd3,buf,sizeof(buf));
-
- if(a == 1)
- {
- strcpy(buf,"on");
- write(fd1,buf,sizeof(buf));
- write(fd2,buf,sizeof(buf));
- write(fd3,buf,sizeof(buf));
- }
- else if(a == 0)
- {
- strcpy(buf,"off");
- write(fd1,buf,sizeof(buf));
- write(fd2,buf,sizeof(buf));
- write(fd3,buf,sizeof(buf));
- }
- read(fd1,buf1,sizeof(buf));
- printf("buf1:%s\n",buf1);
- }
- return 0;
- }
2.设置定时器,5秒钟打印一次hello world
内核程序
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/of_gpio.h>
- #include <linux/delay.h>
- #include <linux/timer.h>
-
- struct device_node *dnode1;
- struct gpio_desc *gpiono1;
- struct gpio_desc *gpiono2;
- struct gpio_desc *gpiono3;
- struct timer_list mytimer;
-
- char kbuf[128] = {0};
-
- void mytimer_funtion(struct timer_list *timer)
- {
-
- //PRINTK
- printk("阿巴阿巴阿巴阿巴阿巴\n");
- gpiod_set_value(gpiono1,!gpiod_get_value(gpiono1));
-
- //启用定时器
- mod_timer(timer,jiffies + msecs_to_jiffies(5000));
- }
-
-
- static int __init mycdev_init(void)
- {
- //解析设备树节点信息
- dnode1 = of_find_node_by_path("/myled");
- if(dnode1 == NULL)
- {
- printk("path_find failed \n");
- return -ENXIO;
- }
- //根据GPIO相关节点得到GPIO编号
- gpiono1 = gpiod_get_from_of_node(dnode1,"led1-gpio",0,GPIOD_OUT_LOW,NULL);
- if(IS_ERR(gpiono1))
- {
- printk("申请gpiono1信息失败 \n");
- }
- gpiono2 = gpiod_get_from_of_node(dnode1,"led2-gpio",0,GPIOD_OUT_LOW,NULL);
- if(IS_ERR(gpiono2))
- {
- printk("申请gpiono2信息失败 \n");
- }
- gpiono3 = gpiod_get_from_of_node(dnode1,"led3-gpio",0,GPIOD_OUT_LOW,NULL);
- if(IS_ERR(gpiono3))
- {
- printk("申请gpiono3信息失败 \n");
- }
- //分配定时器对象(timer_list)
- //初始化定时器(timer_setup)
- timer_setup(&mytimer,mytimer_funtion,0);
- mytimer.expires = jiffies+HZ;
- //注册定时器并启用(add_timer)
- add_timer(&mytimer);
-
-
- //GPIO的状态
-
- return 0;
- }
- static void __exit mycdev_exit(void)
- {
- //设定该GPIO管脚的输出值
- gpiod_set_value(gpiono1,0);
- gpiod_set_value(gpiono2,0);
- gpiod_set_value(gpiono3,0);
- //释放GPIO编号
- gpiod_put(gpiono1);
- gpiod_put(gpiono2);
- gpiod_put(gpiono3);
- //注销定时器(del_timer)
- del_timer(&mytimer);
-
- }
- module_init(mycdev_init);
- module_exit(mycdev_exit);
- MODULE_LICENSE("GPL");
