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

Linux下LED灯驱动模板详解

一、地址映射

我们先了解MMU,全称是Memory Manage Unit。在老版本的Linux中要求处理器必须有MMU,但是现在Linux内核已经支持五MMU。MMU主要完成的功能如下:

1、完成虚拟空间到物理空间的映射

2、内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性

对于32位的处理器来说,虚拟地址范围是2^32=4GB,我们的开发板上有512MB的DDR3,这512MB内存就是物理内存,经过MMU可以将其映射到整个4GB的虚拟空间,如图所示

Linux内核启动的时候会初始化MMU,设置好内存映射,设置好CPU以后访问的都是虚拟地址,比如 I.MX6ULL 的 GPIO1_IO03 引脚的复用寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 的地址为 0X020E0068。如果没有开启 MMU 的话直接向 0X020E0068 这个寄存器地址写入数据就可以配置 GPIO1_IO03 的复用功能。现在开启了 MMU,并且设置了内存映射,因此就不能直接向 0X020E0068 这个地址写入数据了。我们必须得到 0X020E0068 这个物理地址在 Linux 系统里面对应的虚拟地址,这里就涉及到了物理内存和虚拟内存之间的转换,需要用到两个函数:ioremap 和 iounmap。

1、ioremap函数

ioremap函数用于获取指定物理地址空间对应的虚拟地址空间,定义在arch/arm/include/asm/io.h文件中。假如我们要获取IMX6ULL的IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器对应的虚拟地址,使用如下代码

#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
static void __iomem* SW_MUX_GPIO1_IO03;
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);

宏 SW_MUX_GPIO1_IO03_BASE 是寄存器物理地址,SW_MUX_GPIO1_IO03 是映射后的虚拟地址。对于 I.MX6ULL 来说一个寄存器是 4 字节(32 位)的,因此映射的内存长度为 4。映射完成以后直接对 SW_MUX_GPIO1_IO03 进行读写操作即可。

2、iounmap函数

卸载驱动的时候需要使用iounmap函数释放掉ioremap函数所做的映射,iounmap函数原型如下

void iounmap (volatile void __iomem *addr)

iounmap只有一个参数addr,此参数就是要取消映射的虚拟地址空间首地址

iounmap(SW_MUX_GPIO1_IO03);

二、实验程序编写

1、驱动代码

新建名为2_led文件夹,然后在2_led文件夹里面创建VScode工程,工作区命名为led,工程创建好以后新建led.c文件,此文件就是led的驱动文件,代码如下:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>#define LED_MAJOR  200
#define LED_NAME   "led"//寄存器物理地址
#define CCM_CCGR1_BASE (0X020C406C)
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
#define GPIO1_DR_BASE (0X0209C000)
#define GPIO1_GDIR_BASE (0X0209C004)//映射后的寄存器虚拟地址指针
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;#define LEDOFF   0
#define LEDON    1static void led_switch(u8 sta)
{u32 val = 0;if(sta == LEDON){val = readl(GPIO1_DR);val &= ~(1 << 3);writel(val,GPIO1_DR);}else if(sta == LEDOFF){val = readl(GPIO1_DR);val |= (1 << 3);writel(val,GPIO1_DR);}
}static int led_open(struct inode *inode,struct file *filp)
{return 0;
}static int led_release(struct inode *inode,struct file *flip)
{return 0;
}static ssize_t led_write(struct file *filp, const char __user *buf,size_t count, loff_t *ppos)
{int retvalue;unsigned char databuf[1];retvalue = copy_from_user(databuf,buf,count);if(retvalue < 0){printk("kernel write failed!\r\n");return -EFAULT;}led_switch(databuf[0]);
}static const struct file_operations led_fops = {.owner      = THIS_MODULE,.write    = led_write,.open     = led_open,.release  = led_release,
};static int __init led_init(void)
{int ret = 0;unsigned int val = 0;//寄存器地址映射IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE,4);SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE,4);SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE,4);GPIO1_DR = ioremap(GPIO1_DR_BASE,4);GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE,4);//使能GPIO1时钟val = readl(IMX6U_CCM_CCGR1);val &= ~(3 << 26);val |= 3 << 26;//设置GPIO1_IO03的复用功能writel(val,IMX6U_CCM_CCGR1);//设置IO属性writel(0x5,SW_MUX_GPIO1_IO03);writel(0x10B0,SW_PAD_GPIO1_IO03);//设置为输出功能val = readl(GPIO1_GDIR);val |= 1 << 3;writel(val,GPIO1_GDIR);//默认关闭LEDval = readl(GPIO1_DR);val |= (1 << 3);writel(val,GPIO1_DR);//输出字符设备驱动ret = register_chrdev(LED_MAJOR, LED_NAME,&led_fops);if(ret < 0){printk("register chardev failed!\r\n");return -EIO;}printk("led_init\r\n");return 0;
}static void __exit led_exit(void)
{unsigned int val = 0;val = readl(GPIO1_DR);val |= (1 << 3);writel(val,GPIO1_DR);//取消映射iounmap(IMX6U_CCM_CCGR1);iounmap(SW_MUX_GPIO1_IO03);iounmap(SW_PAD_GPIO1_IO03);iounmap(GPIO1_DR);iounmap(GPIO1_GDIR);//注销字符设备驱动unregister_chrdev(LED_MAJOR,LED_NAME);printk("led_exit\r\n");
}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("mxh");

