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

news2024/11/26 10:16:52

目录

一、确定引脚编号

二、编写思路

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2035526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

岗位信息采集全攻略:两种方法快速获取招聘信息

摘要 本文将揭秘两大实战策略&#xff0c;助你在激烈的人才市场中迅速捕捉前程无忧上的宝贵岗位信息&#xff0c;无论是手动搜索还是利用现代技术手段&#xff0c;都能事半功倍&#xff0c;抢占先机。 正文 一、手动搜索的艺术&#xff1a;精准定位&#xff0c;深度挖掘 1.…

【网络】传输层TCP协议的报头和传输机制

目录 引言 报头和有效载荷 确认应答机制 超时重传机制 排序和去重 连接管理机制 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 TCP是传输层协议&#xff0c;全称传输控制协议。TCP报头中有丰富的字段以及协议本身会制定完善的策略来保证网络传输的可靠性。 TCP…

ICM-20948芯片详解(12)

接前一篇文章&#xff1a;ICM-20948芯片详解&#xff08;11&#xff09; 六、寄存器详解 2. USER BANK 0寄存器详述 &#xff08;56&#xff09;FIFO_EN_1 参考代码&#xff1a; 无。 &#xff08;57&#xff09;FIFO_EN_2 ACCEL_FIFO_EN 1 —— 以采样率将ACCEL-XOUT_H、…

haproxy实例

什么是haproxy Haproxy是一款提供高可用性&#xff0c;负载均衡以及基于tcp和http的的应用交付控制器的开源软件。它由法国人威利塔罗使用c语言开发的。它广泛用于管理和路由网络流量&#xff0c;并确保应用程序的高可用性和高性能。 haproxy的功能 提供第4层&#xff08;TCP层…

vulnhub系列:Hackademic.RTB1

vulnhub系列&#xff1a;Hackademic.RTB1 靶机下载 一、信息收集 nmap 扫描存活&#xff0c;根据 mac 地址寻找 IP nmap 192.168.23.0/24nmap 扫描端口&#xff0c;开放端口&#xff1a;22、80 nmap 192.168.23.143 -p- -Pn -sV -O访问80端口&#xff0c;页面发现 target …

DirectX修复工具解决问题:一步步教你排除常见错误

在日常使用电脑的过程中&#xff0c;许多用户可能会遇到与DirectX相关的问题&#xff0c;特别是在运行大型游戏或图形密集型应用程序时。这种情况下&#xff0c;选择一款合适的DirectX修复工具免费版来解决问题至关重要&#xff01; 我们将分享六款好用的DirectX修复工具&…

字节Java后端二面也太难了吧...

粉丝投稿&#xff0c;字节二面直接连环问场景题&#xff0c;难以招架&#xff0c;已经准备好市场上常见的场景题了&#xff0c;希望能帮助你&#xff01; 由于平台篇幅原因&#xff0c;很多内容展示不了&#xff0c;需要这份《java面试宝典》的伙伴们转发文章关注后&#xff…

Linux_Shell变量及运算符-05

一、Shell基础 1.1 什么是shell Shell脚本语言是实现Linux/UNIX系统管理及自W动化运维所必备的重要工具&#xff0c; Linux/UNIX系统的底层及基础应用软件的核心大都涉及Shell脚本的内容。Shell是一种编程语言, 它像其它编程语言如: C, Java, Python等一样也有变量/函数/运算…

MySQL基础练习题38-每位教师所教授的科目种类的数量

目录 题目 准备数据 分析数据 总结 题目 查询每位老师在大学里教授的科目种类的数量。 准备数据 ## 创建库 create database db; use db;## 创建表 Create table If Not Exists Teacher (teacher_id int, subject_id int, dept_id int)## 向表中插入数据 Truncate table…

ALB使用指南|深入探究 lj-lua-stacks:如何生成 Lua 代码级别的火焰图?

前言 ALB&#xff08;Another Load Balancer&#xff09;是一款由灵雀云基于 OpenResty 开发的开源Kubernetes&#xff08;K8s&#xff09; 网关&#xff0c;拥有多年的生产环境使用经验。Openresty框架高性能的基础上&#xff0c;提供了一系列高级特性&#xff0c;包括多租户支…

