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,全称是Memory Manage Unit。在老版本的Linux中要求处理器必须有MMU,但是现在Linux内核已经支持五MMU。MMU主要完成的功能如下:1、完成虚拟空间到物理空间的映射2、内存保护,设置存储器的访问权限&#…...
【C++】你不得不爱的——继承
凡是面向对象的语言,都有三大特性,继承,封装和多态,但并不是只有这三个特性,是因为者三个特性是最重要的特性,那今天我们一起来看继承! 目录 1.继承的概念及定义 1.概念 2.继承的定义 2.基类…...
数据库系统概论
文章目录前言基础篇: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?我们经常会传输图片文件给同事或者朋友,但是多张图片的传输比较麻烦,有的时候传输比较慢,而且也不便于查看,所以我们就可以将需要传输的多张图片转换成一个PDF文件,这样查看文件时就可…...
kali双网卡
先单独开启一个网卡,配置/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前端? 简单来说就是网页,只是这个网页它是由多种技术参与制作的,用来向用户展示的页面。 HTML(超文本标签语言):它决定了网页的结构。 CSS:网页的装饰器。 JavaScript:JavaScrip最初是因为校验…...
sd卡格式化后数据恢复怎么操作
有时候我们需要清空SD卡数据文件,有时候则是因为需要修复SD卡所以需要格式化,但是却被提示无法格式化SD卡。这种情况往往是由于平时SD卡使用时的一些不良习惯或是SD卡中病毒,病毒在运行SD卡中的软件所造成的。那么sd卡格式化后数据恢复怎么操…...
论文阅读笔记|大规模多标签文本分类
多标签文本分类(Extreme Multi Label Classification, MLTC)是自然语言处理领域中一个十分重要的任务,其旨在从一个给定的标签集合中选取出与文本相关的若干个标签。MLTC可以广泛应用于网页标注,话题识别和情感分析等场景。大规模…...
国际化翻译navigator.language与语种对照表
代码(navigator.language) 语种 字段名 "zh-CN", 中文 Chinese "zh-SG" 马新简体 Chinese_SG "zh-TW","zh-HK", 繁体中文 Chinese_TW "en", "en-US"(美国), "en-EG"…...
Matlab进阶绘图第6期—雷达图/蜘蛛图/星图
雷达图(Radar Chart),又称星图、蜘蛛图、蜘蛛网图、网络图、Kiviat图等,是一种以从同一点开始的轴上表示的三个以上变量的二维图表的形式,来显示多变量数据的图形方法。 雷达图可以直观地对多维数据集目标对象的性能、…...
Javascript的ES6 class写法和ES5闭包写法性能对比
看到很多闭包写法的函数, 一直怀疑它对性能是否有影响. 还有就是备受推崇的React Hooks函数式写法中出现大量的闭包和临时函数, 我很担心这样会影响性能. 于是, 做了一个实验来做对比. 这个实验很简单, 用md5计算一百万次. 计算过程将结果再放回参数, 这样避免结果没被引用被…...
探秘MySQL——全面了解索引、索引优化规则
文章目录0.什么是索引1.常用索引分类逻辑维度底层数据结构维度物理维度(InnoDB)2.为什么底层是B树平衡二叉查找树红黑树B树(多叉)B树(多叉)3.MySQL索引优化SQL性能分析之explainQ.MySQL如何查看查询是否用到…...
战斗力最强排行榜:10-30人团队任务管理工具
工欲善其事,必先利其器。在高效的任务执行过程中,选择灵活轻便的项目管理工具来提升工作效率、适应快速多变的发展诉求,对团队来说,至关重要。但是如果团队不大,企业对这块的预算又有限,大型的团队任务管理…...
2023-03-09干活小计
强化学习: 强化学习用智能体(agent)这个概念来表示做决策的机器。 感知、决策和奖励 感知。智能体在…...
基数排序算法
目录:什么是基数排序?基本原理核心思想实现逻辑代码实现复杂度分析总结什么是基数排序? 基数排序:基数排序(Radix sort)是一种非比较型整数排序算法, 基本思想主要是通过关键字间的比较和移动记…...
项目实战典型案例24——xxljob控制台不打印日志排查
xxljob控制台不打印日志排查一:背景介绍问题截图问题解读二:思路&方案三:过程四:总结一:背景介绍 本篇博客是对xxljob控制台不打印日志排查进行的总结和进行的改进。 目的是将经历转变为自己的经验。通过博客的方…...
旋转框目标检测mmrotate v1.0.0rc1 之RTMDet训练DOTA的官方问题解析整理(四)
关于rotated_rtmdet_l-coco_pretrain-3x-dota_ms.py配置文件的batchsize和学习率设置问题:回答:如何在mmrotate中绘制特征图问题:回答:你好AllieLan,您可以尝试使用https://github.com/open-mmlab/mmyolo/blob/main/de…...
4个顶级的华为/小米/OPPO/Vivo手机屏幕解锁工具软件
有好几次用户发现自己被锁定在他们的华为/小米/OPPO/Vivo设备之外,我们知道这可能是一种非常可怕的体验。在这种情况下,找到安卓手机解锁软件,重新获得手机中重要数据和文件的访问权限。看看这篇文章,因为我们将与您分享什么是解锁…...
华为OD机试题 - 和最大子矩阵(JavaScript)| 机考必刷
更多题库,搜索引擎搜 梦想橡皮擦华为OD 👑👑👑 更多华为OD题库,搜 梦想橡皮擦 华为OD 👑👑👑 更多华为机考题库,搜 梦想橡皮擦华为OD 👑👑👑 华为OD机试题 最近更新的博客使用说明本篇题解:和最大子矩阵题目输入输出示例一输入输出说明Code思路版权说明华…...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
Qt Widget类解析与代码注释
#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码,写上注释 当然可以!这段代码是 Qt …...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)
一、OpenBCI_GUI 项目概述 (一)项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台,其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言,首次接触 OpenBCI 设备时,往…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...
