在决定使用SPI或I2C接口时应该考虑哪些权衡?
该加速度计/陀螺仪分接板有两种型号,每个接口一个。哪一个更容易集成到Arduino项目中?
在决定使用SPI或I2C接口时应该考虑哪些权衡?
该加速度计/陀螺仪分接板有两种型号,每个接口一个。哪一个更容易集成到Arduino项目中?
Answers:
摘要
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信号,以菊花链方式连接从站。这将减慢通信速度,因为您必须循环访问所有从站数据。
就像tcrosley所说的那样,SPI的工作频率比I2C高得多。
I2C有点复杂。由于它是总线,因此您需要一种寻址设备的方法。您的通信从一个独特的开始序列开始:当时钟(SCL)为高时,数据线(SDA)被拉低,而其余的通信数据仅在时钟为低时才被改变。该开始序列同步每个通信。
由于通信包括寻址,所以对于任何数量的设备(最多127个)仅需要两条线。
编辑
显然,数据线是双向的,但值得注意的是,时钟线也是如此。从站可能会延长时钟来控制总线速度。这使得I2C不太方便进行电平转换或缓冲。(标准模式下的SPI线都是单向的。)
发送每个字节(地址或数据)后,接收器必须通过在SDA上放置一个确认脉冲来确认接收。如果您的微控制器具有I2C接口,则将自动进行处理。如果您的微控制器不支持它,您仍然可以对其进行位冲击,但是对于每个确认或读取数据,您都必须将I / O引脚从输出切换为输入,除非您使用I / O引脚进行读取和读取。一种写作。
在400kHz时,标准I2C比SPI慢得多。有些高速I2C器件的工作频率为1MHz,但仍比20MHz的SPI慢得多。
(编辑:要清楚,以下许多问题与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,否则这是不值得的。
实际上,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运行-差别不大。
通常,SPI是一条更快的总线-时钟频率可以在MHz范围内。但是,SPI至少需要3条线进行双向通信,并为总线上的每个设备选择一个附加的从器件选择。
I2C仅需要2条线路,而不管您有多少个设备(当然,在限制范围内)。但是,速度在kHz范围内(典型值为100-400kHz)。
如今,大多数微控制器都为两条总线提供硬件支持,因此两者的使用同样简单。
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有很多建议。
这个问题已经在此处的出色答案中进行了深入探讨,但是从芯片制造商的角度来看,也许我还可以提供I 2 C 的另一种观点。
I 2 C的电气接口是集电极开路。现在,呼吸一下,思考其中的含义。使用I 2 C,我可以设计一个与总线的工作电压完全无关的芯片。我需要做的就是将SDA线拉低(如果我愿意),然后将SCL和SDA的电压与一些我可以选择的接地基准阈值电压进行比较。而且,如果我省去了普通的高端保护结构并用其他结构替换,我可以制造出完全可以独立于系统其余部分使用的芯片-SCL,SDA永远不会向我的芯片提供任何电流,当然不会向这些引脚提供任何电流。这就是为什么它对于实时时钟和其他类似低功耗设备而言如此出色。