2、编写测试APP

编写测试APP,led驱动加载成功以后手动创建/dev/led节点,应用APP通过操作/dev/led文件完成对LED设备的控制,向/dev/led文件写0表示关闭LED灯,写1表示打开LED灯,新建ledAPP.c,代码如下

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>#define LEDOFF 0
#define LEDON 1int main(int argc,char *argv[])
{int fd,retvalue;char *filename;unsigned char databuf[1];if(argc != 3){printf("Error Usage!\r\n");return -1;}filename = argv[1];//打开led驱动fd = open(filename,O_RDWR);if(fd < 0){printf("file %s open failed!\r\n",filename);return -1;}databuf[0] = atoi(argv[2]);//向/dev/led文件写入数据retvalue = write(fd,databuf,sizeof(databuf));if(retvalue < 0){printf("LED Control Failed!\r\n");close(fd);return -1;}close(fd);return 0;
}

3、运行测试

3.1、编译驱动程序

编写Makefile文件,代码如下

KERNELDIR := /home/mxh/linux/IMX6ULL/linux/linux-imx-rel_imx_4.1.15_2.1.0_gaCURRENT_PATH := $(shell pwd)obj-m := led.obuild: kernel_moduleskernel_modules:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules 
clean:$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

注意第5行是led.o

输入如下命令编译出驱动模块文件

make -j4

3.2、编译测试APP

输入如下命令测试

arm-linux-gnueabihf-gcc ledAPP.c ledAPP

编译成功后就会生成ledAPP这个应用程序

3.3、运行测试

将编译出来的led.ko和ledAPP这两个文件拷贝到rootfs/lib/modules/4.1.15目录,重启开发板,进入到目录rootfs/lib/modules/4.1.15,输入如下命令加载led.ko驱动模块

depmod             //第一次加载驱动需要运行此命令
modprobe led.ko   //加载驱动

驱动加载成功以后创建/dev/led设备节点

mknod /dev/led.c 200 0

驱动创建成功以后就可以使用ledAPP软件来测试驱动是否正常工作

./ledAPP /dev/led 1    //打开LED灯
./ledAPP /dev/led 0    //关闭LED灯

卸载驱动

rmmod led.ko

其它字符设备都按照这个模板来写

相关文章:

Linux下LED灯驱动模板详解

一、地址映射我们先了解MMU&#xff0c;全称是Memory Manage Unit。在老版本的Linux中要求处理器必须有MMU&#xff0c;但是现在Linux内核已经支持五MMU。MMU主要完成的功能如下&#xff1a;1、完成虚拟空间到物理空间的映射2、内存保护&#xff0c;设置存储器的访问权限&#…...

【C++】你不得不爱的——继承

凡是面向对象的语言&#xff0c;都有三大特性&#xff0c;继承&#xff0c;封装和多态&#xff0c;但并不是只有这三个特性&#xff0c;是因为者三个特性是最重要的特性&#xff0c;那今天我们一起来看继承&#xff01; 目录 1.继承的概念及定义 1.概念 2.继承的定义 2.基类…...

数据库系统概论

