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

Linux驱动开发(二)--字符设备驱动开发提升 LED驱动开发实验

1、地址映射

在编写驱动之前,需要知道MMU,也就是内存管理单元,在老版本的 Linux 中要求处理器必须有 MMU,但是现在Linux 内核已经支持无 MMU 的处理器了。
MMU的功能如下:
  • 完成虚拟空间到物理空间的映射
  • 内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性

 我们重点来讲第一点,物理空间映射,虚拟空间到物理空间的映射,也叫做地址映射。
先了解虚拟地址(VA,Virtual Address)物理地址(PA,PhyscicalAddress)这两个概念,对于 32 位 的处理器来说,虚拟地址范围是 2^32=4GB,我们的开发板上有 512MB DDR3,这 512MB 的 内存就是物理内存,经过 MMU 可以将其映射到整个 4GB 的虚拟空间。

所以后续我们访问相关引脚进行操作的时候,如果没有开启 MMU 的话 直接向 0X020E0068 这个寄存器地址写入数据就可以配置 GPIO1_IO03 的复用功能。现在开启 了 MMU,并且设置了内存映射,因此就不能直接0X020E0068 这个地址写入数据了。我们必须得到 0X020E0068 这个物理地址在 Linux 系统里面对应的虚拟地址,这里就涉及到了物理内 存和虚拟内存之间的转换,需要用到两个函数:ioremap iounmap
总得来说也就是上面的步骤多加了一个IO映射的一个过程,仅此而已。

 

2、引脚操作回顾

2.1 STM32 GPIO回顾

主要是通过流程来作为思维的引导。
我们一般拿到一款全新的芯片,第一个要做的事情的就是驱动其 GPIO,控制其 GPIO 输出高低电平,我们学习 I.MX6U 也一样的,先来学习一下 I.MX6U GPIO。在学习 I.MX6U 的 GPIO 之前,我们先来回顾一下 STM32 GPIO 初始化(如果没有学过 STM32 就不用回顾了),我们以最常见的 STM32F103 为例来看一下 STM32 GPIO 初始化,示例代码如下:

void LED_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能 PB 端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PB5 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化 GPIOB.5GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
}

看不止是看代码,要看流程,1.使能时钟  2.初始化GPIO,比如上下拉、速度  3.io口是否需要复用 4.GPIO输出高电平还是低电平 这是流程。

我们还需要了解相关位操作,具体如下所示:

分别是写(设置),读(清除)

val = data_reg;
val = val | (1<<n);
data_reg = val;

上述为写操作,具体涉及 “ | ”,不影响其他位。

val = data_reg;
val = val & ~(1<<n);
data_reg = val;

上述为读操作,具体涉及 “ ~  “  ” & ”,不影响其他位。

