计算机基本架构-系统总线
计算机基本架构-系统总线
系统总线负责维护中央处理器(CPU)、系统外设和内存之间的所有通信。系统总线按照一定的总线协议运行,以在总线主控设备和总线从属设备之间交换数据。总线协议确保在总线主控设备与总线从属设备交换数据时,将所有其他系统设备隔离开,以免干扰总线。总线主控设备发起数据传输,发送或接收来自从属设备或系统内存的数据。另一方面,总线从属设备没有启动数据传输的能力,只能响应总线主控设备以交换数据。
总线架构有两种类型,串行总线和并行总线。串行总线架构基本上由主控设备和从属设备之间的一根数据线组成,数据位一次一位地交换。相反, 并行总线由多根数据线组成,可以同时发送或接收多个数据位。
在本章中,我们将描述几种串行和并行总线协议以及优先级方案。
1.并行总线架构
典型系统中有两种并行总线架构:单向总线和双向总线。单向总线包含两条独立的数据路径:一条从总线主控设备开始到总线从属设备结束,另一条从总线从属设备开始到总线主控设备结束。而双向总线共享一条物理数据路径,允许数据在两个方向上流动。然而,这种类型的总线需要额外的逻辑开销和更复杂的控制。
下图描述了一种32位单向总线架构,包括两个总线主控设备和三个从属设备。在该图中,两条单向数据路径用较粗的线条突出显示。第一条路径是写路径,总线主控设备使用该路径将数据写入从属设备。此路径需要每个主控设备和从属设备都有一个写数据端口(WData
)。第二条路径是读路径,用于从从属设备读取数据。这也需要每个主控设备和从属设备都有一个读数据端口(RData
)。总线主控设备和从属设备都具有地址和控制端口,用于定义目标地址、数据传输方向、数据宽度和数据传输长度。
所有总线主控设备在开始数据传输之前必须与总线仲裁器协商以获得总线的所有权。当有多个总线主控设备的请求待处理时,仲裁器会根据某种优先级方案决定哪个总线主控设备应该优先开始数据传输,并向优先级最高的主控设备发出确认信号。因此,每个总线主控设备都有请求(Req)和确认(Ack)端口与仲裁器进行通信。一旦获得许可,主控设备会在第一个总线周期内向选定的从属设备发送地址和控制信号,并在下一个周期内写入或读取数据。连接到地址总线的解码器(DEC)会生成使能(EN)信号来激活选定的从属设备。每个主控设备和从属设备都有一个准备状态(ready)的端口,指示选定的从属设备是否准备好传输或接收数据。

32位双向总线架构如下图所示。为了便于比较,主设备和从设备的数量与上图保持一致。两图之间唯一的区别是,早期架构中的单向数据总线被双向总线所取代,用于读写数据。在双向总线架构中,数据线上的三态缓冲器是必不可少的,它们可以在数据传输仅在主设备和从设备之间进行时,隔离非必要的系统设备。图中的地址总线也可以与数据总线集成,以便在同一条总线上交换地址和数据。然而,这种方案速度较慢,并且需要额外的控制逻辑开销来维护正确的数据流和管理。

下面这张图展示了典型总线主设备的所有输入/输出(I/O)端口。正如前面提到的,Req
和Ack
端口用于与仲裁器进行通信。总线主设备使用Ready
端口来确定从设备是否准备好传输或接收数据。WData
、RData
和Address
端口分别用于写入数据、读取数据和指定从设备地址。控制信号Status
、Write
、Size
和Burst
描述了数据传输的性质。

