I2C
I2C (Inter-Integrated Circuit) 和 SPI (Serial Peripheral Interface) 是嵌入式系统中最常用的两种低速串行总线协议。它们主要用于连接微控制器与各种外设,如传感器、EEPROM、显示驱动、ADC/DAC 等设备。这两种总线在电气特性和使用场景上各有特点。
I2C 总线
I2C 是由 Philips (现 NXP) 在 1980 年代初开发的双向、二线制、半双工串行总线。I2C 只需要两根信号线:SDA (Serial Data) 串行数据线和 SCL (Serial Clock) 串行时钟线,支持多主多从架构。
I2C 的物理接口采用开漏输出模式,需要通过上拉电阻将信号线拉高。这种设计使得多个设备可以共享同一条总线,任何一个设备都可以将信号线拉低。当所有设备都释放总线时,上拉电阻将信号线拉高,形成逻辑 1。当某个设备将信号线拉低时,形成逻辑 0。
I2C 的通信过程由主设备控制。主设备产生时钟信号 SCL,并启动和停止通信。I2C 定义了启动条件 (SCL 为高时 SDA 从高变低)、停止条件 (SCL 为高时 SDA 从低变高)、应答位 (ACK) 等协议细节。每个设备都有唯一的 7 位或 10 位地址,主设备通过发送设备地址来选择要通信的从设备。
I2C 支持多种速度模式。标准模式 (Standard-mode) 支持 100kbps,快速模式 (Fast-mode) 支持 400kbps,快速模式增强版 (Fast-mode Plus) 支持 1Mbps,高速模式 (High-speed mode) 支持 3.4Mbps。速度越高,对总线电容和上拉电阻的要求越严格。
从工程实践来看,I2C 的优势在于接线简单、节省 IO 口。但 I2C 也有明显的局限性。由于采用开漏输出和上拉电阻,信号上升沿较慢,限制了通信速度。I2C 的地址空间有限,7 位地址只能支持 128 个设备,而且还有一些保留地址。I2C 的抗干扰能力较弱,长距离通信容易受噪声影响。
SPI 总线
SPI 是由 Motorola 最初开发的全双工同步串行总线。SPI 通常使用四根信号线:SCK (Serial Clock) 串行时钟、MOSI (Master Out Slave In) 主出从入、MISO (Master In Slave Out) 主入从出、CS (Chip Select) 片选信号。SPI 采用主从架构,通常一个主设备和多个从设备。
与 I2C 不同,SPI 采用推挽输出而非开漏输出,信号转换速度快,可以实现更高的通信速率。SPI 的片选信号是独立的,每个从设备需要一根专用的 CS 线,这使得 SPI 在多从设备场景下占用较多的 IO 口,但同时也简化了设备选择逻辑。
SPI 的通信由主设备发起。主设备拉低某个从设备的 CS 线,然后产生时钟信号 SCK,在 SCK 的边沿通过 MOSI 发送数据,同时通过 MISO 接收数据。SPI 支持四种时钟极性和相位模式 (CPOL 和 CPHA),不同的从设备可能需要不同的模式,主设备需要根据从设备的规格进行配置。
SPI 没有定义标准的速度等级,实际速率取决于主设备和从设备的性能。在实际应用中,SPI 可以轻松达到数十 Mbps 的速率,远高于 I2C。一些高速 SPI Flash 甚至支持 100Mbps 以上的速率。
SPI 的优势在于全双工通信、高速传输、简单的协议逻辑。SPI 不需要复杂的地址解析和应答机制,硬件实现简单。但 SPI 也有局限性,主要是缺少统一的设备寻址机制,每个从设备需要独立的 CS 线,在从设备数量较多的场景下会占用大量 IO 口。
I2C 与 SPI 的选型
在实际工程中,I2C 和 SPI 的选择取决于具体的应用需求。如果 IO 口资源紧张,设备数量较多,通信距离较长,I2C 是更好的选择。典型的 I2C 应用包括温度传感器、湿度传感器、EEPROM、实时时钟 (RTC)、小型 OLED 显示屏等。
如果需要高速数据传输,全双工通信,或者 IO 口资源充足,SPI 是更合适的选择。典型的 SPI 应用包括 SD 卡、SPI Flash、高速 ADC/DAC、无线通信模块 (如 NRF24L01)、TFT LCD 显示屏等。
需要注意的是,I2C 和 SPI 都有扩展协议和变种。I2C 有 SMBus (System Management Bus),主要用于智能电池系统,与 I2C 高度兼容但有一些额外的电气和协议要求。SPI 有 Quad SPI (QSPI),使用四根数据线实现更高的传输速率,常用于高速 Flash 存储器。
Linux 对 I2C 和 SPI 的支持
Linux 内核提供了完整的 I2C 和 SPI 子系统。对于 I2C,内核支持通过设备树或 ACPI 描述 I2C 总线和设备,提供通用的 i2c-master 驱动框架和设备驱动接口。开发者可以使用 i2c-tools 工具集在用户空间进行 I2C 设备的探测和调试。
对于 SPI,内核同样支持设备树和 ACPI 两种描述方式。Linux 的 SPI 控制器驱动负责管理物理总线,而具体的 SPI 设备驱动则通过 spi_driver 接口注册。内核还提供了 spidev 设备,允许用户空间直接访问 SPI 总线,这对开发和调试非常有用。
在嵌入式开发中,理解 I2C 和 SPI 的电气特性和协议细节非常重要。错误的接线、不当的上拉电阻、不匹配的时钟模式都可能导致通信失败。使用逻辑分析仪或示波器观察总线信号是调试这类问题的有效手段。