【☀Linux驱动开发笔记☀】linux下led驱动(非设备树)_03

linux下led驱动(非设备树)

目录

第一步地址映射

编写驱动前,简单了解一下MMU和虚拟地址空间

MMU全称Memory Management Unit内存管理单元,是一种硬件设备,用于管理内存访问权限和地址转换。

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

针对于32位机来说

虚拟地址的范围是4G,而我们的开发板只有512MB的DDR内存,所以只能映射512MB的物理内存,经过MMU转换后,可以映射4G的虚拟地址空间。这个工作在linux内核启动时会做好工作,设置好后CPU访问的都是虚拟地址。

打个比方.MX6ULL 的 GPIO1_IO03 引脚的复用寄存器

IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 的地址为 0X020E0068。如果没有开启 MMU 的话

直接向 0X020E0068 这个寄存器地址写入数据就可以配置 GPIO1_IO03 的复用功能。现在开启

了 MMU,并且设置了内存映射,因此就不能直接向 0X020E0068 这个地址写入数据了。我们必

须得到 0X020E0068 这个物理地址在 Linux 系统里面对应的虚拟地址,这里就涉及到了物理内

存和虚拟内存之间的转换,需要用到两个函数:ioremap 和 iounmap。

ioremap

ioremap 函数用于将物理地址映射为虚拟地址,函数原型如下:

c 复制代码
void *ioremap(unsigned long phys_addr, unsigned long size);

phys_addr 是要映射的物理地址,size 是要映射的内存大小。函数返回映射后的虚拟地址。

假如我们现在要获取该io口的虚拟地址

c 复制代码
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
static void __iomem* SW_MUX_GPIO1_IO03;//定义一个指向io口的虚拟地址的指针
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);//将物理地址0X020E0068映射为虚拟地址

映射完后直接对SW_MUX_GPIO1_IO03 进行读写操作

iounmap

iounmap 函数用于取消之前通过 ioremap 映射的虚拟地址,函数原型如下:

c 复制代码
void iounmap(void *addr);

addr 是要取消映射的虚拟地址。

假如我们现在要取消对0X020E0068的映射

c 复制代码
iounmap(SW_MUX_GPIO1_IO03);

第二步内存访问函数

这里涉及两个概念:io端口和io内存

io端口:

当外部寄存器或内存映射到 IO 空间时,称为 I/O 端口。

io内存:

当外部寄存器或内存映射到内存空间时称为io内存。

在做完地址映射后,我们就可以直接对虚拟地址进行读写操作了,但是为了方便起见,linux提供了一些内存访问函数,比如readb,writeb,readl,writel等,这些函数可以直接对虚拟地址进行读写操作,而不需要我们自己去实现。

读操作函数

readb,readw,readl 分别用于读取 8 位、16 位和 32 位数据,函数原型如下:

c 复制代码
u8 readb(void *addr);
u16 readw(void *addr);
u32 readl(void *addr);

addr 是要读取的虚拟地址。

写操作函数

writeb,writew,writel 分别用于写入 8 位、16 位和 32 位数据,函数原型如下:

c 复制代码
void writeb(u8 value, void *addr);
void writew(u16 value, void *addr);
void writel(u32 value, void *addr);

value 是要写入的数据,addr 是要写入的虚拟地址。

一个简单的led驱动

需要查看一下芯片的驱动手册后进行编写

c 复制代码
/* 寄存器物理地址 */
#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)

/* 说明:
 * CCM_CCGR1 bit[27:26] 控制 GPIO1 时钟门控;值 0b11 表示使能。
 * SW_MUX_GPIO1_IO03 选择复用为 GPIO;写入 5 表示 ALT5(GPIO)。
 * SW_PAD_GPIO1_IO03 配置上下拉、速度、驱动能力等 PAD 属性。
 * GPIO1_GDIR 设置方向;GPIO1_DR 设置输出电平。
 */

/* 映射后的寄存器虚拟地址指针 */
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;

//往后代码是在驱动的入口函数里编写
/* 初始化LED */
	/* 1、寄存器地址映射 */
  	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);
    /* bit[27:26] = 0b11 打开 GPIO1 时钟门控 */
    val &= ~(3 << 26);	/* 清除以前的设置 */
    val |= (3 << 26);	/* 设置为始终使能 */
    writel(val, IMX6U_CCM_CCGR1);

    /* 3、设置GPIO1_IO03的复用功能,将其复用为
     *    GPIO1_IO03,最后设置IO属性。
     */
    writel(5, SW_MUX_GPIO1_IO03);
    /* ALT5=GPIO 功能 */
	
	/*寄存器SW_PAD_GPIO1_IO03设置IO属性
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 00 默认下拉
     *bit [13]: 0 kepper功能
     *bit [12]: 1 pull/keeper使能
     *bit [11]: 0 关闭开路输出
     *bit [7:6]: 10 速度100Mhz
     *bit [5:3]: 110 R0/6驱动能力
     *bit [0]: 0 低转换率
	 */
	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);

下一节再讲解用设备树来编写led驱动

相关推荐
糖纸风筝3 小时前
Java指南:eclipse、java-activemq与测试验证
java·开发语言·学习
以琦琦为中心3 小时前
在RK3568开发板嵌入式开发中,配置NFS服务是实现与Ubuntu虚拟机之间文件共享的常用方法
linux·运维·ubuntu·rk3568
雷工笔记3 小时前
读书笔记|算法的破坏性影响
学习·随笔
Nimsolax3 小时前
Linux网络DNS与ICMP
linux·网络
千年糊涂4 小时前
STM32使用薄膜压力传感器
stm32·单片机·嵌入式硬件
赖small强4 小时前
【Linux驱动开发】Linux UART 通信详解:从硬件到驱动再到应用
linux·驱动开发·uart
2301_797267344 小时前
神经网络组植物分类学习规划与本周进展综述15
人工智能·神经网络·学习
月下倩影时4 小时前
视觉学习篇——理清机器学习:分类、流程与技术家族的关系
学习·机器学习·分类
赖small强4 小时前
【Linux驱动开发】Linux 设备驱动中的阻塞与非阻塞 I/O:机制、源码与示例
linux·驱动开发·阻塞与非阻塞