文章目录前言基础篇&#xff1a;1-5章第 1 章 绪论1.1 数据库系统概述1.2 数据模型1.3 数据库系统的结构1.4 数据库系统的组成1.5 小结第 2 章 关系数据库1.关系模型1.1 关系数据结构1.2 关系完整性约束实体完整性、参照完整性、用户定义完整性2.关系代数8种关系代数运算符并 ∪…...

32位处理器AM6528BACDXEA、AM6548BACDXEAF基于Arm Cortex-A53内核【工业4.0嵌入式产品应用】

AM6528BACDXEA、AM6548BACDXEAF 处理器是专为满足工业4.0嵌入式产品对处理性能的复杂需求而设计的Arm应用处理器。AM654x和AM652x器件将四个或两个Arm Cortex-A53内核与一个双Arm Cortex-R5F MCU子系统结合在一起。这些包含的功能旨在帮助客户实现终端产品的功能安全目标。它还…...

多图片怎么转换成PDF?这招教你轻松转换

多图片怎么转换成PDF&#xff1f;我们经常会传输图片文件给同事或者朋友&#xff0c;但是多张图片的传输比较麻烦&#xff0c;有的时候传输比较慢&#xff0c;而且也不便于查看&#xff0c;所以我们就可以将需要传输的多张图片转换成一个PDF文件&#xff0c;这样查看文件时就可…...

kali双网卡

先单独开启一个网卡&#xff0c;配置/etc/network/interfaces 修改为如下配置 This file describes the network interfaces available on your system and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* The loopb…...

【wed前端初级课程】第一章 什么是HTML

什么是WEB前端&#xff1f; 简单来说就是网页&#xff0c;只是这个网页它是由多种技术参与制作的&#xff0c;用来向用户展示的页面。 HTML(超文本标签语言)&#xff1a;它决定了网页的结构。 CSS&#xff1a;网页的装饰器。 JavaScript&#xff1a;JavaScrip最初是因为校验…...

sd卡格式化后数据恢复怎么操作

有时候我们需要清空SD卡数据文件&#xff0c;有时候则是因为需要修复SD卡所以需要格式化&#xff0c;但是却被提示无法格式化SD卡。这种情况往往是由于平时SD卡使用时的一些不良习惯或是SD卡中病毒&#xff0c;病毒在运行SD卡中的软件所造成的。那么sd卡格式化后数据恢复怎么操…...

论文阅读笔记|大规模多标签文本分类

多标签文本分类&#xff08;Extreme Multi Label Classification, MLTC&#xff09;是自然语言处理领域中一个十分重要的任务&#xff0c;其旨在从一个给定的标签集合中选取出与文本相关的若干个标签。MLTC可以广泛应用于网页标注&#xff0c;话题识别和情感分析等场景。大规模…...

国际化翻译navigator.language与语种对照表

代码(navigator.language) 语种 字段名 "zh-CN", 中文 Chinese "zh-SG" 马新简体 Chinese_SG "zh-TW","zh-HK", 繁体中文 Chinese_TW "en", "en-US"&#xff08;美国&#xff09;, "en-EG"…...

Matlab进阶绘图第6期—雷达图/蜘蛛图/星图

雷达图&#xff08;Radar Chart&#xff09;&#xff0c;又称星图、蜘蛛图、蜘蛛网图、网络图、Kiviat图等&#xff0c;是一种以从同一点开始的轴上表示的三个以上变量的二维图表的形式&#xff0c;来显示多变量数据的图形方法。 雷达图可以直观地对多维数据集目标对象的性能、…...

Javascript的ES6 class写法和ES5闭包写法性能对比

看到很多闭包写法的函数, 一直怀疑它对性能是否有影响. 还有就是备受推崇的React Hooks函数式写法中出现大量的闭包和临时函数, 我很担心这样会影响性能. 于是, 做了一个实验来做对比. 这个实验很简单, 用md5计算一百万次. 计算过程将结果再放回参数, 这样避免结果没被引用被…...

探秘MySQL——全面了解索引、索引优化规则

文章目录0.什么是索引1.常用索引分类逻辑维度底层数据结构维度物理维度&#xff08;InnoDB&#xff09;2.为什么底层是B树平衡二叉查找树红黑树B树&#xff08;多叉&#xff09;B树&#xff08;多叉&#xff09;3.MySQL索引优化SQL性能分析之explainQ.MySQL如何查看查询是否用到…...

