0722_驱动3 地址映射驱动点灯

一、为什么需要地址映射

在芯片手册上查看到的地址属于物理地址,在硬件层

在内核空间地址属于虚拟地址,在内核层

在驱动中,操作的是虚拟地址

需要将物理地址《--mmu内存管理单元--》虚拟地址映射

二、映射API接口

void *ioremap(unsigned long port, unsigned long size)#include <linux/io.h>

函数功能:将物理地址映射为虚拟地址

参数:

        port:物理地址

        size:映射大小

返回值: 成功返回映射虚拟地址首地址 失败返回NULL

三、取消映射API接口

void iounmap(volatile void *addr)

函数功能:取消地址映射

参数:

        addr:取消映射虚拟地址首地址

返回值:无

四、编写驱动程序

myled.h:

#ifndef __MYLED_H__
#define __MYLED_H__enum led{LED1, //0LED2, //1LED3, //2
};typedef struct {volatile unsigned int MODER;   // 0x00volatile unsigned int OTYPER;  // 0x04volatile unsigned int OSPEEDR; // 0x08volatile unsigned int PUPDR;   // 0x0Cvolatile unsigned int IDR;     // 0x10volatile unsigned int ODR;     // 0x14volatile unsigned int BSRR;    // 0x18volatile unsigned int LCKR;    // 0x1C volatile unsigned int AFRL;    // 0x20 volatile unsigned int AFRH;    // 0x24volatile unsigned int BRR;     // 0x28volatile unsigned int res;volatile unsigned int SECCFGR; // 0x30
}gpio_t;#define  GPIOE   (0x50006000) //GPIOE组基地址
#define  GPIOF   (0x50007000) //GPIOF组基地址
#define RCC_MP_AHB4ENSETR 0x50000A28//RCC_MP_AHB4ENSETR寄存器地址#endif 

