3.4 I2C、SPI 与 PCIe 总线速览


3.4 I2C、SPI 与 PCIe 总线速览

本节摘要:总线是外设与主控之间的"交通法规"。本节从两根线的 I2C、四根线的 SPI 讲到可枚举的 PCIe,对比三者的通信模型、时钟角色、设备寻址与软件接口差异,为第 4 章的总线驱动模型打好物理层底子。

芯片圈的行话把这三条总线分成"两根线""四根线"和"差分对",一句话就点出了各自的复杂度梯度:I2C 用两根线(时钟加数据)拼出多设备共享总线;SPI 用四根线(时钟、两根数据、片选)换更高的速率与全双工;PCIe 用高速差分对加交换结构,撑起显卡与固态盘的吞吐。驱动写给哪条总线上的设备,就得懂哪条总线的规矩——总线决定了你怎样"够到"寄存器

I2C:两根线上的地址喊话

I2C 总线只有两根线:串行时钟线与串行数据线,所有设备并联其上,靠七位地址区分彼此。通信永远是主设备发起:先在总线上喊出目标地址,应答的设备继续对话。数据线是开漏输出配上拉电阻——任何设备都可以把线拉低,这种电气设计让多设备共存成为可能,也带来了 I2C 的速度上限:标准模式一百千赫兹、快速模式四百千赫兹,再往上就要更严格的电气条件。

一次"读传感器温度寄存器"的完整对话,在逻辑分析仪上是这个样子:

START | 设备地址 0x48 写 | ACK | 寄存器号 0x00 | ACK | RESTART | 设备地址 0x48 读 | ACK | 数据 0x1C | NACK | STOP 主机指定要读哪个寄存器,随后转为读方向取回数据

两个 I2C 特有的现象值得记下。时钟拉伸:慢速从设备可以拉住时钟线,让主设备等它准备好——这是从设备的"喘气权"。总线死锁:从设备在主机复位中途卡在"以为自己在发数据"的状态、一直拉着数据线,总线就瘫了;老练的驱动会用九个时钟脉冲加停止条件这类手法解救。这些电气层的脾气,到了第 4 章会被 I2C 核心层封装掉,但出问题时你还得下到这一层看波形。

SPI:四根线的全双工专线

SPI 加了两根数据线(主出从入、主入从出)与片选线,换来三个质变:全双工(收发同时进行)、更高速率(几十兆赫兹起步)、无地址协议(片选拉低谁,谁就是对话对象)。没有地址、没有应答机制,一切靠双方预先约定的"模式"对齐——时钟极性与相位组合出四种模式,主从双方必须一致,模式配错的典型症状是"数据错位一个比特"。

SPI 传输的字节序对话(模式0,先发高位): 主机: 0x03 0x00 0x2A 读命令 + 寄存器地址 + 填充字节 从机: 0x00 0x00 0x1C 填充 + 填充 + 目标寄存器数据 本质是移位寄存器对射:主机发 N 字节,必然同时收回 N 字节

Flash 芯片、显示屏、高速 ADC 是 SPI 的常客。它的驱动模型也因"无地址"而直白:内核 SPI 核心层把"片选、模式、速率"做成设备参数,传输用消息结构描述,第 4 章的 spi_driver 一节会实际写一遍。

PCIe:可枚举的差分高速公路

前两条总线都解决不了"设备自报家门"的问题——挂了什么设备,软件只能靠板级描述。PCIe 从物理层就换了个世界:高速差分对、包交换协议、树状拓扑(根复合体挂交换器,交换器挂端点)。最关键的是配置空间:每台设备加电后都自带一份标准化的身份与能力清单——厂商识别、设备识别、内存空间需求(BAR,基址寄存器)。

软件枚举就是沿着这棵树读配置空间:发现设备、读出它需要多大的地址窗口、分配物理地址、把窗口基址写回 BAR。枚举完成后,设备的寄存器区就被映射进统一地址空间,访问方式回到了 3.1 节的 ioremap 那一套。驱动无需知道设备插在哪个槽——总线号、设备号、功能号三层编号唯一定位,写在设备描述里递给驱动。

三总线能力对照

三总线能力对照

