1. 课程导论:网关外设驱动开发概述、SPI与I2C总线在物联网网关中的核心地位、HAL层抽象的意义
1.1 物联网网关:外设驱动的“第一公里”
在物联网(IoT)架构中,网关是连接感知层(传感器、执行器)与网络层(云平台、边缘服务器)的核心枢纽。网关外设驱动开发,本质上是解决“第一公里”的数据搬运问题——将物理世界中的电信号、模拟量、数字协议,转化为操作系统可识别的文件描述符与内存数据。
一个典型的工业物联网网关,其外设接口呈现高度异构化特征:
| 接口类型 | 典型设备 | 数据速率 | 通信距离 |
|---|---|---|---|
| SPI | ADC、DAC、LCD、RF模块、SD卡 | 1~80 Mbps | 板级(< 10 cm) |
| I2C | 温湿度传感器、加速度计、EEPROM、RTC | 100 kHz~3.4 MHz | 板级(< 30 cm) |
| UART | GPS模块、蓝牙模块、RS485网关 | 115.2 kbps~1 Mbps | 板级~千米级(加驱动) |
| GPIO | 按键、LED、继电器、中断输入 | 取决于软件轮询/中断 | 板级 |
其中,SPI 和 I2C 占据了网关板级通信的 70% 以上场景,是外设驱动开发的核心战场。
关键认知: 网关外设驱动不是简单的“点灯”或“读寄存器”,而是涉及总线时序、DMA传输、中断上下文、电源管理、设备树描述、HAL层抽象的系统工程。本课程将聚焦 SPI 与 I2C 设备在 HAL 层的挂载全流程。
1.2 SPI 与 I2C 总线:物联网网关中的“毛细血管”
1.2.1 SPI(Serial Peripheral Interface)
SPI 是一种全双工、同步、主从式串行总线,由 Motorola 公司提出。其核心特征在于:
- 四线制: SCLK(时钟)、MOSI(主出从入)、MISO(主入从出)、CS(片选)。
- 全双工: 每个时钟周期同时发送和接收一位数据。
- 高速率: 典型频率 10~80 MHz,适合高吞吐量传感器(如 16 位 ADC、摄像头)。
- 无内置寻址: 通过硬件片选线 CS 选择从设备,每个从设备独占一条 CS 线。
在网关中,SPI 常用于连接:
- 高速数据采集前端(多通道同步 ADC)
- 无线通信模块(LoRa、Wi-Fi、Sub-1G)
- 显示控制器(TFT-LCD、OLED)
- 存储设备(SD卡、Nor Flash)
开发避坑: SPI 的时钟极性(CPOL)和时钟相位(CPHA)必须与从设备数据手册严格匹配,否则会导致数据移位错误。在 HAL 层挂载时,务必在设备树或配置结构中显式声明 spi-cpol 和 spi-cpha。
1.2.2 I2C(Inter-Integrated Circuit)
I2C 是一种半双工、同步、多主从式串行总线,由 Philips 公司(现 NXP)发明。其核心特征:
- 两线制: SCL(时钟)、SDA(数据)。
- 内置寻址: 每个从设备有 7 位或 10 位地址,总线仲裁由硬件完成。
- 速率适中: 标准模式 100 kHz,快速模式 400 kHz,高速模式 3.4 MHz。
- 开漏输出: 需要外部上拉电阻,支持多主机仲裁。
在网关中,I2C 常用于连接:
- 环境传感器(温湿度、气压、光照)
- 电源管理芯片(PMIC、电池电量计)
- 实时时钟(RTC)
- 低速存储(EEPROM)
注意: I2C 总线上的电容负载会限制通信距离和速率。在网关设计中,若 I2C 总线长度超过 20 cm,建议使用 I2C 总线缓冲器(如 PCA9517)或降低时钟频率。
1.2.3 SPI vs I2C:选型对比
| 对比维度 | SPI | I2C |
|---|---|---|
| 引脚数量 | 4 + N(N为从设备数) | 2(总线共享) |
| 通信模式 | 全双工 | 半双工 |
| 最大速率 | 80+ Mbps | 3.4 Mbps |
| 寻址方式 | 硬件片选 | 软件地址 |
| 多主机支持 | 不支持(单主) | 支持(多主仲裁) |
| 典型功耗 | 较高(全驱动) | 较低(开漏) |
| 适用场景 | 高速、大数据量 | 低速、多设备、低功耗 |
1.3 HAL 层抽象:从“裸机寄存器”到“可移植驱动”
1.3.1 为什么需要 HAL 层?
在嵌入式 Linux 系统中,外设驱动直接操作硬件寄存器会带来三个致命问题:
- 不可移植: 寄存器地址、位域定义、时钟配置与 SoC 强耦合,更换芯片需重写驱动。
- 不安全: 用户态直接访问物理地址会破坏系统稳定性,且无法利用内核的并发保护机制。
- 不统一: 不同厂商的 SPI/I2C 控制器寄存器模型差异巨大,驱动开发人员需要学习多套底层 API。
HAL(Hardware Abstraction Layer) 正是为解决这些问题而生。它在内核驱动框架与具体硬件寄存器之间插入一层抽象接口,将“如何操作寄存器”与“业务逻辑”解耦。
1.3.2 HAL 层的分层架构
在 Linux 内核中,SPI 和 I2C 的 HAL 层呈现清晰的“三明治”结构:
1.3.3 HAL 层在 SPI/I2C 驱动中的具体体现
在 Linux 内核中,SPI 和 I2C 的 HAL 层通过以下核心数据结构实现抽象:
| 总线类型 | 核心结构体 | HAL 接口示例 | 抽象内容 |
|---|---|---|---|
| SPI | struct spi_controller |
spi_sync()、spi_async() |
时钟极性/相位、位序、片选控制、DMA 传输 |
| I2C | struct i2c_adapter |
i2c_transfer()、i2c_smbus_read_byte() |
总线频率、从设备地址、重试策略、超时控制 |
驱动开发人员编写设备驱动时,只需填充这些结构体中的回调函数(如 master_xfer、transfer_one_message),内核子系统会自动处理中断、锁、电源管理等复杂逻辑。
课程核心主张: 掌握 HAL 层挂载,意味着你不再需要为每个 SoC 重写 SPI/I2C 驱动。你只需要理解
struct spi_device 和 struct i2c_client 的注册流程,以及设备树中如何描述外设拓扑。这正是本课程 30 章要系统交付的能力。
1.4 本课程的技术路线图
从下一章开始,我们将按照以下路径逐步深入:
- 基础篇(第2~8章): Linux 内核 SPI/I2C 子系统源码分析、设备树绑定、控制器驱动框架。
- 核心篇(第9~18章): 典型外设(ADC、温湿度传感器、LCD、RF模块)的 HAL 层挂载实战。
- 进阶篇(第19~25章): DMA 传输、中断优化、电源管理、多主 I2C 仲裁、SPI 菊花链。
- 工程篇(第26~30章): 驱动调试技巧(ftrace、逻辑分析仪)、性能基准测试、生产环境部署。
每章均包含可运行的代码示例、设备树片段、以及对应的 HAL 层接口分析。
学习建议: 请提前准备一块支持 Linux 的嵌入式开发板(如 Raspberry Pi、STM32MP1、i.MX8M),并搭建好交叉编译环境。本课程所有代码均可在主线内核 5.10+ 上编译运行。
1.5 本章小结
- 物联网网关的外设驱动开发核心在于 SPI 和 I2C 总线,两者在速率、引脚、寻址方式上互补。
- HAL 层通过
spi_controller和i2c_adapter将硬件寄存器差异封装为统一接口,实现驱动可移植。 - 本课程从源码分析到实战挂载,系统覆盖 SPI/I2C 设备在 HAL 层的完整生命周期。