demo.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "myled.h"#define CNAME "myled"
unsigned int major = 0;
char kbuf[128] = {};
unsigned int* rcc_virt = NULL; //RCC虚拟地址
gpio_t* gpioe_virt = NULL; //gpioe组虚拟地址
gpio_t*gpiof_virt = NULL; //gpiof组虚拟地址#define LED1_ON (gpioe_virt->ODR |= (0x1 << 10)) //LED1点亮
#define LED1_OFF (gpioe_virt->ODR &= (~(0x1 << 10))) //LED1熄灭#define LED2_ON (gpiof_virt->ODR |= (0x1 << 10)) //LED2点亮
#define LED2_OFF (gpiof_virt->ODR &= (~(0x1 << 10))) //LED2熄灭#define LED3_ON (gpioe_virt->ODR |= (0x1 << 8)) //LED3点亮
#define LED3_OFF (gpioe_virt->ODR &= (~(0x1 << 8))) //LED3熄灭int myled_open(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff)
{int ret;printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);//如果用户空间想写的大小256个字节,大于内核空间的大小128个字节,需要更正用户空间写的大小if(size > sizeof(kbuf)) size = sizeof(kbuf);ret = copy_from_user(kbuf,ubuf,size); //将用户空间的数据,写入到内核空间if(ret){printk("copy from user is error\n");return -EIO;}//kbuf[0] = 0 操作LED1  kbuf[0] = 1 操作LED2  kbuf[0] = 2 操作LED3//kbuf[1] = 0 LED熄灭 kbuf[1] = 1 LED点亮switch (kbuf[0]){case LED1: //操作LED1kbuf[1] == 0 ? LED1_OFF : LED1_ON;break;case LED2: //操作LED2kbuf[1] == 0 ? LED2_OFF : LED2_ON;break;  case LED3: //操作LED3kbuf[1] == 0 ? LED3_OFF : LED3_ON;break;   }return size; 
}
int myled_close(struct inode *inode, struct file *file)
{printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0; 
}//操作方法结构体
const struct file_operations fops = {.open = myled_open,.write = myled_write,.release = myled_close,
};//入口函数
static int __init demo_init(void)
{  //注册字符设备驱动major = register_chrdev(0,CNAME,&fops);if(major < 0){printk("register chrdev is error\n");return -EIO;}printk("major = %d\n",major);//RCC_MP_AHB4ENSETR寄存器地址映射rcc_virt = ioremap(RCC_MP_AHB4ENSETR,4);if(rcc_virt == NULL){printk("rcc ioremap is error\n");return -EIO;}//GPIOE组寄存器地址映射gpioe_virt = ioremap(GPIOE,sizeof(gpio_t));if(gpioe_virt == NULL){printk("gpioe_virtr ioremap is error\n");return -EIO;}//GPIOF组寄存器地址映射gpiof_virt = ioremap(GPIOF,sizeof(gpio_t));if(gpiof_virt == NULL){printk("gpiof_virtr ioremap is error\n");return -EIO;}//LED1初始化//使能GPIOE组控制器   rcc_virt[4] = 1*rcc_virt |= (0x1 << 4);//设置PE10引脚为输出模式 MODER[21:20] = 01gpioe_virt->MODER &= (~(0x3 << 20));gpioe_virt->MODER |= (0x1 << 20);//设置PE10引脚输出低电平,LED1熄灭 ODR[10] = 0gpioe_virt->ODR &= (~(0x1 << 10));//LED2初始化//使能GPIOE组控制器   rcc_virt[5] = 1*rcc_virt |= (0x1 << 5);//设置PF10引脚为输出模式 MODER[21:20] = 01gpiof_virt->MODER &= (~(0x3 << 20));gpiof_virt->MODER |= (0x1 << 20);//设置PF10引脚输出低电平,LED2熄灭 ODR[10] = 0gpiof_virt->ODR &= (~(0x1 << 10));   //LED3初始化//设置PE8引脚为输出模式 MODER[17:16] = 01gpioe_virt->MODER &= (~(0x3 << 16));gpioe_virt->MODER |= (0x1 << 16);//设置PE8引脚输出低电平,LED3熄灭 ODR[8] = 0gpioe_virt->ODR &= (~(0x1 << 8));return 0; //函数的返回值
}//出口函数
static void __exit demo_exit(void)
{iounmap(gpioe_virt);iounmap(gpiof_virt);iounmap(rcc_virt);//注销字符设备驱动unregister_chrdev(major,CNAME);
}module_init(demo_init); //指定入口地址
module_exit(demo_exit); //指定出口地址
MODULE_LICENSE("GPL"); //许可证,遵循GPL协议

应用层程序:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "myled.h"int main(int argc,const char * argv[])
{int fd = -1;char buf[128] = "";fd = open("/dev/myled",O_RDWR); //打开if(fd == -1){perror("open is error\n");exit(1);}while(1){buf[0] = LED1; //操作LED1灯write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间buf[1] = 1; //LED1灯点亮write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间sleep(1);buf[1] = 0; //LED1灯熄灭write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间sleep(1);buf[0] = LED2; //操作LED2灯write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间buf[1] = 1; //LED2灯点亮write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间sleep(1);buf[1] = 0; //LED2灯熄灭write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间sleep(1);buf[0] = LED3; //操作LED3灯write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间buf[1] = 1; //LED3灯点亮write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间sleep(1);buf[1] = 0; //LED3灯熄灭write(fd,buf,sizeof(buf)); //将用户空间的数据,写入内核空间sleep(1);}close(fd);return 0;
}

 五、测试步骤

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

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

相关文章

backtrace

介绍 arm平台的调用栈与x86平台的调用栈大致相同&#xff0c;稍微有些区别&#xff0c;主要在于栈帧的压栈内容和传参方式不同。在arm平台的不同程序&#xff0c;采用的编译选项不同&#xff0c;程序运行期间的栈帧也会不同。有些工具在对arm的调用栈回溯时&#xff0c;可能会…

