考虑SPI或I2C时需要权衡?


116

在决定使用SPI或I2C接口时应该考虑哪些权衡?

该加速度计/陀螺仪分接板有两种型号,每个接口一个。哪一个更容易集成到Arduino项目中?

http://www.sparkfun.com/products/11028

在此处输入图片说明


13
I2C和SPI有其优势。I2C的设置更为复杂,一旦稳定,您就可以轻松扩展(只要您的总线接线不会太长或太大)。SPI易于设置..如果需要,可以非常容易地对其进行位冲击。扩展与所有芯片选择一起吃I / O。如果我拥有丰富的I / O和连接器空间,并且不需要总线,那么我将始终使用SPI。
汉斯

I2C如何更复杂?我在不同的微处理器(小型PIC和尺寸合适的ARM)上都使用了这两种总线,并且在每种情况下I2C的设置都比较简单(即,更少的寄存器可写)。如果有的话,由于时钟极性和数据采样选项,SPI更复杂。
Armandas 2012年

6
@Armandas-没办法!SPI有4种可能的时钟/数据极性模式,其中两种占主导地位-几乎所有SPI器件都在时钟的下降沿更新其MISO输出,并在时钟的上升沿读取其MOSI输入。您可以通过查看数据表在几分钟之内找出哪一个,然后完成。如果您错误地选择了错误的模式,则一旦查看示波器走线,就会很快发现它。SPI数据错误很少见,不会像I2C那样陷入怪异状态。
杰森S

6
我说I2c更为复杂,因为我曾经不得不在ARM处理器上编写I2C驱动程序。我遵循了NXP文档的状态机,它大约有20个州。我花了相当多的时间弄清楚确认,何时读/写了最后一个字节等。我从未遇到过SPI的任何这些问题,只需要整理时钟和数据即可。
汉斯

1
@JonL,以及坦率地说,我至今已经提供了一个完整的答案只有一个,因为我是唯一一个,讨论具体的接口板的OP想要使用的问题,并指出,这是提供包括SPI和I2C,但只有I2C -因此,如果他要使用此特定的板,必须使用I2C。其他仅涉及哪个接口(SPI或I2C)更易于接口,我也介绍了该接口。
tcrosley

Answers:


97

摘要

  • SPI更快。
  • 如果您的微控制器没有I2C控制器,则I2C更为复杂且不那么容易使用。
  • I2C仅需要2条线。

I2C是在SDA线上具有双向数据的总线系统。SPI是点对点连接,数据输入和数据输出在单独的线(MOSI和MISO)上。

本质上,SPI由一对移位寄存器组成,您可以在其中将数据输入一个移位寄存器,而将数据从另一个移出。通常,每次连续8个时钟脉冲以字节为单位写入数据,但这不是SPI的要求。如果愿意,您还可以设置16位甚至13位的字长。在I2C中,同步是通过SPI中的启动序列来完成的,而同步是由SS变为高电平(SS为低电平有效)来完成的。您可以确定这是多少个时钟脉冲。如果使用13位字,SS将在13个时钟脉冲后锁存最后一个时钟输入位。
由于双向数据位于两条不同的线上,因此很容易进行接口。

标准模式下的SPI至少需要四条线:SCLK(串行时钟),MOSI(主机输出从机输入),MISO(主机输入从机输出)和SS(从机选择)。在双向模式下至少需要三条线:SCLK(串行时钟),MIMO(主输入主输出)和MOSS(从选择),其中MOSI或MISO线之一。在具有多个从站的系统中,每个从站都需要一条SS线,因此对于从站,在标准模式下您需要N + 3条线,在双向模式下您需要N + 2条线。如果您不希望这样做,则可以在标准模式下,通过将一个从站的MOSI信号连接到下一个从站的MISO信号,以菊花链方式连接从站。这将减慢通信速度,因为您必须循环访问所有从站数据。ññ+3ñ+2

就像tcrosley所说的那样,SPI的工作频率比I2C高得多。