JsonUtility和JsonConvert.DeserializeObject

文章目录 JsonUtility 和 JsonConvert在字符串转类型时的不同总结 JsonUtility 和 JsonConvert在字符串转类型时的不同 不同&#xff1a; JsonUtility.FromJson要转的字符串内不能有注释的字符串 但JsonConvert.DeserializeObject要转的字符串里可以有 原因&#xff1a;. Jso…

新品|暴雨发布第四代工作站静安系列-TR1176

极致性能引领未来 暴雨信息推出全新一代工作站——静安系列TR1176&#xff0c;搭载了强劲的第四代处理器&#xff0c;为客户带来前所未有的计算速度与效率。无论是处理大规模数据集、复杂算法还是高负载多任务&#xff0c;都能轻松应对&#xff0c;确保客户的工作流程顺畅无阻…

【随笔】Java 连接操作FTP与SFTP 详细指南

引言 在Java开发中&#xff0c;文件传输协议&#xff08;FTP&#xff09;和安全文件传输协议&#xff08;SFTP&#xff09;是处理文件传输的两种常见方式。FTP是标准的网络文件传输协议&#xff0c;而SFTP则在FTP基础上增加了安全层&#xff08;SSH&#xff09;&#xff0c;提…

设计模式 之 —— 组合模式

目录 什么是组合模式&#xff1f; 定义 特点 结构 组合模式&#xff08;java代码示例&#xff09; 首先定义接口 定义叶节点&#xff08;Leaf类&#xff09; 定义容器节点&#xff08;Composite类&#xff09; 测试类&#xff1a; 树形图 运行结果&#xff1a; 组…

CUDA Programming - (1) CUDA简介

1. GPU 简介 处理器一般包含以下几部分&#xff1a;Cache 缓存&#xff0c;ALU 计算单元&#xff0c;Control 控制中心&#xff0c;RAM 内存。 CPU&#xff08;Central Processing Unit&#xff09;&#xff1a;中央处理器。适合进行逻辑&#xff0c;ALU计算核心较少。适合控…

乒乓球桌上的AI新星:谷歌机器人Agent,是竞技的未来,还是科技的幻想?

在巴黎奥运会乒乓球的激烈角逐中&#xff0c;一个不同寻常的选手悄然登场——谷歌的乒乓球机器人Agent。 这是首个在竞技水平上达到人类标准的AI机器人。 01 AI机器人颠覆初级玩家 Agent不仅能够在正反手之间自如转换&#xff0c;连续进攻&#xff0c;甚至在面对诸如长球、高…

【Qt】QWidegt的enable属性

enabled&#xff1a;描述了一个控件是否处于“可用”状态&#xff08;相对的概念“禁用”&#xff09;。 API说明 isEnabled() 获取到控件的可⽤状态 setEnabled 设置控件是否可使⽤. true 表⽰可⽤, false 表⽰禁⽤ 所谓“禁用”指的是该控件不能接收任何用户的输入事件…

localStorage用法

一、localStorage API使用 注意&#xff0c;localStorage 只能存储字符串。 1.1 存储数据 例如&#xff0c;对象存储时&#xff0c;可以使用JSON.stringify 转成字符串&#xff1b; // 假设你有一个对象 const myObject {name: Alice,age: 25, };// 使用 JSON.stringify 将…

解决windows7虚拟机安装不了vmtools问题

安装不了vmtools问题所在&#xff1a; 没打补丁 ​ 打补丁问题 补丁在本地下载之后无法传到win7虚拟机中 补丁获取 补丁链接如下&#xff1a; https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6…

脱胎于 S 语言的R语言,Ross Ihaka 和 Robert Gentleman 和社区的力量让 R 在学术界与研究机构放光彩

R语言从一门用于统计学教学的编程语言&#xff0c;发展成为全球数据科学领域的重要工具&#xff0c;离不开其强大的功能、丰富的社区资源和开源精神。这些都离不开Ross Ihaka 和 Robert Gentleman 和 社区的力量。 在1990年代初&#xff0c;新西兰奥克兰大学的统计学教授Ross I…