战斗力最强排行榜:10-30人团队任务管理工具

工欲善其事&#xff0c;必先利其器。在高效的任务执行过程中&#xff0c;选择灵活轻便的项目管理工具来提升工作效率、适应快速多变的发展诉求&#xff0c;对团队来说&#xff0c;至关重要。但是如果团队不大&#xff0c;企业对这块的预算又有限&#xff0c;大型的团队任务管理…...

2023-03-09干活小计

强化学习&#xff1a; 强化学习用智能体&#xff08;agent&#xff09;这个概念来表示做决策的机器。 感知、决策和奖励 感知。智能体在…...

基数排序算法

目录&#xff1a;什么是基数排序&#xff1f;基本原理核心思想实现逻辑代码实现复杂度分析总结什么是基数排序&#xff1f; 基数排序&#xff1a;基数排序&#xff08;Radix sort&#xff09;是一种非比较型整数排序算法&#xff0c; 基本思想主要是通过关键字间的比较和移动记…...

项目实战典型案例24——xxljob控制台不打印日志排查

xxljob控制台不打印日志排查一&#xff1a;背景介绍问题截图问题解读二&#xff1a;思路&方案三&#xff1a;过程四&#xff1a;总结一&#xff1a;背景介绍 本篇博客是对xxljob控制台不打印日志排查进行的总结和进行的改进。 目的是将经历转变为自己的经验。通过博客的方…...

旋转框目标检测mmrotate v1.0.0rc1 之RTMDet训练DOTA的官方问题解析整理(四)

关于rotated_rtmdet_l-coco_pretrain-3x-dota_ms.py配置文件的batchsize和学习率设置问题&#xff1a;回答&#xff1a;如何在mmrotate中绘制特征图问题&#xff1a;回答&#xff1a;你好AllieLan&#xff0c;您可以尝试使用https://github.com/open-mmlab/mmyolo/blob/main/de…...

4个顶级的华为/小米/OPPO/Vivo手机屏幕解锁工具软件

有好几次用户发现自己被锁定在他们的华为/小米/OPPO/Vivo设备之外&#xff0c;我们知道这可能是一种非常可怕的体验。在这种情况下&#xff0c;找到安卓手机解锁软件&#xff0c;重新获得手机中重要数据和文件的访问权限。看看这篇文章&#xff0c;因为我们将与您分享什么是解锁…...

华为OD机试题 - 和最大子矩阵(JavaScript)| 机考必刷

更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:和最大子矩阵题目输入输出示例一输入输出说明Code思路版权说明华…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

GruntJS-前端自动化任务运行器从入门到实战

Grunt 完全指南&#xff1a;从入门到实战 一、Grunt 是什么&#xff1f; Grunt是一个基于 Node.js 的前端自动化任务运行器&#xff0c;主要用于自动化执行项目开发中重复性高的任务&#xff0c;例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...

LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》

这段 Python 代码是一个完整的 知识库数据库操作模块&#xff0c;用于对本地知识库系统中的知识库进行增删改查&#xff08;CRUD&#xff09;操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 &#x1f4d8; 一、整体功能概述 该模块…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

深度剖析 DeepSeek 开源模型部署与应用:策略、权衡与未来走向

在人工智能技术呈指数级发展的当下&#xff0c;大模型已然成为推动各行业变革的核心驱动力。DeepSeek 开源模型以其卓越的性能和灵活的开源特性&#xff0c;吸引了众多企业与开发者的目光。如何高效且合理地部署与运用 DeepSeek 模型&#xff0c;成为释放其巨大潜力的关键所在&…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]

报错信息&#xff1a;libc.so.6: cannot open shared object file: No such file or directory&#xff1a; #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

深度解析:etcd 在 Milvus 向量数据库中的关键作用

目录 &#x1f680; 深度解析&#xff1a;etcd 在 Milvus 向量数据库中的关键作用 &#x1f4a1; 什么是 etcd&#xff1f; &#x1f9e0; Milvus 架构简介 &#x1f4e6; etcd 在 Milvus 中的核心作用 &#x1f527; 实际工作流程示意 ⚠️ 如果 etcd 出现问题会怎样&am…...