Rk3568驱动开发_点亮led灯(手动挡)_5

ops/2025/3/4 0:34:24/

1.MMU简介

完成虚拟空间到物理空间的映射
内存保护设立存储器的访问权限,设置虚拟存储空间的缓冲特性

stm32点灯可以直接操作寄存器,但是linux点灯不能直接访问寄存器,linux会使能mmu

在这里插入图片描述

linux中操作的都是虚拟地址,要想访问物理地址0x0a就得先搞清楚0xa对应的虚拟地址

获得物理地址对应的虚拟地址使用ioremap函数,本质是个宏,参数分别是物理地址启始大小,要转换的字节数量

卸载驱动的时候用iounmap()卸载映射

stm32没有这个MMU其控制gpio直接操作寄存器就行,在linux上由于这个内存映射在,需要知道真实物理地址,反推其虚拟地址才能像stm32一样操作寄存器

linux做驱动有配置设备树更高级的操作方式,像这种操作寄存器的好似手动档

2.代码:

驱动:

#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 PMU_GRF_BASE						      (0xFDC20000)
#define PMU_GRF_GPIO0C_IOMUX_L				(PMU_GRF_BASE + 0x0010)
#define PMU_GRF_GPIO0C_DS_0					  (PMU_GRF_BASE + 0X0090)
#define GPIO0_BASE						        (0xFDD60000)
#define GPIO0_SWPORT_DR_H				      (GPIO0_BASE + 0X0004)
#define GPIO0_SWPORT_DDR_H				    (GPIO0_BASE + 0X000C)/* 映射后的寄存器虚拟地址指针 */
static void __iomem *PMU_GRF_GPIO0C_IOMUX_L_PI;
static void __iomem *PMU_GRF_GPIO0C_DS_0_PI;
static void __iomem *GPIO0_SWPORT_DR_H_PI;
static void __iomem *GPIO0_SWPORT_DDR_H_PI;static int led_open(struct inode* inode, struct file* filp){return 0;
}static int led_release(struct inode* inode, struct file* filp){return 0;
}static ssize_t led_write(struct file* filp, const char __user* buf, size_t count, loff_t* ppos){return 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){ // 入口// 初始化led灯int ret = 0;u32 val = 0;PMU_GRF_GPIO0C_IOMUX_L_PI = ioremap(PMU_GRF_GPIO0C_IOMUX_L, 4);PMU_GRF_GPIO0C_DS_0_PI = ioremap(PMU_GRF_GPIO0C_DS_0, 4);GPIO0_SWPORT_DR_H_PI = ioremap(GPIO0_SWPORT_DR_H, 4);GPIO0_SWPORT_DDR_H_PI = ioremap(GPIO0_SWPORT_DDR_H, 4);// 初始化// 设置GPIO0_c0为GPIO功能val = readl(PMU_GRF_GPIO0C_IOMUX_L_PI);val &= ~(0x7 << 0); //最低三位置0val |= ((0x7 << 16) | (0x0 << 0)); // 16 17 18位置1其他不变,bit2:0:0,用作GPIO0_C0writel(val, PMU_GRF_GPIO0C_IOMUX_L_PI);// 设置GPIO_C0驱动能力为level5val = readl(PMU_GRF_GPIO0C_DS_0_PI);val &= ~(0x3f << 0);  // 0 ~ 5置0val |= ((0x3f << 16) | (0x3f << 0)); // 16 ~ 21置1,0~5置1同时用作GPIO0c0writel(val, PMU_GRF_GPIO0C_DS_0_PI);// 设置GPIOO0_c0为输出val = readl(GPIO0_SWPORT_DDR_H_PI);val &= ~(0x1 << 0); // 0置0val |= ((0x1 << 16) | (0x1 << 0)); // 16置1,0置1writel(val, GPIO0_SWPORT_DDR_H_PI);// 设置GPIO_c0为低电平,关闭LEDval = readl(GPIO0_SWPORT_DR_H_PI);val &= ~(0x1 << 0);val |= ((0x1 << 16) | (0x0 << 0));writel(val, GPIO0_SWPORT_DR_H_PI);// 开灯val = readl(GPIO0_SWPORT_DR_H_PI);val &= ~(0X1 << 0); /* bit0 清零*/val |= ((0X1 << 16) | (0X1 << 0));	/* bit16 置1,允许写bit0,bit0,高电平*/ writel(val, GPIO0_SWPORT_DR_H_PI);  // 注册字符设备ret = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);if(ret < 0){printk("register chrdev failed!\r\n");return -EIO;}printk("led_init\r\n");return 0;
}static void __exit led_exit(void){ // 出口u32 val = 0;// 关灯val = readl(GPIO0_SWPORT_DR_H_PI);val &= ~(0X1 << 0); /* bit0 清零*/val |= ((0X1 << 16) | (0X0 << 0));	/* bit16 置1,允许写bit0,bit0,低电平	*/writel(val, GPIO0_SWPORT_DR_H_PI); // 取消地址映射iounmap(PMU_GRF_GPIO0C_IOMUX_L_PI);iounmap(PMU_GRF_GPIO0C_DS_0_PI);iounmap(GPIO0_SWPORT_DR_H_PI);iounmap(GPIO0_SWPORT_DDR_H_PI);// 注销unregister_chrdev(LED_MAJOR, LED_NAME);printk("led_exit\r\n");}module_init(led_init);
module_exit(led_exit);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Narnat");

ioremap(PMU_GRF_GPIO0C_IOMUX_L, 4);将物理地址转虚拟内存

在程序挂载时初始化一些寄存器,并点亮led灯,卸载时关闭led灯

3.现象:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


http://www.ppmy.cn/ops/162909.html

相关文章

C++二分图

二分图&#xff08;Bipartite Graph&#xff09;是一种特殊的图结构&#xff0c;其顶点可以分成两个互不相交的集合&#xff0c;使得每条边的两个顶点分别属于这两个集合。二分图在匹配问题&#xff08;如任务分配、婚姻匹配&#xff09;和网络流算法中有重要应用。 核心概念 …

《机器学习数学基础》补充资料:可逆矩阵的手工计算方法和总结

《机器学习数学基础》第2章2.3.1节阐述了可逆矩阵的定义、性质&#xff0c;并演示了Python中的计算函数及其应用。 本文是对书中这部分内容的补充&#xff0c;主要是说明如何用手工计算的方法得到常用矩阵的逆矩阵&#xff08;如果可逆&#xff09;。 若一个矩阵存在逆矩阵&am…

spring注解开发(Spring整合JUnit+MyBatis)(7)

目录 一、项目环境初始化。 &#xff08;1&#xff09;数据库与数据表。 &#xff08;2&#xff09;pom文件中的核心依赖坐标。 &#xff08;3&#xff09;实体类。 &#xff08;4&#xff09;service层。 &#xff08;5&#xff09;dao层。&#xff08;Mapper代理模式&#xf…

Android Binder 用法详解

Binder 是 Android 系统中的一种进程间通信&#xff08;IPC&#xff09;机制&#xff0c;它允许不同进程之间进行高效通信。Binder 在 Android 系统中被广泛使用&#xff0c;例如在 Activity 与 Service 的交互中。 Binder 的基本组成 实现 Binder 通信通常包含以下几个关键部…

如何在netlify一键部署静态网站

1. 准备你的项目 确保你的静态网站文件&#xff08;如 HTML、CSS、JavaScript、图片等&#xff09;都在一个文件夹中。通常&#xff0c;项目结构如下&#xff1a; my-static-site/ ├── index.html ├── styles/ │ └── styles.css └── scripts/└── script.js…

分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机多特征分类预测

分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机多特征分类预测 目录 分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机多特征分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机…

矩阵的奇异值(SVD)分解和线性变换

矩阵的奇异值&#xff08;SVD&#xff09;分解和线性变换 SVD定义 奇异值分解&#xff08;Singular Value Decomposition&#xff0c;简称 SVD&#xff09;是一种重要的线性代数工具&#xff0c;能够将任意矩阵 ( A ∈ R m n \mathbf{A} \in \mathbb{R}^{m \times n} A∈Rmn…

ubuntu中ollama设置记录

自己同一台电脑主机安装3080和3090显卡&#xff0c;测试发现ollama只默认跑在3090上&#xff1b;故查看一下设置&#xff0c;成功也把3080也运行起来了。 原因如下&#xff1a; 开始设置记录&#xff1a; Environment Variables: OLLAMA_DEBUG 作用&#xff1a;显示额外的调试…