
一、驱动内容系统学习

1.1、基础核心模块
这部分是驱动开发的基石,必须全部掌握。
1.1.1、瑞芯微开发环境搭建
- 必要性:学习与实践的第一步,稳定的代码环境是基础。
- 原因:没有环境,则无法进行后续的编译、烧录与调试。
- 学习方法:
- 参照原厂手册,完成系统SDK的获取与编译(通常执行
./build.sh 即可)。
- 将编译好的镜像烧录至开发板。
- 通过串口调试工具连接开发板,查看启动日志,验证系统运行是否正常。
1.1.2、Linux模块化编程
- 必要性:掌握内核模块的编写(
module_init/exit)、编写驱动Makefile、理解符号导出机制。
- 原因:这是所有Linux驱动的标准编写形式,是驱动开发的第一个程序。
- 学习方法:
- 最小化案例:编写一个仅打印 “Hello Module” 的内核模块,掌握
module_init/exit 和 Makefile 的基础语法(如 obj-m)。
- 符号导出实验:创建两个模块,通过
EXPORT_SYMBOL 共享函数,深入理解模块间的通信机制。
1.1.3、中断及异常处理
- 必要性:学习中断注册(
request_irq)、理解顶半部与底半部机制(如tasklet、工作队列)。
- 原因:这是处理硬件实时事件(如按键中断、传感器数据到达)的核心机制。
- 学习方法:
- 编写基于tasklet的底半部处理实验。
- 尝试中断线程化,观察其与普通中断的差异。
1.1.4、内核互斥与同步技术
- 必要性:掌握自旋锁、信号量、互斥体、RCU等同步机制。
- 原因:保障多核或多线程环境下驱动数据访问的安全,是面试和工作中的高频考点。
- 学习方法:
- 分别使用自旋锁(
spin_lock)和互斥体(mutex)保护共享资源,编写实验代码对比其适用场景。
1.1.5、字符设备驱动模型
- 必要性:理解
file_operations 结构体、掌握设备号分配与注册(register_chrdev)。
- 原因:约90%的简单外设(如LED、按键、各类传感器)驱动都基于此模型构建。
- 学习方法:
- 简化框架实践:实现一个虚拟字符设备,仅支持
read/write 操作(例如实现一个“回声驱动”:写入什么,读出什么)。
- 自动创建设备节点:结合
udev规则,使得驱动加载时能在 /dev 目录下自动生成对应的设备文件。
1.1.6、Linux设备模型
- 必要性:理解
sysfs、kobject、kset 以及 udev 规则。
- 原因:这是理解Linux内核如何统一、动态管理设备的基础,是学习后续各类设备子系统的前提。
- 学习方法:
- 手动创建
kobject:在 /sys 文件系统下创建一个自定义目录,并通过 kobj_attribute 添加可读写的属性文件。
- 观察分析:深入研究
/sys/bus、/sys/class 下已有设备(如 input 子系统)的层次结构,加深理解。
1.2、进阶核心技能
这部分构建了驱动开发的完整能力框架,建议全部掌握。
1.2.1、设备树(Device Tree)
- 必要性:掌握
.dts 语法、设备树编译流程、以及内核解析设备树的机制。
- 原因:在现代嵌入式开发中,设备树已全面替代硬编码的板级信息,是必须掌握的技能。
- 学习方法:
- 反编译对比:修改
.dts 源文件并编译为 .dtb,再用 fdtdump 工具反编译,观察语法与二进制数据的对应关系。
- 动态查看:通过
/proc/device-tree 目录实时查看内核解析后的设备树节点信息,这是深入理解Linux系统与网络原理的重要实践。
1.2.2、Platform虚拟总线驱动
- 必要性:理解
platform_driver 与 platform_device 的分离设计思想。
- 原因:体现了Linux驱动框架“驱动与设备分离”的核心设计模式,是高频面试题。
- 学习方法:
- 改造实践:将一个简单的字符设备驱动,改造为
platform_driver 和 platform_device 分离的结构(使用设备树描述硬件资源)。
- 匹配机制实验:故意修改
of_match_table 中的兼容性字符串,观察驱动因匹配失败而无法加载的现象。
1.2.3、GPIO子系统
- 必要性:学习
gpiod_get、GPIO方向设置、中断绑定等API。
- 原因:这是控制所有芯片引脚的基础,用于驱动LED、按键、继电器等简单外设。
- 学习方法:
- LED闪烁实战:通过
gpiod_direction_output() 控制LED引脚电平,结合内核定时器实现呼吸灯效果。
- 中断按键:使用
gpiod_to_irq() 将按键对应的GPIO映射为中断号,编写驱动并测试按键防抖处理。
1.2.4、Pinctrl子系统
- 必要性:掌握引脚复用配置,解决功能冲突(如某个引脚既想用作UART又想用作GPIO)。
- 原因:对于引脚资源复杂的SoC,必须通过Pinctrl子系统来正确配置引脚功能。
- 学习方法:
- 冲突实验:在设备树中尝试将同一引脚同时配置为UART TX和GPIO输出,观察内核启动时的报错信息。
- 硬件验证:修改
pinctrl 配置后,使用示波器测量引脚的实际电平变化,进行交叉验证。
1.2.5、LED子系统
- 必要性:学习
led_classdev 结构体、以及内置的触发器(trigger)机制。
- 原因:内核提供了标准化的LED控制框架,使用它能够快速开发,无需重复造轮子。
- 学习方法:
- 触发器应用:利用内核内置的
heartbeat 触发器,轻松实现LED跟随系统心跳闪烁,无需编写额外的驱动逻辑。
1.2.6、Input子系统
- 必要性:掌握输入事件的上报函数
input_event()。
- 原因:这是为按键、触摸屏、鼠标等输入设备编写驱动的标准化框架。
- 学习方法:
- 虚拟输入设备:创建一个虚拟按键驱动,通过
input_event() 函数上报按键按下/松开事件。
- 解析真实数据:使用
evtest 工具读取 /dev/input/eventX 中的原始输入事件数据,分析其结构。
1.2.7、I2C总线驱动
- 必要性:I2C总线用于连接各类低速外设,如传感器、EEPROM存储器、触摸屏控制器等。
- 学习方法:
- 用户态先行:先用
i2c-tools(如 i2cset、i2cget)在用户态手动操作I2C传感器,理解通信过程,再对比内核驱动的实现。
- 协议分析:使用逻辑分析仪抓取I2C通信的实际波形,对照协议时序图分析
START、STOP、ACK 等信号。
1.2.8、SPI总线驱动
- 学习方法:
- 全双工环回测试:将SPI的MOSI与MISO短接,实现环回测试,编写驱动验证数据收发的正确性。
- 性能对比:分别使用
spi_sync()(同步)和 spi_async()(异步)API传输大量数据(如1MB),对比两者的吞吐量耗时差异。
1.2.9、UART串口驱动
- 学习方法:
- 硬件回环测试:短接开发板的TX和RX引脚,通过
echo 命令发送数据并验证是否能自己接收回来。
- 自定义协议实现:基于
tty_struct,在驱动层实现一个简单的串口通信协议(例如:帧头+数据长度+数据内容+CRC校验)。
1.3、高阶专题选学
这部分可根据个人职业发展方向或项目需求进行选择性学习。
1.3.1、SDIO
- 必要性:SD卡、Wi-Fi模块(如RTL8723DS)的通信接口。
- 原因:嵌入式设备常用SDIO接口连接高速外设,需掌握SDIO协议、块设备读写及电源管理。
1.3.2、以太网
- 必要性:有线网络通信,涉及TCP/IP协议栈、MAC与PHY芯片驱动。
- 原因:工业设备(如PLC)、网络网关开发必备,需熟悉PHY驱动、
net_device 结构体及DMA传输优化。
1.3.3、USB
- 必要性:支持主机(Host)和设备(Gadget)两种模式。
- 原因:用于扩展U盘、摄像头、4G模块等外设,需学习URB请求、描述符配置及OTG双角色切换,这部分知识也常见于云原生与基础设施领域的设备管理。
1.3.4、PCIe
- 必要性:用于高速数据传输,连接NVMe SSD、GPU加速卡等设备。
- 原因:适用于边缘计算、服务器等高性能场景(如AI推理),需掌握BAR空间映射、MSI中断及DMA引擎配置。

|