Tradeoffs when considering SPI or I2C?

Summary

  • SPI is faster.
  • I2C is more complex and not as easy to use if your microcontroller doesn't have an I2C controller.
  • I2C only requires 2 lines.

I2C is a bus system with bidirectional data on the SDA line. SPI is a point-to-point connection with data in and data out on separate lines (MOSI and MISO).

Essentially SPI consists of a pair of shift registers, where you clock data in to one shift register while you clock data out of the other. Usually data is written in bytes by having each time 8 clock pulses in succession, but that's not an SPI requirement. You can also have word lengths of 16 bit or even 13 bit, if you like. While in I2C synchronization is done by the start sequence in SPI it's done by SS going high (SS is active low). You decide yourself after how many clock pulses this is. If you use 13 bit words the SS will latch the last clocked in bits after 13 clock pulses.
Since the bidirectional data is on two separate lines it's easy to interface.

SPI in standard mode needs at least four lines: SCLK (serial clock), MOSI (Master Out Slave In), MISO (Master In Slave Out) and SS (Slave Select). In bideroctional mode needs at least three lines: SCLK (serial clock), MIMO (Master In Master Out) which is one of the MOSI or MISO lines and SS (Slave Select). In systems with more than one slave you need a SS line for each slave, so that for \$N\$ slaves you have \$N+3\$ lines in standard mode and \$N+2\$ lines in bidirectional mode. If you don't want that, in standard mode you can daisy-chain the slaves by connecting the MOSI signal of one slave to the MISO of the next. This will slow down communication since you have to cycle through all slaves data.

Like tcrosley says SPI can operate at a much higher frequency than I2C.

I2C is a bit more complex. Since it's a bus you need a way to address devices. Your communication starts with a unique start sequence: the data line (SDA) is pulled low while the clock (SCL) is high, for the rest of the communication data is only allowed to change when the clock is low. This start sequence synchronizes each communication.
Since the communication includes the addressing only two lines are required for any number of devices (up to 127).

edit
It's obvious that the data line is bidirectional, but it's worth noting that this is also true for the clock line. Slaves may stretch the clock to control bus speed. This makes I2C less convenient for level-shifting or buffering. (SPI lines in standard mode are all unidirectional.)

After each byte (address or data) is sent the receiver has to acknowledge the receipt by placing an acknowledge pulse on SDA. If your microcontroller has an I2C interface this will automatically be taken care of. You can still bit-bang it if your microcontroller doesn't support it, but you'll have to switch the I/O pin from output to input for each acknowledge or read data, unless you use an I/O pin for reading and one for writing.

At 400kHz standard I2C is much slower than SPI. There are high-speed I2C devices which operate at 1MHz, still much slower than 20MHz SPI.


(edit: To be clear, many of the following concerns have to do with signal integrity caused by board-to-board use of I2C/SPI devices, as Olin correctly points out.)

Unless you have constraints that strongly push you towards fewer wires (we had one project with a hermetically-sealed connector that each additional contact was rather expensive), avoid I2C when possible, and stick with SPI.

SPI is fairly easy to deal with on a hardware and a software basis. In hardware, there are two shared data lines, Master In Slave Out (MISO or SOMI) and Master Out Slave In (MOSI or SIMO), a shared clock generated by the master, and one chip select per device. The CS line goes low, the clock cycles and essentially shifts in input bits and shifts out output bits, until the transaction finishes, at which point the CS line goes high. When their CS line is high, slave devices don't communicate: they ignore the CLK and MOSI lines, and put their MISO pin into a high-impedance state to let someone else use it.

If you have a microcontroller using several SPI devices, and it has a built-in SPI peripheral, send the microcontroller's CS output to a demultiplexer (e.g. 74HC138) and control the address lines to select the device between SPI transactions; you write words to a register to queue them up for output, and read them back after the CS pin is raised high.

Because SPI signals are all unidirectional, they can be buffered, used across an isolation barrier with digital isolators, and can be sent from board to board using line drivers like LVDS. The only thing you have to worry about is the round-trip propagation delay, which will limit your maximum frequency.


I2C is a completely different story. While it's much simpler from a wiring standpoint, with only two wires SCL and SDA, both these lines are shared bidirectional lines that use open-drain devices with an external pullup. There's a protocol for I2C that starts by transmitting a device address, so that multiple devices can be used if each has their own address.

From a hardware standpoint, it is very difficult to use I2C in systems that have any significant noise. In order to buffer or isolate I2C lines, you have to resort to exotic ICs -- yes, they exist, but there aren't many: we used one on one project and realized that you could use one isolator, but you couldn't use two in series -- it used small voltage drops to figure out which side was the driving end of things, and two series drops were two much.

The logic level thresholds of I2C depend on Vcc so you have to be really careful if you use 3V/3.3V and 5V devices in the same system.