Status
端口是一个两位总线,如下表所示,用于描述总线主设备的状态。根据该表,总线主设备可以通过发出START
信号来启动新的数据传输。如果主设备正在与从设备交换数据,则会发出Continue
(CONT)信号。IDLE
信号表示总线主设备已经完成了数据传输。一旦产生该信号,主设备会继续发出当前数据传输的最后一个地址和控制信号,直到总线上出现新的数据传输。总线主设备在与从设备交换数据的同时,也可能正在进行内部操作。对于这种特定情况,主设备可能会通过发出BUSY
信号来暂时中止数据传输。
Status[1:0] | 总线主设备的状态 |
---|---|
0 0 | 开始传输(START) |
0 1 | 继续传输(CONT) |
1 0 | 完成传输(IDLE) |
1 1 | 停止传输(BUSY) |
Write端口,顾名思义,用于描述主设备是否正在进行数据写入或读取,如下表所示:
Write | 总线主设备的操作 |
---|---|
0 | 读 |
1 | 写 |
Size
端口描述了传输过程中数据的位宽,如下表所示。总线主设备可以以8位(字节)、16位(半字)、32位(字)或64位(双字)的形式传输或接收数据,位宽在传输过程中不可更改:
Size[1:0] | 比特数 |
---|---|
0 0 | 8 |
0 1 | 16 |
1 0 | 32 |
1 1 | 64 |
Burst
端口描述了总线主设备发送或接收的数据包数量,如下表所示。在该表中,总线主设备可以在一次突发传输中传输从一个数据包到超过32,000个数据包的数据。
Burst[3:0] | 数据包数量 |
---|---|
0 0 0 0 | 1 |
0 0 0 1 | 2 |
0 0 1 0 | 4 |
0 0 1 1 | 8 |
0 1 0 0 | 16 |
0 1 0 1 | 32 |
0 1 1 0 | 64 |
0 1 1 1 | 128 |
1 0 0 0 | 256 |
1 0 0 1 | 512 |
1 0 1 0 | 1024 |
1 0 1 1 | 2048 |
1 1 0 0 | 4096 |
1 1 0 1 | 8196 |
1 1 1 0 | 16384 |
1 1 1 1 | 32768 |
下图显示了一个典型的总线从设备的I/O端口。由于从设备无权发起数据传输,因此省略了Req
和Ack
端口。Ready
信号指示一旦总线主设备发起传输,从设备是否准备好传输或接收数据。WData、RData和Address端口分别用于写数据、读数据和指定目的地址。控制输入Status
、Write
、Size
和Burst
描述了上述传输的性质。Enable
(EN)输入由地址解码器生成,并基于总线主设备生成的地址来激活特定的从设备。

2.基本写传输过程
这一节中,我们将使用时序图作为标准工具,展示主设备与从设备之间的总线活动。写操作的总线协议描述了总线主控设备如何使用单向总线将数据写入从属设备,具体过程由图中的时序图展示。
在第一个时钟周期,总线主控设备向从属设备发送目标地址和控制信号,A1
和C1
,而不管从属设备的状态如何。如果从属设备的状态是准备好(Ready
),实际数据包WData1
将在第二个周期与下一个数据包的地址和控制信号A2
和C2
一起发送。如果从属设备准备好,它应能在第三个时钟周期的上升沿读取WData1
。

然而,有时从属设备可能未准备好接收或发送数据。比如,在下图的第二个周期,从属设备的状态变为未准备好(Not Ready)。在第三个时钟周期的上升沿检测到从属设备的状态后,主控设备暂停写传输。这意味着当前的数据包WData2
及下一个地址和控制信号A3
和C3
将被重复发送,直到从属设备的状态变为准备好为止。当从属设备准备好接收剩余数据时,正常的数据传输将继续。

下面讨论这样一个问题:当从设备频繁更改其状态时,会发生什么情况?
当从设备在一个时钟周期内将状态更改为未准备好时,主设备会在下一个时钟上升沿检测到这一变化,并保持当前数据、下一个地址和控制信号,直到从设备再次变为准备好状态。
下图是一个从设备频繁更改其状态的例子。在该图中,从设备在第一个周期内处于未准备好状态。因此,第一个地址和控制包A1
和C1
被延长,没有数据发送到从设备。当从设备在第二个周期内发出准备好信号时,总线主设备在第三个周期的上升沿产生第一个数据包WData1
,并将地址和控制信号更改为A2
和C2
。然而,从设备在第三和第四周期再次将状态更改为未准备好。主设备在第四和第五时钟周期的上升沿检测到状态变化,并通过不更改A2
、C2
和WData1
作出响应。第五周期的准备好信号促使主设备在第六周期开始时产生A3
、C3
和WData2
。主设备保持这些值,直到第八周期开始时从设备再次更改其状态为准备好。此时,主设备发送新的A4
、C4
和WData3
。

