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

server/2025/2/27 10:02:59/

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/server/171003.html

相关文章

动态规划_01背包

2915. 和为目标值的最长子序列的长度 给你一个下标从 0 开始的整数数组 nums 和一个整数 target 。 返回和为 target 的 nums 子序列中&#xff0c;子序列 长度的最大值 。如果不存在和为 target 的子序列&#xff0c;返回 -1 。 子序列 指的是从原数组中删除一些或者不删除任…

TinyEngine v2.2版本发布:支持页面嵌套路由,提升多层级路由管理能力开发分支调整

2025年春节假期已过&#xff0c;大家都带着慢慢的活力回到了工作岗位。为了让大家在新的一年继续感受到 Tiny Engine 的成长与变化&#xff0c;我们很高兴地宣布&#xff1a;TinyEngine v2.2版本正式发布&#xff01;本次更新带来了重要的功能增强------页面支持嵌套路由&#…

【网络系列】SSRF攻击

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

MySQL数据库入门到大蛇尚硅谷宋红康老师笔记 高级篇 part 4

第04章_逻辑架构 1. 逻辑架构剖析 首先MySQL是典型的C/S架构&#xff0c;即Client/Server架构&#xff0c;服务器端程序使用的mysqld。 不论客户端进程和服务器进程是采用哪种方式进行通信&#xff0c;最后实现的效果都是&#xff1a;客户端进程向服务器进程发送一段文本&…

华为云设备接入

原生接入方式 支持设备通过MQTT、HTTP、LWM2M、CoAP、WebSocket、QUIC等通用通信协议对接物联网平台。 MQTT(S)协议接入 概述 MQTT消息由固定报头&#xff08;Fixed header&#xff09;、可变报头&#xff08;Variable header&#xff09;和有效载荷&#xff08;Payload&…

DeepSeek-R1-671B大模型满血版私有化部署高可用教程-SparkAi系统集成图文教程

DeepSeek官网服务器繁忙的主要原因是由于用户数量激增导致的服务器资源紧张。‌为了解决这一问题&#xff0c;DeepSeek团队已经暂停了API服务充值&#xff0c;以避免对用户造成业务影响。目前&#xff0c;存量充值金额仍可继续调用&#xff0c;但充值功能暂时不可用‌。 DeepSe…

如何实现将http请求转化为rpc请求

以下是10个可以实现HTTP请求转发到内部RPC服务的GitHub项目推荐&#xff0c;这些项目涵盖了多种语言和框架&#xff0c;适用于不同的技术栈和需求&#xff1a; 1. **grpc-gateway** grpc-gateway 是一个流行的开源项目&#xff0c;用于将HTTP请求转发到gRPC服务。它支持通…

如何用HBase轻松管理海量数据?

如何用HBase轻松管理海量数据&#xff1f;小白也能学会的入门指南 数据太多&#xff0c;头都大了&#xff1f; 你有没有过这样的经历&#xff1a;面对堆积如山的数据文件&#xff0c;感觉像是被淹没在信息的海洋里&#xff1f;别担心&#xff0c;今天我们要聊的HBase&#xf…