电商项目之如何判断线程池是否执行完所有任务

文章目录 1 问题背景2 前言3 4种常用的方法4 代码4.1 isTerminated()4.2 线程池的任务总数是否等于已执行的任务数4.3 CountDownLatch计数器4.4 CyclicBarrier计数器 1 问题背景 真实生产环境的电商项目&#xff0c;常使用线程池应用于执行大批量操作达到高性能的效果。应用场景…

Dify中语音和文字间转换问题的一种暂时注释方式

本文主要解释了Dify中语音和文字间转换可能会遇到的问题&#xff0c;并给出了一种暂时注释的解决方案。 一.文本转语音可能问题 本地部署文本转语音时&#xff0c;如果遇到如下问题&#xff0c;安装ffmpeg即可。但是如果安装后&#xff0c;重启系统还是遇到这个问题该如何办&…

分库分表——从理论到最佳实践

目录 1、为什么要分库分表&#xff1f;2、切分方案有哪些&#xff1f;2.1 分库2.1.1 垂直分库2.1.2 水平分库 2.2 分表2.2.1 垂直分表2.2.2 水平分表 2.3 分库分表 3、数据水平分片方法3.1 Hash分片3.2 一致性Hash分片3.3 Range分片 4、分库分表的挑战4.1 分布式id4.2 分布式事…

LLM:归一化 总结

一、Batch Normalization 原理 Batch Normalization 是一种用于加速神经网络训练并提高稳定性的技术。它通过在每一层网络的激活值上进行归一化处理&#xff0c;使得每一层的输入分布更加稳定&#xff0c;从而加速训练过程&#xff0c;并且减轻了对参数初始化的依赖。 公式 …

分类模型——逻辑回归和Fisher线性判别分析

个人学习笔记&#xff0c;课程为数学建模清风付费课程 目录 一、引例 二、逻辑回归 2.1线性概率模型 2.2Fisher线性判别分析 2.3两点分布&#xff08;伯努利分布&#xff09; 2.4连接函数的取法 2.5如何求解 2.6如何用于分类 三、SPSS 3.1二元分类 3.1.1逻辑回…

MySQL内如何改变编码格式

查找数据库的编码格式&#xff1a; show variables like character%;具体内容时这些 在创建表时设定编码格式&#xff1a; create database <要创建的数据库的名字> charset utf8; 修改数据库默认编码&#xff1a; set character_set_databaseutf8mb4; character_…

eclipse ui bug

eclipse ui bug界面缺陷&#xff0c;可能项目过多&#xff0c;特别maven项目过多&#xff0c;下载&#xff0c;自动编译&#xff0c;加载更新界面异常 所有窗口死活Restore不回去了 1&#xff09;尝试创建项目&#xff0c;还原界面&#xff0c;失败 2&#xff09;关闭所有窗口&…

将TP5链接导入笔影个人博客代码

首先第一步&#xff0c;打开界面 第二步&#xff0c;这里卡住了&#xff0c;无法看到源代码&#xff0c;我们使用其他软件看看源代码 调试乱码&#xff0c;因为没有找到相应的笔影个人博客源码。源码在桌面上。询问百度&#xff0c;说了有的没的一大堆。 尝试的结果就是失败…

时间复杂度与O(n)

文章目录 1 复杂度分析1.1 时间复杂度1.1.1 循环执行次数1.1.2 大O(n)表示法 1.2 空间复杂度 1 复杂度分析 1.1 时间复杂度 ​ 时间复杂度用来表示算法运行时间的长短&#xff0c;用来定性的描述程序的运行时间。要了解时间复杂度&#xff0c;我们需要先了解程序执行的次数。…

机器学习(二十二):精度和召回率

