当前位置: 首页 > news >正文

Linux驱动入门实验班——LED驱动(附百问网视频链接)

目录

一、确定引脚编号

二、编写思路

2.1驱动层

2.2应用层

三、源码

四、实现

课程链接


一、确定引脚编号

首先,可以在开发板上执行如下命令查看已经在使用的GPIO状态:

cat /sys/kernel/debug/gpio

可以看到每个gpio都有对应的编号,如何查看自己想要的设备对应的gpio编号呢?

最简单的就是可以通过查看原理图 :

我所使用的开发板时IMX6ULL,所以下面也是IMX6ULL的开发板原理图上截取出来的

通过原理图我们可以观察到LED所在的引脚为GPIO5_3,意思是第五组中的第三个

根据上方我们用cat命令查看到的GPIO状态,可知一组GPIO为0-31,也就是三十二个。

GPIO1:0~31

GPIO2:32~63

GPIO5:4 x 32 

GPIO5_3 : 4 x 32 + 3

可知LED引脚为 32 x 5 + 3 = 131

得出来引脚编号,就可以进行代码实现了。 

二、编写思路

2.1驱动层

1.先构造file_operations结构体。

static struct file_operations led_drv = {.owner = THIS_MOUDLE,.read = led_drv_read,.write = led_drv_write,
};

2.实现write和read函数

根据自己构造出来的的file_operations结构体,去实现具体的函数。

使用到的函数

  • opy_to_user()
  • copy_from_user()
  • gpio_set_value
  • gpio_get_value

在上一篇文章有具体介绍这篇文章所使用到的函数的作用和使用方法。

3.编写入口函数

用到的函数

  • gpio_request
  • gpio_direction_output
  • register_chrdev
  • class_create
  • device_create

4.编写出口函数

  • device_destroy
  • class_destroy
  • unregister_chrdev
  • gpio_free

5.声明出口函数和入口函数,声明描述内核模块的许可权限 

  • module_init
  • module_exit
  • MODULE_LICENSE("GPL");

2.2应用层

根据传入参数的个数和值,判断用户想对那个引脚进行什么操作 

实现选择控制LED亮灭,可读取GPIO电平状态

三、源码

led_drv.c

#include "asm-generic/errno-base.h"
#include "asm-generic/gpio.h"
#include "asm/uaccess.h"
#include <linux/module.h>
#include <linux/poll.h>#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>struct gpio_desc {int gpio;int irq;char *name;
};static struct gpio_desc gpios[2] = 
{{131, 0, "led0"},
};static int major = 0;
static struct class *led_class;static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{char kernel_buf[2];int err;if(size != 2){return -EINVAL;}err = copy_from_user(kernel_buf, buf, 1);if(kernel_buf[0] >= (sizeof(gpios)/sizeof(gpios[0]))){return -EINVAL;}kernel_buf[1] = gpio_get_value(gpios[kernel_buf[0]].gpio);err = copy_to_user(buf, kernel_buf, 2);return 2;
}static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{char kernel_buf[2];int err;if (size != 2){return -EINVAL;}err = copy_from_user(kernel_buf, buf, 1);if (kernel_buf[0] >= (sizeof(gpios)/sizeof(gpios[0]))){return -EINVAL;}gpio_set_value(gpios[kernel_buf[0]].gpio,kernel_buf[1]);return 2;a
}static struct file_operations led_drv = {.owner = THIS_MODULE,.read = led_drv_read,.write = led_drv_write,
};static int __init led_drv_init(void)
{int err;int i;int count = sizeof(gpios)/sizeof(gpios[0]);for (i = 0; i < count; i++){err = gpio_request(gpios[i].gpio, gpios[i].name);if (err < 0) {printk("can not request gpio %s %d\n", gpios[i].name, gpios[i].gpio);return -ENODEV;}gpio_direction_output(gpios[i].gpio, 1);}/* 注册file_operations结构体 */major = register_chrdev(0, "led_drv",&led_drv);led_class = class_create(THIS_MODULE, "drv_class");if (IS_ERR(led_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "led_class");return PTR_ERR(led_class);}device_create(led_class, NULL, MKDEV(major, 0), NULL, "led_drv");return 0;
}static void __exit led_drv_exit(void)
{int i;int count = sizeof(gpios)/sizeof(gpios[0]);device_destroy(led_class, MKDEV(major, 0));class_destroy(led_class);unregister_chrdev(major, "led_drv");for(i = 0; i< count; i++){gpio_free(gpios[i].gpio);}
}module_init(led_drv_init);
module_exit(led_drv_exit);MODULE_LICENSE("GPL");