从总线视角回看驱动写作

三条总线对驱动写作的影响可以压缩成一张表:

维度 I2C SPI PCIe
设备如何被发现 板级描述(设备树) 板级描述(设备树) 总线枚举自报家门
寄存器访问方式 总线传输报文 总线传输报文 映射后直接读写
一台设备的信息来源 设备树节点 设备树节点 配置空间加设备树
典型驱动入口 i2c 驱动的 probe spi 驱动的 probe pci 驱动的 probe
传输对象 消息(地址加数据段) 消息(片选控制加字节流) DMA 为主

看出规律了吗?发现机制与访问方式组合出三类驱动形态,而"probe"是它们共同的入口仪式。这正是下一章的主角:内核把"设备怎么来、驱动怎么认"抽象成了统一的总线模型——平台总线、I2C 总线、SPI 总线、PCI 总线在软件层共享同一套匹配与探查框架。

⚠️ 常见坑:把 I2C 设备当内存映射设备访问。I2C 设备的"寄存器"是总线报文里的字节偏移,不存在物理地址,ioremap 对它毫无意义——总线上没有"地址窗口"这回事。

上手:用系统工具窥探三条总线

认识总线不必等到写驱动那天,现成系统就是观察场。嵌入式开发板上,设备树的运行时视图(系统设备树目录)把 I2C 与 SPI 控制器连同挂载的子设备一览无余;桌面系统上,总线枚举工具列出每台 PCIe 设备的厂商识别与设备识别——PCIe 的"自报家门"在这里直接可见

$ lspci -nn | grep -i net 03:00.0 Ethernet controller [0200]: 厂商识别:设备识别 ↑ 总线03 设备00 功能0 ← 三层编号唯一定位 $ ls /proc/device-tree/ 2>/dev/null ... i2c@ff020000 spi@ff1f0000 ...

第一份输出里的方括号编码就是配置空间里读出的身份对——第 4 章讲匹配表时你会认出:PCI 驱动的匹配表登记的正是这些号码。第二份输出是设备树在运行系统里的投影,控制器节点与子节点的关系清晰可见。工具先行是硬件学习的好习惯:先看见总线上的居民,再研究怎么跟他们说话。

从逻辑分析仪波形到软件报文

嵌入式调试常配一件入门硬件——逻辑分析仪:几根探针夹在总线上,软件把电平变化翻译成协议报文。一次 I2C 读取在屏幕上呈现为"起始位、地址、应答、数据、停止位"的完整序列,与 3.4 节的文字描述逐字对应。这种"波形与代码互相印证"的体验,是建立硬件直觉最快的方式——第 7 章的排错工具箱里,它也是诊断总线死锁、时序违例的终极手段。

三条总线怎么选

给一块新板子排外设时,总线选型有三个常用判断维度:速率——低速配置类外设(每秒几个读数)I2C 足矣,中高速数据流(传感器原始波形、显示屏缓冲)SPI 更稳,吞吐大类(存储、网卡)才轮到内存映射或 PCIe;布线成本——I2C 两根线挂一串设备最省引脚,SPI 的片选线随设备数量增长,PCIe 的差分对则是高速专属的布线功课;软件生态——I2C 与 SPI 设备的驱动骨架高度模板化,接错线的排错成本主要在硬件侧,PCIe 设备则享受自动枚举的便利但要求设备实现完整的配置空间。三维度摆在一起你会发现:总线的"脾气"决定了驱动代码的形状——这正是下一章要把它们统一进总线模型的原因:形状不同,撮合的流程相同。

本节要点回顾

  • I2C:两根线、七位地址、主从应答,低速多设备的省钱方案。
  • SPI:四根线、片选点名、全双工,中高速外设的主力,模式配错数据错位。
  • PCIe:配置空间自报家门、BAR 分配地址窗口、枚举后回归内存映射访问。
  • 总线决定驱动形态:发现机制与访问方式的组合,预告了下一章的统一总线模型。

物理层的课补完了。第 4 章回到软件世界,看内核如何用统一的总线模型把"设备描述"与"驱动代码"撮合到一起——那个从第 2 章就写死的 GPIO 地址,终于要有个体面的归宿。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U