一、倾斜数据集 倾斜数据集&#xff1a;一个数据集中的正面和负面例子的比例非常不平衡&#xff0c;比如数据集中&#xff0c;结果为1的占比20%&#xff0c;结果为0的占比80% 例子&#xff1a;如果数据集的结果中只有0.5%是1&#xff0c;其余结果是0。有一个模型的预测准确度…

【信创】udisk2服务异常导致U盘使用中自动移除问题解决

原文链接&#xff1a;【信创】udisk2服务异常导致U盘使用中自动移除问题解决 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在信创终端操作系统上由于udisk2服务异常导致U盘等移动设备在使用中自动移除问题的排查文章。udisk2是一个管理存储设备的服务&#xf…

【计算机网络】OSPF单区域实验

一&#xff1a;实验目的 1&#xff1a;掌握在路由器上配置OSPF单区域。 2&#xff1a;学习OSPF协议的原理&#xff0c;及其网络拓扑结构改变后的变化。 二&#xff1a;实验仪器设备及软件 硬件&#xff1a;RCMS交换机、网线、内网网卡接口、Windows 2019操作系统的计算机等。…

Vue 3 实现左侧列表点击跳转滚动到右侧对应区域的功能

使用 Vue 3 实现左侧列表点击跳转到右侧对应区域的功能 1. 引言 在这篇博客中&#xff0c;我们将展示如何使用 Vue 3 实现一个简单的页面布局&#xff0c;其中左侧是一个列表&#xff0c;点击列表项时&#xff0c;右侧会平滑滚动到对应的内容区域。这种布局在很多应用场景中都…

Llama 3.1 405B 详解

2024 年 7 月 23 日星期二&#xff0c;Meta 宣布推出 Llama 3.1&#xff0c;这是其Llama 系列大型语言模型 (LLM)的最新版本。虽然只是对 Llama 3 模型进行小幅更新&#xff0c;但它特别引入了Llama 3.1 405B——一个 4050 亿参数的模型&#xff0c;这是迄今为止世界上最大的开…

运行ruoyi

nacos 数据库配置 修改nacos/conf/application.properties 单机版运行 startup.cmd -m standalone redis 运行后端 运行gateway,auth,modules/system模块 可能遇到的问题&#xff1a;端口正在使用 解决 netstat -ano | findstr 9200 taskkill -pid 18284 -f

JAVA同城圈子达人交友系统源码支持微信小程序+公众号+H5+APP

&#x1f308; 同城圈子达人交友系统&#xff0c;遇见志同道合的TA&#xff01; &#x1f389; 开篇&#xff1a;告别孤单&#xff0c;同城圈子等你来探索&#xff01; 在这个快节奏的城市生活中&#xff0c;你是否常常感到孤独&#xff0c;渴望找到一群志同道合的朋友&#…

Elasticsearch基础(六):使用Kibana Lens进行数据可视化

文章目录 使用Kibana Lens进行数据可视化 一、进入Kibana Lens 二、基础可视化 1、指标可视化 2、垂直堆积条形图 3、表格 三、高级可视化 1、多图层和索引 2、子桶 3、树状图 使用Kibana Lens进行数据可视化 一、进入Kibana Lens 在Kibana主页&#xff0c;单击页面…

【资料分享】2024钉钉杯大数据挑战赛A题思路解析+代码演示

2024第三届钉钉杯大学生大数据挑战赛今天已经开赛&#xff0c;【A题】思路解析代码&#xff0c;资料预览&#xff1a;

【JAVA学习笔记】找不到依赖项 ‘org.springframework.boot:spring-boot-starter-web:3.0.5‘

如果环境都是跟着教程配的话&#xff0c;并且上网搜了一圈询问gpt都没发现对应长得像的错误&#xff0c;那么试试**刷新一下Maven项目**&#xff0c;可能问题就自己解决了。如果这样解决不了再查到底是什么地方没有配置对。&#xff08;我第一次遇到这个问题的时候搜了半天都不…