本次课程从硬件电路分析出发,完成LED字符设备驱动完整开发,讲解寄存器配置、内核地址映射、设备树冲突处理等实战要点。
1. 硬件分析与电路原理
LED硬件电路:LED一端接3.3V电源,另一端连接GPIO引脚。当GPIO输出低电平,LED导通点亮;GPIO输出高电平,LED熄灭。本实验LED0对应i.MX6ULL核心板GPIO1_IO03引脚,编写驱动前必须对照原理图确认引脚编号。
2. 相关寄存器配置
想要控制LED,需要配置4个寄存器:
IOMUXC_SW_MUX_CTL:引脚复用寄存器,将引脚配置为GPIO功能。IOMUXC_SW_PAD_CTL:PAD电气属性寄存器,一般可直接使用默认参数。GPIO_GDIR:GPIO方向寄存器,设置引脚为输出模式。GPIO_DR:GPIO数据寄存器,修改输出电平,控制LED亮灭。
3. 驱动代码实现要点
- 物理地址映射
内核无法直接访问物理寄存器地址,需要调用ioremap把物理地址映射成内核虚拟地址;驱动卸载时调用iounmap解除映射,释放资源。 - 寄存器读写接口
内核提供readl读取寄存器,writel写入寄存器,完成硬件寄存器操作。 - 用户态与内核态数据交互
驱动write函数内,依靠copy_from_user把应用层下发的数据拷贝到内核缓冲区,解析收到的指令字符串,控制LED点亮或者熄灭。 - release资源回收
设备关闭时,在release回调函数中执行地址解映射,防止内存泄漏。
4. 设备树修改与冲突处理
开发板设备树自带LED、gpio按键节点,会占用GPIO资源,和我们自定义LED驱动产生冲突。需要打开dts设备树源文件,注释掉原生leds和gpio-keys节点。
修改完成后单独执行make dtbs编译设备树,将新dtb放到TFTP目录,重启开发板加载生效。
5. 裸机开发与Linux驱动核心区别
裸机代码可以直接操作物理地址;Linux驱动运行在内核框架之下,必须遵守内核规范,使用虚拟地址映射,依托系统调用完成用户程序和硬件之间交互。驱动模块既可以静态编译进内核镜像,也可以编译成ko模块动态加载调试。