I2C有点复杂。由于它是总线,因此您需要一种寻址设备的方法。您的通信从一个独特的开始序列开始:当时钟(SCL)为高时,数据线(SDA)被拉低,而其余的通信数据仅在时钟为低时才被改变。该开始序列同步每个通信。
由于通信包括寻址,所以对于任何数量的设备(最多127个)仅需要两条线。

编辑
显然,数据线是双向的,但值得注意的是,时钟线也是如此。从站可能会延长时钟来控制总线速度。这使得I2C不太方便进行电平转换或缓冲。(标准模式下的SPI线都是单向的。)

发送每个字节(地址或数据)后,接收器必须通过在SDA上放置一个确认脉冲来确认接收。如果您的微控制器具有I2C接口,则将自动进行处理。如果您的微控制器不支持它,您仍然可以对其进行位冲击,但是对于每个确认或读取数据,您都必须将I / O引脚从输出切换为输入,除非您使用I / O引脚进行读取和读取。一种写作。

在400kHz时,标准I2C比SPI慢得多。有些高速I2C器件的工作频率为1MHz,但仍比20MHz的SPI慢得多。


7
我还没有遇到能够处理I2C所有极端情况的微控制器,因此需要以无需成为I2C专家就可以使用的方式来处理正确的错误检测和恢复。我一直不得不从“智能” I2C外围设备降级到临时性地砰砰地跳,以处理SDA保持为低电平时的时钟丢失情况,这是一个完全的痛苦。/–
Jason S

(但+1,因为我同意您的其余回答)
Jason

甚至还有I2C设备,其工作频率为3.4MHz,但是我不确定这些设备是否可以与速度较慢的设备结合使用(因为所有设备都必须能够遵循总线寻址)。我也相信3.4MHz I2C的时序有点不同。
汉斯

@Hans-HS I2C似乎与更常见的400kbit设备向下兼容。坦率地说,(没有进行深入研究)我从未见过支持HS的微控制器(至今),这就是为什么我不想提及它。
stevenvh 2012年

@stevenvh:某些控制器的两线制实现(例如赛普拉斯PSOC)要求SCK在内部时钟至少保持一两个周期之前为低电平,然后才将其锁存,否则将导致严重故障。我不知道为什么没有系统时钟脉冲他们就无法检测和时钟拉伸I2C启动条件,但是这种行为意味着当这种芯片以较低的系统时钟速度运行时,总线上的所有I2C事务必须运行缓慢)。对于以3MHz运行的PSOC而言,即使400Khz的操作速度也太快了。
supercat 2012年

39

(编辑:要清楚,以下许多问题与Ilin / I2C / SPI设备的板对板使用引起的信号完整性有关。)

除非您有约束力将您推向更少的电线(我们有一个项目采用的是密封连接器,每个附加的触点都相当昂贵),否则请尽可能避免使用I2C,并坚持使用SPI。

SPI在硬件和软件基础上都非常容易处理。在硬件中,有两条共享数据线,即主机输入从机输出(MISO或SOMI)和主机输出从机输入(MOSI或SIMO),主机生成的共享时钟以及每个设备一个芯片选择。CS线变为低电平,时钟周期并实质上移入输入位并移出输出位,直到事务完成为止,此时CS线变为高电平。当它们的CS线为高电平时,从设备不进行通信:它们忽略CLK和MOSI线,并将其MISO引脚置于高阻抗状态,以供其他人使用。

如果您有一个使用多个SPI设备的微控制器,并且具有内置的SPI外设,则将微控制器的CS输出发送到解复用器(例如74HC138),并控制地址线在SPI事务之间选择设备;您可以将字写到寄存器中以使其排队等候输出,并在CS引脚变为高电平后将其读回。

由于SPI信号都是单向的,因此可以对其进行缓冲,与数字隔离器一起用于隔离栅,并可以使用LVDS之类的线路驱动器在板与板之间发送信号。您唯一需要担心的是往返传播延迟,它将限制您的最大频率。


I2C是一个完全不同的故事。尽管从布线的角度来看要简单得多,但只有两条线SCL和SDA,这两条线都是共享的双向线,它们使用带有外部上拉的开漏器件。有一个I2C协议以传输设备地址开始,因此,如果每个设备都有自己的地址,则可以使用多个设备。