Any signals that use a cable of more than a foot or two have to worry about cable capacitance. Capacitance of 100pf/meter isn't out of the ordinary for multiconductor cable. This causes you to have to slow down the bus, or use lower pullup resistors, to be able to handle the extra capacitance properly and meet the rise time requirements.

So let's say you have a system that you think you've designed well, and you can deal with most of the signal integrity issues, and noise is rare (but still present). What do you have to worry about?

There are a bunch of error conditions you have to be prepared to handle:

  • Slave device doesn't acknowledge a particular byte. You have to detect this and stop and restart the communications sequence. (With SPI, you can usually read back the data you send if you want to make sure it was received without error.)

  • You're reading a byte of data from a slave device, and the device is "hypnotized" because of noise on the clock line: You have sent the requisite 8 clocks to read that byte, but because of noise, the slave device thinks it has received 7 clocks, and is still transmitting a 0 on the data line. If the device had received the 8th clock, it would have released the data line high so that the master could raise or lower the data line to transmit an ACK or NACK bit, or the master could transmit a stop (P) condition. But the slave is still holding the data line low, waiting in vain for another clock. If a master is not prepared to try extra clocks, the I2C bus will be stuck in deadlock. While I have used several microcontrollers that handle the normal ACK/NACK conditions, I have never used one that handles this missed clock bit (or extra clock bit) condition successfully, and I've had to exit automatic I2C mode, enter into bit-banging mode, add clocks until the data line is high, and re-enter automatic I2C mode.

  • The really awful case is when a master is writing data to one slave device, and another slave interprets the device address incorrectly and thinks that the data transmitted is meant for it. We've had I2C devices (I/O expanders) that occasionally have registers set incorrectly because of this. It is nearly impossible to detect this case, and to be robust to noise, you have to periodically set all registers, so that if you do run into this error, at least it will be fixed after a short period of time. (SPI never has this problem -- if you happen to have a glitch on the CS line, it will never persist for long and you won't get data accidentally read by the wrong slave device.)

A lot of these conditions could be handled properly in the protocol if there were error detection (CRC codes), but few devices have this.


I find that I have to build complex software in my I2C master device to handle these conditions. In my opinion, it's just not worth it unless the constraints on wiring force us to use I2C and not SPI.


The breakout board for device at SparkFun is actually for the I2C version only (MPU-6500). The MPU-6000 version has both SPI and I2C interfaces on the same chip, and I don't see that SparkFun has a board with that chip. So I believe you are limited to using I2C if you want to use that particular board. But I was going to recommend using I2C anyway in your situation for the following reasons.

In general, you will find that the I2C bus is easier to use from a hardware standpoint than the SPI bus. I2C is a 2 wire bus (SCL/SDA):

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

SPI is a 4 wire bus (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.

You can have several devices connected to one I2C bus. Each device has its own set of address(es) built-in to the chip. The address is actually broadcast over the bus as the first byte of every command (along with a read/write bit). This, along with some other overhead, requires more bits to be sent over an I2C bus vs SPI for the same functionality.

Different classes of devices (memory, I/O, LCD, etc.) have different address ranges. Some devices, which are commonly used more than once in a system (such as the PCF8574 I/O expander), use one or more address lines (AD0-2 for the PCF8574) which can be tied high or low to specify the low bits of the address. The MPU-6500 has one such address line (AD0), so two of them can be used in the same system.

You can also have multiple devices on an SPI bus, but each device must have its own chip-select (CS) line. Therefore the 4-wire description is a bit of a misnomer -- it is really a three wire interface + one additional wire per device. I am not experienced with the Arduino series of boards, but I believe this would make using SPI more difficulty on the Arduino, since if you needed lots of chip select lines this would start to get cumbersome with the common pin assignments used by the various shields.

I believe most Arduino boards run at 5 volts, with some newer ones running at 3.3v. The MPU-6500 runs at 3.3v. If the minimum input "high" voltage for a the I2C bus on a 5v CPU is 3v or below, you could avoid level conversion issues by just providing 10K pullup resistors to 3.3v on the SCL and SDA lines, since the bus is open-collector. Make sure any 5v internal pullups on an CPU are disabled.

However I checked the datasheet for the ATmega2560 (using the ADK 5v Arduino as an example), and its minimum input 'high" voltage is 0.7*Vcc, or 3.5v which is greater than 3.3v. So you need some sort of active level conversion. The TI PCA9306, which requires pullups resistors on both 5v and 3.3v sides of the chip, costs just 78 cents in single quantities.

Why then ever pick SPI over I2C? Mainly because SPI can be run much much faster -- up to many 10's of MHz in some cases. I2C is generally limited to 400 KHz. But this is not really an issue for the MPU-6050/6000 accelerometer, since it runs at 400 KHz for I2C, and only 1 MHz for SPI -- not that much of a difference.

Tags:

I2C

Spi