3、编译驱动程序

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>#define LED_MAJOR 200 /* 主设备号 */
#define LED_NAME "led" /* 设备名字 */#define LEDOFF 0 /* 关灯 */
#define LEDON 1 /* 开灯 */#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;/** @description : LED 打开/关闭* @param - sta : LEDON(0) 打开 LED,LEDOFF(1) 关闭 LED* @return : 无*/
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 *inodp, struct file *filp)
{return 0;
}static ssize_t led_read (struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}/*
* @description : 向设备写数据
* @param - filp : 设备文件,表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数,如果为负值,表示写入失败
*/
static ssize_t led_write (struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{int retvalue = 0;unsigned char databuf[1];unsigned char ledstat;retvalue = copy_from_user(databuf,buf,cnt);if(retvalue < 0){printk("kernel write failed\r\n");return -EFAULT;}ledstat = databuf[0];if(ledstat == LEDON){led_switch(LEDON);}else if(ledstat == LEDOFF){led_switch(LEDOFF);}return 0;
}/** @description : 关闭/释放设备* @param - filp : 要关闭的设备文件(文件描述符)* @return : 0 成功;其他 失败*/
static int led_release (struct inode *inodp, struct file *filp)
{return 0;
}static struct file_operations led_fops = {.owner   = THIS_MODULE,.open    = led_open,.read    = led_read,.write   = led_write,.release = led_release,
};static int __init led_init(void){int retvalue = 0;u32 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);/* 2、使能 GPIO1 时钟 */val = readl(IMX6U_CCM_CCGR1);val &= ~(3 << 26); /* 清除以前的设置 */val |= (3 << 26); /* 设置新值 */writel(val, IMX6U_CCM_CCGR1);/* 3、设置 GPIO1_IO03 的复用功能,将其复用为* GPIO1_IO03,最后设置 IO 属性。*/writel(5, SW_MUX_GPIO1_IO03);/* 寄存器 SW_PAD_GPIO1_IO03 设置 IO 属性 */writel(0x10B0, SW_PAD_GPIO1_IO03);/* 4、设置 GPIO1_IO03 为输出功能 */val = readl(GPIO1_GDIR);val &= ~(1 << 3); /* 清除以前的设置 */val |= (1 << 3); /* 设置为输出 */writel(val, GPIO1_GDIR);/* 5、默认关闭 LED */val = readl(GPIO1_DR);val |= (1 << 3); writel(val, GPIO1_DR);//设备号 名字 字符模型驱动的一个结构体retvalue = register_chrdev(LED_MAJOR,LED_NAME,&led_fops);if(retvalue < 0){// exit}return 0;
}static void __exit led_exit(void){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);
}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("7yewh");

相关文章:

  • 18个机器学习核心算法模型总结
  • 2025计算机毕业设计选题题目推荐-毕设题目汇总大全
  • 智慧校园综合管理系统:打造高效智慧的学校管理平台
  • 契约锁电子签章平台 add 远程命令执行漏洞复现(XVE-2023-23720)
  • 关于面试被面试官暴怼:“几年研究生白读” 的前因后果
  • React获取DOM节点
  • 【Android】基于webView打造富文本编辑器(H5)
  • 网络故障排查-TCP标志位
  • VB.net调用VC DLL(二)
  • AD域离线破解新思路:Trustroasting和TimeRoasting
  • HTML(13)——显示模式
  • 渗透测试基础(四) MS08-067 漏洞攻击
  • InPixio Photo Cutter v10 解锁版安装教程 (懒人抠图工具)
  • KEYSIGHT是德E5063A网络分析仪
  • 网络编程面试题
  • 「面试题」如何实现一个圣杯布局?
  • 【跃迁之路】【444天】程序员高效学习方法论探索系列(实验阶段201-2018.04.25)...
  • 4. 路由到控制器 - Laravel从零开始教程
  • axios 和 cookie 的那些事
  • FineReport中如何实现自动滚屏效果
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • Logstash 参考指南(目录)
  • npx命令介绍
  • 不上全站https的网站你们就等着被恶心死吧
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 翻译--Thinking in React
  • 给新手的新浪微博 SDK 集成教程【一】
  • 好的网址,关于.net 4.0 ,vs 2010
  • 机器学习中为什么要做归一化normalization
  • 那些被忽略的 JavaScript 数组方法细节
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 深入浅出webpack学习(1)--核心概念
  • 使用权重正则化较少模型过拟合
  • 为视图添加丝滑的水波纹
  • 小程序开发中的那些坑
  • 一些基于React、Vue、Node.js、MongoDB技术栈的实践项目
  • ​【数据结构与算法】冒泡排序:简单易懂的排序算法解析
  • ​渐进式Web应用PWA的未来
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #Java第九次作业--输入输出流和文件操作
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (1) caustics\
  • (35)远程识别(又称无人机识别)(二)
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (Git) gitignore基础使用
  • (html转换)StringEscapeUtils类的转义与反转义方法
  • (iPhone/iPad开发)在UIWebView中自定义菜单栏
  • (LeetCode C++)盛最多水的容器
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (二)正点原子I.MX6ULL u-boot移植
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (论文阅读30/100)Convolutional Pose Machines
  • (面试必看!)锁策略
  • (转载)OpenStack Hacker养成指南
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换