从硬件的角度来看,在噪声较大的系统中很难使用I2C。为了缓冲或隔离I2C线路,您必须求助于奇异的IC-是的,它们存在,但数量不多:我们在一个项目上使用了一个,并意识到可以使用一个隔离器,但不能使用两个串联-它使用小的电压降来确定物体的驱动端是哪一侧,而两个串联的电压降是两个。

I2C的逻辑电平阈值取决于Vcc,因此,如果在同一系统中使用3V / 3.3V和5V器件,则必须格外小心。

任何使用一英尺或两英尺以上电缆的信号都必须担心电缆电容。多芯电缆的电容为100pf /米。这导致您必须降低总线速度或使用较低的上拉电阻,才能正确处理额外的电容并满足上升时间要求。

因此,假设您拥有一个设计良好的系统,并且可以处理大多数信号完整性问题,并且噪声很少(但仍然存在)。你要担心什么

您必须准备处理许多错误条件:

  • 从设备不应答特定字节。您必须检测到这一点,然后停止并重新启动通信序列。(使用SPI,如果要确保已正确接收到数据,通常可以读回发送的数据。)

  • 您正在从从设备读取一个字节的数据,并且由于时钟线上的噪声而将该设备“催眠”:您已发送了必需的8个时钟来读取该字节,但是由于噪声,从设备认为它已接收到7个时钟,并且仍在数据线上发送0。如果设备已接收到第8个时钟,它将释放数据线为高电平,以便主机可以升高或降低数据线以发送ACK或NACK位,或者主机可以发送停止(P)条件。但是从机仍将数据线保持在低电平,徒劳地等待另一个时钟。如果主机不准备尝试额外的时钟,则I2C总线将陷入死锁状态。虽然我使用了几种微控制器来处理正常的ACK / NACK条件,

  • 真正糟糕的情况是,当一个主设备正在将数据写入一个从属设备,而另一个从属设备则错误地解释了设备地址,并认为传输的数据是为该设备指定的。我们有一些I2C设备(I / O扩展器),因此有时会错误地设置寄存器。要检测这种情况几乎是不可能的,并且要对噪声具有鲁棒性,您必须定期设置所有寄存器,这样,如果您确实遇到此错误,至少可以在短时间内将其修复。(SPI永远不会出现此问题-如果您碰巧在CS线上出现故障,它将永远不会持续很长时间,并且您不会被错误的从属设备意外读取数据。)

如果存在错误检测(CRC码),则协议中的许多条件都可以正确处理,但是很少有设备具有此功能。


我发现我必须在I2C主设备中构建复杂的软件来处理这些情况。我认为,除非接线方面的限制迫使我们使用I2C而不是SPI,否则这是不值得的。


5
您对IIC的宗教厌恶在这里无处可寻。IIC和SPI都擅长于各自的工作,并且各有千秋。您对IIC的大多数反对意见都来自对IIC的不当使用。尽管IIC通常在电源行业中用于控制智能电源,但IIC应该仅被认为是板载的。如果您发现自己需要IIC缓冲区,那么就很强烈地表明IIC不是正确的解决方案。但是,IIC对于所有在同一板上的低速设备非常有效。
Olin Lathrop'4

2
I2C的逻辑电平阈值取决于Vcc,因此,如果在同一系统中使用3V / 3.3V和5V器件,则必须格外小心。不,这是错误的。IIC逻辑阈值为固定电压。您可以通过线拉至只有3.3 V.平凡混合5个V和3.3 V系统
奥林莱思罗普

5
这不是对I2C的宗教厌恶,而是对I2C的实际厌恶。您认为使用车载系统更容易,这是正确的;我会在合理的情况下使用它,但这会增加软件成本,并且太多的硬件工程师只是将I2C设备粘贴在板上,而没有讨论导致更多软件麻烦的折衷方案。
杰森S

3
IIC在电气上更容易实现,而SPI在固件中可能更容易实现。然而,从两个方面来看,两者都非常容易和直截了当。
Olin Lathrop '04年

