嵌入式linux驱动开发-点灯大师(旧版)

本章开始编写第一个真正的 Linux 字符设备驱动。

Linux 下 LED 灯驱动原理

LED 灯驱动最终也是对 I.MX6ULL 的 IO 口进行配置,并配置相应的硬件寄存器,与裸机实验不同的是,在 Linux 下编写驱动要符合 Linux的驱动框架

地址映射

MMU 全称叫做 MemoryManage Unit,也就是内存管理单元
MMU 主要完成的功能如下:
①、完成虚拟空间到物理空间的映射。
②、内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性。

物理地址:真实存在的地址,如 512MB 的 DDR3;
虚拟地址:MMU映射的地址,如32 位的处理器,虚拟地址范围是 2^32=4GB。
MMU就是将少的物理地址映射到更多的虚拟地址,之前裸机开发用到的都是物理内存,直接往寄存器写数据;有了MMU之后,就需要向寄存器所在的物理地址映射的虚拟地址写数据。

如下图:

在这里插入图片描述
物理内存和虚拟内存之间的转换,需要用到两个函数: ioremap 和 iounmap。

1、 ioremap 函数
ioremap 函 数 用 于 获 取 指 定 物 理 地 址 空 间 对 应 的 虚 拟 地 址 空 间 , 定 义 在arch/arm/include/asm/io.h

1 #define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE)
2 
3 void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
4 {
5 		return arch_ioremap_caller(phys_addr, size, mtype, __builtin_return_address(0));
6 }

phys_addr:要映射给的物理起始地址。
size:要映射的内存空间大小。
mtype: ioremap 的类型,可以选择 MT_DEVICE、 MT_DEVICE_NONSHARED、MT_DEVICE_CACHED 和 MT_DEVICE_WC, ioremap 函数选择 MT_DEVICE。
返回值: __iomem 类型的指针,指向映射后的虚拟空间首地址。

2、 iounmap 函数
卸载驱动的时候需要使用 iounmap 函数释放掉 ioremap 函数所做的映射

void iounmap (volatile void __iomem *addr)

3、加载/卸载驱动

SW_MUX_GPIO1_IO03 就是一个__iomem类型的指针。

//加载
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
static void __iomem* SW_MUX_GPIO1_IO03;
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);

//卸载
iounmap(SW_MUX_GPIO1_IO03);

I/O 内存访问函数

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

对于 ARM 来说没有 I/O 空间这个概念,因此 ARM 体系下只有 I/O 内存(可以直接理解为内存)。

Linux 内核不建议直接通过指针访问这些地址,而是推荐使用一组操作函数来对映射后的内存进行读写操作。

1、读操作函数

1 u8 readb(const volatile void __iomem *addr)
2 u16 readw(const volatile void __iomem *addr)
3 u32 readl(const volatile void __iomem *addr)

2、写操作函数

1 void writeb(u8 value, volatile void __iomem *addr)
2 void writew(u16 value, volatile void __iomem *addr)
3 void writel(u32 value, volatile void __iomem *addr)

以上函数不做太多说明,有眼就行。

实验程序编写

程序的编写和上一章虚拟设备驱动的编写类似,不用写注释了,自己能看懂就行了,理解大概意思就行,后边儿还会学习新字符设备驱动。

LED 灯驱动程序编写

led.c

在这里插入代码片

编写测试 APP

ledApp.c

在这里插入代码片

运行测试

编译驱动程序

Makefile

KERNELDIR := /home/zxy/linux/kernel_lib/linux-imx-rel_imx_4.1.15_2.1.0_ga_alientek
CURRENT_PATH := $(shell pwd)
obj-m := led.o

build: kernel_modules

kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean

编译测试 APP

arm-linux-gnueabihf-gcc ledApp.c -o ledApp

运行测试


depmod //第一次加载驱动的时候需要运行此命令
modprobe led.ko  //加载驱动
(或insmod,两个命令都行,上边儿那个就是能查找依赖关系)
mknod /dev/led c 200 0

./ledApp /dev/led 1 //打开 LED 灯
./ledApp /dev/led 0 //关闭 LED 灯

rmmod led.ko	//卸载驱动模块

总结

没啥好说,没啥新知识。
就是原子出厂的设备树中内置了led的设备树,里边儿有心跳灯功能,进入到设备树文件.dts中,将其中的led设备树相关的状态"on"改为"off",然后在内核目录make dtbs即可重新编译设备树,mfgtool烧写即可。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值