led_drv_test.c

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <signal.h>int main(int argc, char **argv)
{int ret;int fd;char buf[2];if (argc < 2){printf("Usage : %s <0> [on|off]", argv[0]);return -1;}fd = open("/dev/led_drv", O_RDWR);if (fd == -1){printf("can not open file /dev/100ask_led\n");return -1;}if (argc == 3){buf[0] = strtol(argv[1],NULL, buf[0]);if(strcmp(argv[2],"on") == 0){buf[1] = 0;}else{buf[1] = 1;}ret = write(fd, buf, 2);}else{buf[0] = strtol(argv[1], NULL, 0);ret = read(fd, buf, 2);if (ret == 2){printf("led %d status is %s\n", buf[0], buf[1] == 0 ? "on" : "off");}}close(fd);return 0;
}

四、实现

在开发板上执行以下命令,将生成的.ko文件装载到内核

insmod led_drv.ko

课程链接

36_模板1实战_LED驱动上机_STM32MP157_哔哩哔哩_bilibiliicon-default.png?t=N7T8https://www.bilibili.com/video/BV1XK411D7wK/?p=37&spm_id_from=pageDriver&vd_source=3a9afee9fda50350a1c881b4325e007d

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • pnpm install 后还是没有生成 pnpm-lock.yaml 文件
  • CentOS系统下安装NVIDIA显卡驱动
  • 云原生日志Loki
  • MySQL 数据表管理
  • 41-设计规则:线宽规则
  • [upload]-做题笔记
  • 疫情隔离酒店管理系统的开发--论文pf
  • Postman内置动态参数和自定义动态参数
  • 钧瓷联合体——7月中国最具影响力的50位钧瓷匠人
  • flink车联网项目前篇:业务实现1(第67天)
  • AI编程系列一1小时完成链家房价爬虫程序
  • 【MySQL】数据库约束
  • 【Kubernetes】k8s集群安全机制
  • CPU飙升 怎么定位问题
  • nginx代理转发如何配置
  • 分享一款快速APP功能测试工具
  • 【comparator, comparable】小总结
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • dva中组件的懒加载
  • HTTP中的ETag在移动客户端的应用
  • JavaScript类型识别
  • JWT究竟是什么呢?
  • mysql中InnoDB引擎中页的概念
  • React Transition Group -- Transition 组件
  • tab.js分享及浏览器兼容性问题汇总
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • webpack项目中使用grunt监听文件变动自动打包编译
  • WebSocket使用
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 将回调地狱按在地上摩擦的Promise
  • 坑!为什么View.startAnimation不起作用?
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 学习HTTP相关知识笔记
  • 异步
  • 正则与JS中的正则
  • ​​​【收录 Hello 算法】10.4 哈希优化策略
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #define 用法
  • #我与Java虚拟机的故事#连载14:挑战高薪面试必看
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (175)FPGA门控时钟技术
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (delphi11最新学习资料) Object Pascal 学习笔记---第13章第1节 (全局数据、栈和堆)
  • (Python) SOAP Web Service (HTTP POST)
  • (Qt) 默认QtWidget应用包含什么?
  • (安卓)跳转应用市场APP详情页的方式
  • (备忘)Java Map 遍历
  • (二)pulsar安装在独立的docker中,python测试
  • (附源码)springboot高校宿舍交电费系统 毕业设计031552
  • (更新)A股上市公司华证ESG评级得分稳健性校验ESG得分年均值中位数(2009-2023年.12)
  • (六)Hibernate的二级缓存
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (四)【Jmeter】 JMeter的界面布局与组件概述