2
@Olin-过去似乎使用固定的1.5 V阈值,但根据最新版本的规范,阈值确实为0.3 Vcc和0.7 Vcc。规范中的引用提到了传统设备的1.5V。
stevenvh 2012年

16

实际上,SparkFun的设备分线板仅适用于I2C版本(MPU-6500)。MPU-6000版本在同一芯片上同时具有SPI和I2C接口,我看不到SparkFun有一块带有该芯片的电路板。因此,我相信如果您要使用该特定板子,则只能使用I2C。但是出于以下原因,无论如何我还是建议您使用I2C。

通常,从硬件的角度来看,您会发现I2C总线比SPI总线更易于使用。I2C是2线总线(SCL / SDA):

SCL – Serial clock.
SDA – Serial data (bidirectional).

SPI是4线总线(SCLK / MOSI / MISO / CS):

SCLK– Serial clock.
MOSI – Master-out, Slave-in. Data from the CPU to the peripheral.
MISO – Master-in, Slave out. Data from the peripheral back to the CPU.
CS – Chip select.

您可以将多个设备连接到一条I2C总线。每个设备都有内置于芯片中的自己的一组地址。该地址实际上在总线上作为每个命令的第一个字节(连同读/写位)一起广播。对于相同的功能,这以及其他一些开销要求通过I2C总线与SPI发送更多位。

不同类别的设备(内存,I / O,LCD等)具有不同的地址范围。某些设备在系统中通常不止一次使用(例如PCF8574 I / O扩展器),它们使用一条或多条地址线(对于PCF8574为AD0-2),可以将其绑定为高电平或低电平以指定低位地址的。MPU-6500具有一个这样的地址线(AD0),因此其中两个可以在同一系统中使用。

您还可以在SPI总线上具有多个设备,但是每个设备必须具有自己的片选(CS)线。因此4线描述有点用词不当-实际上是3线接口+每个设备增加一条线。我对Arduino系列板没有经验,但是我相信这会使在Arduino上使用SPI更加困难,因为如果您需要大量的芯片选择线,那么各种屏蔽使用的通用引脚分配将变得很麻烦。

我相信大多数Arduino开发板都以5伏电压运行,而一些较新的板则以3.3v运行。MPU-6500在3.3v下运行。如果5v CPU上I2C总线的最小输入“高”电压为3v或以下,则可以通过在SCL和SDA线上仅提供10K上拉电阻至3.3v来避免电平转换问题,因为总线是开放的,集电极。确保禁用CPU上的任何5v内部上拉电阻。

但是我检查了ATmega2560的数据表(以ADK 5v Arduino为例),其最小输入“高”电压为0.7 * Vcc或3.5v(大于3.3v),因此您需要某种有源电平TI PCA9306在芯片的5v和3.3v侧均需要上拉电阻,单颗价仅为78美分。

为什么然后选择I2C上的SPI?主要是因为SPI可以更快地运行-在某些情况下高达10兆赫兹。I2C通常限制为400 KHz。但这对于MPU-6050 / 6000加速度计来说并不是真正的问题,因为它在I2C上以400 KHz运行,而在SPI上仅以1 MHz运行-差别不大。


3
在I2C上选择SPI的另一个原因:所有线路都是单向的,这使电平转换器之类的事情变得容易一些。
2012年

3
I2C比SPI更容易吗?如果您可以将所有内容挂钩在一起,那么I2C唯一简单的事情就是连接性。否则,在I2C中信号完整性将变得更加困难,而在I2C中强大的软件实现将变得更加困难。
杰森S

2
@JasonS,我已经使用I2C完成了许多嵌入式软件项目,并且从未遇到过您在帖子中提到的锁定问题。我可以理解,由于您的不良经历,您不喜欢它。我目前在市场上有一款产品使用I2C DAC输出音频,同时通过SPI从SD卡读取下一个数据缓冲区。效果很好。由于总线争用和音频中断,我无法同时将SPI用于DAC和SD卡。微型(低端)只有一个SPI和一个I2C端口。
tcrosley 2012年