3.基本读传输过程
下面是一个基本的读传输过程。当从设备发出准备信号,它就会为主设备提供数据。一旦主设备在时钟边沿检测到准备信号,它会在下一个正时钟边沿读取从设备的响应,并生成下一个地址和控制信号发送给从设备。

当从设备频繁更改其状态时,读取序列会如何变化?
下图显示了一个从设备频繁更改其状态的例子。在此图中,从设备在第一个周期之前处于未准备好状态。因此,主设备会保持第一个地址和控制数据包A1
和C1
,直到从设备变为准备好状态。当主设备在第三个周期的正边沿检测到准备信号时,它会通过向从设备发出新的地址和控制信号A2
和C2
作出响应。在第三个周期内,从设备还会向主设备发送RData1
。主设备在检测到从设备的准备信号后,于第六个周期的正边沿读取数据。
图中其余的读事务遵循上述相同的协议。换句话说,每当主设备检测到从设备的准备信号时,就会为从设备生成一组新的地址和控制信号;从设备在变为准备好状态后会向主设备发送新的数据包;主设备在从设备准备好时读取从设备的数据。

4.总线主状态改变
在数据传输过程中,主设备可能会间歇性地忙于执行其自身的内部任务。如果主设备正忙于执行内部任务,数据总线协议要求主设备在其忙碌期间保持地址、控制和数据值。
下图展示了一个在写数据给从设备的过程中,主设备在时钟周期 2、9 和 10 变为忙碌的例子。主设备通过发出 Status = 00
(来启动数据传输,并迅速发送第一个地址 A1。在第二个周期,主设备变得忙碌并发出忙碌信号(Status = 11
)。因此,它重复了之前的地址 A1
,但无法发送任何数据,尽管在此期间从设备已发出 Ready = 1
信号。在第三个周期,所有内部操作停止,主设备通过生成Cont
信号继续正常的数据传输。主设备还在第三个周期的正边沿检测到从设备已准备好,并发出第二个地址 A2
以及第一个写数据 WD1
。在下一个周期,主设备重复A2
和 WD1
,因为从设备在第四个周期的正边沿未准备好。尽管从设备在第七个周期显示为未准备好,正常的数据传输序列继续进行,直到第九个周期,主设备再次将状态更改为忙碌。这个变化导致主设备在第九和第十周期延长地址 A5
和数据 WD4
的传输,而不管从设备的状态如何。

当主设备频繁更改其状态时,会发生什么情况?
假设总线主设备将两个半字(16位宽数据包)传输到内存块的地址0x20
和0x22
,然后将4个字(32位宽数据包)传输到地址0x5c
、0x60
、0x64
和0x68
。下图显示了此字节可寻址内存的地址映射,其中每个框中的数字表示单个地址。

在数据传输过程中,如下图所示,主设备在周期2、3、4、7和8频繁发出忙碌信号。注意,从周期2开始直到数据传输结束,从设备一直处于就绪状态。
总线主设备在第一个周期通过发出以下信号开始传输第一个数据包:Status = 00
(START),Burst = 0001
(共两个数据包),Size = 01
(半字),Write = 1
,Address = 0x20
。由于从设备在第二个周期开始时处于就绪状态,主设备准备发送下一个地址0x22
和第一个写入数据Data20
。然而,在此周期内,主设备由于内部操作变得忙碌,直到第五个周期开始,并发出忙碌信号,如图所示。忙碌状态要求总线主设备在此期间重复其控制、地址和数据信号。因此,当主设备在第五个周期最终将其状态更改为Cont
时,它能够在同一周期内发送Data20
,并在随后的周期内发送Data22
。
一旦第一个数据传输完成,主设备在第六个周期开始另一段写传输,发出以下信号:Status = 00
(START),Burst = 0010
(共四个数据包),Size = 10
(字),Write = 1
,Address = 0x5C
。由于从设备的状态为就绪,主设备准备在第七个周期开始时发送下一个地址和数据包。然而,其内部操作再次干扰了此过程,直到第九个周期开始。主设备发出忙碌信号,并重复其控制、地址和数据输出。当主设备在第九个周期最终将其状态更改为Cont
时,它传递第二个地址0x60
和第一个数据Data5C
。在第十个周期,分别发送下一个地址0x64
和数据Data60
。主设备在第十一个周期写入Data64
,并在第十二个周期写入最后的数据Data68
,完成传输。在此周期内,总线主设备将其状态更改为Idle
,表示数据传输结束。

5.总线握手
每个总线主设备通过请求-确认信号与仲裁器进行通信,这些信号构成了基本的握手协议。开始总线传输的主设备发出请求信号Req
,向仲裁器请求总线的所有权。仲裁器通过确认信号Ack
授予该请求。如果没有正在进行的数据传输,通常在主设备发出请求后的下一个周期内会发出确认信号。然而,由于可能存在的当前数据传输,确认信号可能在请求信号发出后的多个周期后才生成。
下图显示了在总线所有权授予主设备之前,总线主设备和仲裁器之间握手机制的时序图。Ack
信号上的~
标志表示此信号在仲裁器收到来自特定总线主设备的请求后经过多个周期才产生。一旦主设备在第n个周期收到Ack信号,它将在第(n + 1)个周期将其状态更改为Start
,并发出第一个地址A1
,而不管从设备的状态如何。如果从设备处于Ready状态,主设备将在接下来的周期内发送第二个地址A2
和第一个数据WData1
。

6.总线仲裁器
总线仲裁是总线管理中至关重要的一部分,特别是当有多个总线主设备竞争总线所有权时。仲裁可以是硬件编码的,实现为状态机,也可以是可编程的,基于寄存器实现。
下表解释了两个总线主设备之间的硬件编码总线仲裁机制。当仲裁器没有收到请求时,不会向任何总线主设备生成确认信号。然而,如果两个请求同时发出,根据该表,确认信号会发给总线主设备1,因为假定总线主设备1的优先级高于总线主设备2,如最后一行所示。

下面这张图是上面这张表实现为状态机的形式。在此图中,Req = (Req1 Req2)
的简写表示对应于总线主设备请求输入1和2。同样,Ack = (Ack1 Ack2)
对应于仲裁器为总线主设备1和2生成的确认信号。
当没有挂起的请求时,仲裁器通常处于空闲状态(IDLE
)。如果总线主设备1和2同时发出请求,仲裁器从空闲状态转移到ACK1
状态,并生成Ack1 = 1
给总线主设备1,同时通过Ack2 = 0
忽略总线主设备2的请求。此状态转移的输入显示为Req = (1 x)
,其中Req1 = 1,Req2 = x(不关心状态)
。当总线主设备1通过发出Req1 = 0
终止数据传输时,如果总线主设备1有另一个挂起的请求,则仲裁器继续保持在ACK1
状态,否则返回到空闲状态(IDLE
)。然而,如果在ACK1
状态时仲裁器收到Req1 = 0
和Req2 = 1
,它将转移到ACK2
状态,并向总线主设备2发出Ack2 = 1
。

类似地,从空闲状态(IDLE
)到ACK2状态的转移需要Req2 = 1
和Req1 = 0
。一旦进入ACK2
状态,仲裁器通过发出Ack2 = 1
和Ack1 = 0
向总线主设备2授予总线使用权。当总线主设备2通过发出Req2 = 0
完成传输时,仲裁器要么返回到空闲状态,要么在Req1 = 1
的情况下转移到ACK1
状态。如果优先级更高的总线主设备1在优先级较低的总线主设备2进行传输时请求总线所有权(Req1 = 1
),仲裁器会保持在ACK2
状态,只要总线主设备2的Req2 = 1
,确保数据传输完成。
7.总线主设备的切换
如果当前总线主设备降低其请求,总线可能会被移交给另一个总线主设备。下图描述了这种单向总线中总线所有权的移交过程。在这个时序图中,当前总线主设备1在接收到来自仲裁器的Ack1 = 1
后,延迟一个周期生成Start
信号以启动新的传输。写入传输持续到第八周期,总线主设备发送其最后一个地址A4
。在第九周期,总线主设备发送其最后一个数据WA4
,降低其请求,并将状态改为空闲,从而终止数据传输。在第十周期的上升沿,仲裁器检测到Req1 = 0
和Req2 = 1
,并通过发出Ack1 = 0
和Ack2 = 1
切换总线所有权。新的总线主设备2在第十一周期开始新的传输,并生成其第一个地址B1
。写入传输持续到第十四周期,总线主设备2发送其最后一个数据WB2
。

8.串行接口
外设和以低频率运行的外部缓冲存储器通过串行总线与处理器通信。
目前,在低速通信中有两种流行的串行总线。串行外围接口(SPI
)由摩托罗拉于1979年引入,作为著名的摩托罗拉68000微处理器的外部微处理器总线。SPI
总线通常需要四根线,但每增加一个外设设备,线数就会增加一根。第二种总线是集成电路间总线(),由飞利浦于1982年开发,用于将飞利浦的CPU连接到电视机中的外围芯片。该总线只需要两根线,但速度比SPI总线慢得多。
串行外部接口(SPI)
SPI
被设计为一种非常简单的串行总线。四个信号实现了CPU与外围设备之间的所有串行通信。SPI
时钟信号SCK
分配给系统中的所有从设备,并使每个外围设备与单个主设备同步。选择信号(SS=select signal
)为低电平有效信号,用于在数据传输前使特定从设备处于使能状态。串行数据输出 (SDO=Serial-Data-Out
)或者主出从入(MOSI=Master-Out-Slave-In
)端口是主设备用来向从设备发送串行数据的端口。串行数据输入(SDI=Serial-Data-In
)或者主入从出(MISO
)端口是主设备用来从从设备读取串行数据的端口。
下图显示了总线主设备与单个从设备之间的串行总线配置。除了SDI
信号外,所有SPI
信号都必须由总线主设备发起。

当总线主设备连接到多个从设备时,它需要为每个从设备生成一个低电平有效的从设备选择信号,如下图所示:

SPI 是一种单主设备串行通信协议。这意味着只有一个主设备被指定来启动并执行与从设备的所有串行通信。当 SPI 主设备希望发送或请求从设备的数据时,它首先通过将相应的从设备选择()信号拉低至逻辑0来选择特定的从设备,然后为从设备生成时钟信号,如下图所示。一旦选择信号和时钟信号建立,主设备就可以在每个SCK
的下降沿通过其 SDO
端口向选定的从设备发送串行数据,同时在每个 SCK
的沿通过 SDI
端口采样从设备的数据。根据 SPI
协议,从设备能够发送和接收数据,但不能生成 SCK
。
在下图的示例中,主设备在时钟信号(SCK
)的下降沿从其SDO
端口发送串行数据,数据从DataM1
(最高有效位)到DataM4
(最低有效位)。同时,在时钟信号的上升沿,从从设备的SDI端口对其发送的串行数据进行采样,数据从DataS1(最高有效位)到DataS4
(最低有效位)。
另一方面,从设备也可以在时钟信号的下降沿从其SDO
端口发送串行数据包,数据从DataS1
(最高有效位)到DataS4
(最低有效位)。然后,在时钟信号的上升沿,从主设备的SDI
端口对从设备发送的串行数据进行采样,数据从DataM1
(最高有效位)到DataM4
(最低有效位)。

SPI
总线协议提供了四种通信模式。每种协议根据SCK
信号的初始电平(SCK稳态时的逻辑电平)和数据生成边沿进行分类。每种通信模式如下图所示。
MODE 0
通信协议假设SCK
的稳态电平为逻辑0。每个数据位由主设备(或从设备)在SCK的下降生成,并在上升沿进行采样。上面提到的工作模式就是MODE 0
协议的一个典型示例。
MODE 1
仍然假设SCK
的稳态电平为逻辑0,但数据生成发生在SCK的上升沿。在这种模式下,主设备和从设备都在负边沿读取数据。
MODE 2
将SCK
的稳态电平切换到逻辑1。数据在SCK的正边沿释放,并在负边沿进行采样,如下图所示。
MODE 3
同样假设SCK
的稳态电平为逻辑1。然而,数据在SCK的负边沿释放,并在正边沿进行采样。

一个主从对必须在数据交换期间使用相同的模式。如果使用多个从设备,并且每个从设备使用不同的通信模式,主设备在与不同从设备通信时必须重新配置自身。
SPI总线没有确认机制来确认数据接收,也不提供其他数据流控制。实际上,SPI总线的主设备不知道接收端是否存在物理从设备,也无法确定发送的数据是否被从设备正确接收。大多数SPI实现将一个字节的数据打包在一个时钟突发中,该时钟突发通常为八个时钟周期长。然而,今天许多SPI的变种使用16甚至32个时钟周期来在一个突发中发送更多的数据位,以提高速度。
Inter Integrated Circuit ()
是一种多主机总线协议,使用仅有的两根线路——串行时钟线(Serial Clock,SCL)和串行数据线(Serial Data,SDA),在总线设备(主机和从机)之间交换数据。
在这种特定的总线协议中,不需要使用从机选择信号、地址解码器或仲裁。在I2C总线上可以使用仅有的两根线路连接任意数量的从机和主机。
数据传输速率通常为100 Kbps,这是标准模式。然而,该总线可以在高速模式下运行,速率可以达到400 Kbps甚至3.4 Mbps。
在物理上,总线由两根活动线组成,即SDA
和SCL
,它们连接主设备和从设备,如下图所示。时钟生成和数据流都是双向的。这个协议假定发起数据传输的设备是总线主设备;总线上的所有其他设备被视为总线从设备。
在典型的总线中,如下图所示,总线主设备和从设备都有两个输入端口,即SCL In
和SDA In
,以及两个输出端口,即SCL Out
和SDA Out
。当主设备发出SCL Out = 1
(或者SDA Out = 1
)时,相应的N通道MOSFET开启,并将SCL
线路(或SDA
线路)拉低至地线。当主设备发出SCL Out = 0
(或者SDA Out = 0
)时,相应的n通道晶体管关闭,使得SCL(或SDA)线路悬空。然而,无论是SCL
还是SDA
,实际上都不会真正悬空到不确定的电压水平。上拉电阻Rpu
会立即将悬空线路提升到电源电压水平VDD
。在总线的另一端,从设备通过SCL In
(或者SDA In
)端口检测变化,并确定当前的总线数值。

I2C总线上每个从设备由一个七位或十位的地址字段定义,如下图所示。每个地址后的数据包长度为八位。只有四个控制信号来调节数据流:启动(Start)、停止(Stop)、写/读(Write/Read)和确认(Acknowledge)。
下图展示了七位和十位版本的读写数据传输。在该图的顶部序列解释了总线主控器如何向使用七位地址的从设备写入多个字节的数据。主控器通过产生一个开始位来启动序列。这相当于给所有从设备发出唤醒信号,使它们能够监视即将到来的地址。接下来是一个七位长的从设备地址。总线主控器首先发送最高有效地址位。剩余的地址位将逐个释放,直到最不重要的位。这时,所有从设备都会将刚刚发送的总线地址与它们自己的地址进行比较。如果地址不匹配,从设备就会忽略SDA总线上的其余传入位,并等待下一次总线传输的开始。然而,如果地址匹配,被寻址的从设备会等待下一个位,指示来自主设备的传输类型。当主设备发送写比特位时,从设备通过将SDA
线拉低来响应一个确认信号SAck
。主设备检测到确认信号后,发送第一个8位长的数据包。传输数据位的格式与地址相同:首先发送数据包的最高有效位,然后是中间位,最后是最低有效位。当所有8位数据都成功接收后,从设备会产生另一个确认信号。数据传输会一直继续,直到主设备完成所有数据包的发送。传输在主设备生成停止信号时结束。
下图中的第二个条目显示了对一个十位地址的总线从设备的写传输。在开始位之后,总线主设备发送一个五位前导码 11110,指示它将要发送一个十位从设备地址。接下来,主设备发送两个最高有效地址位,然后是写位。当从设备确认所有这些条目的传递后,主设备发送剩下的八个地址位。随后从设备再次发出确认信号,主设备将所有数据字节传输到指定的从设备。数据传输在总线主设备生成停止位时完成。
下图中的第三个和第四个条目展示了由总线主设备发起的七位和十位读序列。在每个序列中,接收到开始位和地址后,指定的从设备开始向主设备发送数据包。在成功接收到第一个数据字节后,主设备向从设备发送确认信号 MAck,之后从设备传输下一个字节。传输持续进行,直到从设备将其所有数据字节传送给主设备。然而,就在主设备发出停止位之前,它会生成一个不确认信号 MNack,表示传输结束,如图所示。

开始(Start
)和停止(Stop
)信号是由SCL
和SDA
值的组合生成的,如下图所示。根据该图,当总线主设备将SDA
线拉到地时且SCL = 1
时,会产生一个开始信号。类似地,当总线主设备释放SDA
线时且SCL = 1
时,会创建一个停止信号。

下图显示了何时允许数据更改以及何时需要保持稳定。I2C 协议仅允许在 SCL 为逻辑 0 时更改数据。如果 SDA 上的数据在 SCL 为逻辑 1 时发生变化,这可能会根据数据转换被解释为启动或停止条件。因此,只要 SCL = 1,SDA 上的数据就不允许更改。

下图解释了在具有七位地址的从设备上总线主机向其写入两个字节数据的时序图。根据该图,写入过程始于在SCL = 1
时将SDA
的值转换为逻辑0。随后是起始位,从最高有效位SA[6]
到最低有效位SA[0]
的从设备地址位逐个传递。根据I2C总线协议,每个地址位只在SCL
为逻辑0
时才会被引入SDA
。接下来生成写命令及随后的从设备应答。字节0和字节1中的数据位也从最高有效数据位D[7]
开始逐个传递到SDA
。写入序列在SCL = 1
时SDA
转换为逻辑1,完成写入过程。

下图展示了从从设备读取两个字节数据的时序图。在起始位和从设备地址后,主机通过SDA = 1
发出读取命令。随后,数据字节从从设备传输到主机,并且主机在接收每个数据字节时进行确认。传输在主机不确认最后一个数据字节(MNack
)并生成停止位时结束。

这就是为什么I2C总线协议在只使用两根物理线路的情况下,能够在任意数量的主设备和从设备之间保持无故障通信的原因。例如,如果两个或多个设备同时尝试在SDA上写入数据会发生什么情况?在电气级别上,实际上没有多个设备同时在总线上竞争逻辑电平的情况。如果一个特定设备试图向总线写入逻辑0,而另一个设备试图写入逻辑1,那么在上面的原理图中带有上拉电阻的物理总线结构确保这两个设备之间不会发生冲突,并且总线会转换为逻辑0。换句话说,在任何冲突中,逻辑0总是胜出!
I2C总线的这种物理结构还使得总线主机能够自由地从总线上读取数值或向总线上写入数值,而无需担心碰撞的危险。在两个主机之间发生冲突的情况下(假设一个主机尝试写入逻辑0,另一个尝试写入逻辑1),试图写入逻辑0的主机会在不知情的情况下获得总线的使用权。只有试图写入逻辑1的主机会意识到失去了总线访问权,因为它在尝试写入逻辑1时从总线上读取到了逻辑0。在大多数情况下,这个设备会延迟其访问,并稍后再试。
此外,这种总线协议还有助于处理通信问题。总线上的任何设备都会监听总线活动,特别是起始位和停止位的存在。在I2C总线上,潜在的总线主机检测到起始信号后会等待直到检测到停止信号,然后才尝试访问总线。同样地,未寻址的从设备会在发出停止位之前返回到休眠模式。
类似地,主从设备在传输每个字节后通过主动低电平的应答位互相确认彼此的存在。如果出现问题,发送数据的设备未能从接收方检测到应答,那么该设备会简单地发出停止位以终止数据传输并释放总线。
I2C通信的一个重要元素是主设备确定时钟速率以与从设备同步。如果存在I2C从设备无法跟上主设备速率过快的情况,主设备可以通过称为“时钟拉伸”的机制降低频率。根据这种机制,如果I2C从设备需要总线主机降低总线速度,它允许保持SCL为逻辑0。主设备必须始终观察SCL信号电平,并在从设备不再将线拉到逻辑0时继续数据传输。
总的来说,SPI和I2C都提供了对低速外设通信的良好支持。SPI更快速,更适合单总线主应用,其中设备彼此流式传输数据,而I2C速度较慢,更适合多主应用。这两种协议提供了相同的健壮性水平,并在生产闪存存储器、模数转换器、数模转换器、实时时钟、传感器、液晶显示控制器等领域中都取得了同样成功。