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

it2023-09-17  67

这里写目录标题

Linux 下 LED 灯驱动原理地址映射I/O 内存访问函数 实验程序编写LED 灯驱动程序编写编写测试 APP 运行测试编译驱动程序编译测试 APP运行测试总结

本章开始编写第一个真正的 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烧写即可。

最新回复(0)