1
您可以将音频输出到I2C DAC给我留下了深刻的印象!(最大时钟速率是多少?)如果您使用的是短期运行的板载IC,则发生锁定的可能性非常小,但仍然存在。(而且,如果您只是向I2C写入数据,就永远不会遇到它。它要求您从愿意永远等待它认为丢失/多余的时钟的设备上进行读取。)
Jason S

1
@JasonS,音频只是8KHz的语音质量-我正在使用128 us中断来输出每个16位样本。I2C也会在自己的中断上运行。空闲时间用于从SD卡读取数据。关于锁定的好点是从未在编写时发生过。除了ADC,我通常将I2C用于输出设备。但是,您是否知道Wii遥控器和Wii Nunchuck(通过3'电缆)之间的只读接口(2个按钮,加速计和操纵杆)是400 KHz的I2C吗?网路上的许多资讯都重新入侵了这个装置的介面。
tcrosley 2012年

15

通常,SPI是一条更快的总线-时钟频率可以在MHz范围内。但是,SPI至少需要3条线进行双向通信,并为总线上的每个设备选择一个附加的从器件选择。

I2C仅需要2条线路,而不管您有多少个设备(当然,在限制范围内)。但是,速度在kHz范围内(典型值为100-400kHz)。

如今,大多数微控制器都为两条总线提供硬件支持,因此两者的使用同样简单。


4
@Jason:您似乎对IIC有一些偏见,但因此而向其他人讨价还价是不公平的。IIC和SPI都很“容易”,每个都有自己的皱纹。SPI需要额外的线路,这并不容易。IIC稍微复杂一点,但是要完成所有固件实现仍然很容易,我有时可能会这样做。它并不需要那么多代码。两者都有自己的位置,而且两者都很容易,以至于不会成为任何知道自己正在做的事情的因素。
Olin Lathrop'4

5
@Jason:我刚刚检查了一下,而我的用于IIC在8位PIC上的固件实现的通用IIC代码只有311行,其中可能有一半以上是注释。这使您可以在启动,放置,获取,停止等例程级别上与IIC总线建立过程接口。一个模块来驱动一个简单的EEPROM是272行,可能也是1/2条注释,并且包含一些高级管理,例如默认数据,UART调试接口等。这是如此琐碎,以至于争论是否少花10条指令比SPI毫无意义。
Olin

2
@Andrew Kohlsmith-- I2C is designed for on-board applications.显然I2C设备制造商不同意您的看法。拿TMP100。该产品页明确指出:The TMP100 and TMP101 are ideal for extended temperature measurement in a variety of communication, computer, consumer, environmental, industrial, and instrumentation applications.同样是真实的TMP75
康纳狼

5
@FakeName您不正确;我花了13年时间从事工业电力电子学。(启动和监视大型三相电动机是一个非常嘈杂的环境)并不是说SPI更加可靠,而是要设计出计划并考虑了所有故障模式的系统,并在需要时在系统中内置恢复选项。我从来没有遇到过噪声尖峰杀死我的I2C(或SPI)通信,但我也从来没有完全依靠I2C控制器来为我做任何事情。这是规划和设计的问题,而不是一辆公交车会更好。
akohlsmith 2012年

2
@akohlsmith:单主机单从I2C应该具有“位爆炸”主机的鲁棒性。如果有多个从设备,并且两个从设备同时以不同的方式被“混淆”,则总线可能无法恢复锁定(例如,如果两个或多个填充有零的内存芯片都认为主设备正在尝试读取它们,但是它们的位计数器不同步的,那么每个将只在次释放SDA时,另一种是断言它,并没有什么高手能做到将释放总线,除非它可以驱动一个“高”强大到足以超速所有的奴隶。
supercat

12

SPI的运行速度比I2C快得多(某些SPI设备的运行频率超过60MHz;我不知道“官方” I2C规范是否允许设备超过1MHz)。使用这两种协议来实现从设备都需要硬件支持,而两者都可以轻松实现“软件位爆炸”主设备。使用相对最少的硬件,就可以构造一个符合I2C的从机,即使主机可以一次决定在500us的时间内无视总线,而又不需要额外的握手线路,它也可以正常运行。可靠的SPI操作,即使有硬件支持,也通常要求增加一条握手线,或者要求主机“手动”在每个字节之后添加一个延迟,该延迟等于从机的最坏情况响应时间。

如果我有德雷特,控制器的SPI支持将包含一些简单的额外功能,以使用握手和唤醒功能的控制器之间总共使用三条单向电线(时钟和MOSI [主主机的[out-slave-in];从站的MISO [master-in-slave-out]。相比之下,当带有“备用” SPI端口的微控制器之间进行有效且可靠的通信时,两个处理器都可能被独立延迟任意时间长度,则需要使用更多的电线(启动芯片选择,时钟,MISO和MOSI)如果从站可能开始异步发送数据(例如,因为有人按下了按钮),那么一个从站可能必须使用另一根线作为“唤醒”。

I2C并没有提供我的“改进” SPI所具有的全部功能,但它确实提供了SPI所缺乏的内置握手功能,并且在许多实现中,即使主控方是一个主叫方,也可以将其唤醒。软件位爆炸。因此,对于处理器间通信,我强烈建议使用SPI上的I2C,除非需要的速度比SPI所能提供的更高,并且可以使用额外的引脚。对于需要低引脚数的处理器间通信,UART有很多建议。


I2C有一个高速版本,允许1MHz的频率。正常的I2C为400kHz。
抵抗力量

@TheResistance:我知道正常的I2C为400kHz,但指定的版本最高为1MHz。我不知道是否指定了更快的版本。
2013年

根据规范,400kbps(不是kHz,我在这里使用了错误的单位)是快速模式,1Mbps是快速模式Plus,并且有一个高达3.4Mbps的高速模式。超快速可达5Mbps,但是单向的。
抵抗

@TheResistance:谢谢。我没有听说过这些更高版本。“单向”到底是什么意思?我知道SPI从机到主机的通信速度可以快于主机到从机,因为可以保证从机在主机之后获得时钟,但是我不确定I2C的等效概念。有一个链接?
supercat

此处找到规格。在第23页上说,超快速可用于不发回数据(仅写)甚至不发回数据的设备。
抵抗

8

这个问题已经在此处的出色答案中进行了深入探讨,但是从芯片制造商的角度来看,也许我还可以提供I 2 C 的另一种观点。

I 2 C的电气接口是集电极开路。现在,呼吸一下,思考其中的含义。使用I 2 C,我可以设计一个与总线的工作电压完全无关的芯片。我需要做的就是将SDA线拉低(如果我愿意),然后将SCL和SDA的电压与一些我可以选择的接地基准阈值电压进行比较。而且,如果我省去了普通的高端保护结构并用其他结构替换,我可以制造出完全可以独立于系统其余部分使用的芯片-SCL,SDA永远不会向我的芯片提供任何电流,当然不会向这些引脚提供任何电流。这就是为什么它对于实时时钟和其他类似低功耗设备而言如此出色。


4

在其他答案中我没有看到的一件事是I2C在同一总线上支持多个主机。如果您需要双向通信并且不想使用基于轮询的方法,则I2C将完成这项工作。

在更长的距离上,CAN具有相同的功能并且更坚固。但是CAN是需要硬件支持和收发器的异步协议,因此在低成本系统中可能不是一个选择。


好一点(在多主设备上),我还看到了带有中断引脚的SPI设备,而一个设备仍然是主设备,两者都可以实例化(双向)通信。对于远程设备,当然有更可靠和更好的选择(例如CAN)。
保罗

0

每当同步时钟上升时,使用SPI协议并将您的位直接写入设备。xnor逻辑电路可用于匹配存储器中的“自制”地址,以选择所需设备,就好像它是i2c设备一样。

i2c正在将授权电路集成到设备的格式中,标准...等复杂而又不同,使用spi,您可以使用spi存储器在屏幕上显示视频,但不能使用i2c。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.