Should you use I2C or SPI devices for your project?

It depends on what you want to achieve. 

Note that some devices are only available as either I2C or SPI device and quite often the best solution is to use both I2C and SPI if you have enough pins to spare on your microcontroller. Many designers assume the bus is the primary selection criterion for part search, but often a part’s performance and price are more important than the interface it uses!

Advantages of I2C:

  • I2C uses only two pins (as opposed to SPIs three pins plus one address pin for each device for most configurations)
  • I2C can support multiple devices with the same two pins if each of them has a different address.
  • The I2C standard defines how to read and write to/from a specific address, hence you don’t need to check the datasheet as thoroughly for every individual device. Note that many complex devices extend this standard to a certain extent, e.g. larger EEPROMs have multiple I2C addresses to allow accessing the entire memory.
  • I2C has fewer parameters to configure since the speeds and other attributes are fixed in the standard (100 kbit/s, 400 kbit/s or 1 MBit/s = FM+). Hence you don’t need to worry about SPI modes or configuring the SPI speed correctly for any device.
  • The by-default slower speed of I2C makes it more likely for I2C to work over longer traces / wires out-of-the box. SPI is more prone to experiencing intermittent issues if operating at or near the phyiscal speed limit of a PCB design. With I2C it’s typically safe to assume it will work over 50cm long traces (for the standard 400 kbit/s speed). The only reason for I2C working over longer traces than SPI is it’s slower specified speed. SPI will work just as well if you set the speed sufficiently low.

Advantages of SPI:

  • SPI is much faster. While I2C typically communicates at 400 kbit/s (in Fast mode plus = FM+: 1 Mbit/s), SPI communicates around 20-50 MBit/s (it varies depending on your configuration and what speed each part supports). However for many applications you don’t need as much speed.
  • With SPI you don’t need to worry about assigning I2C addresses since each device has its own chip select pin. See our guide on assigning I2C addresses for more details.
  • SPI is more flexible in what data can be transferred since the communication message format is not standardized as much as in I2C.
  • Each SPI pin communicates only in a single direction. Hence SPI is much easier to galvanically isolate using optocouplers or similar devices. I2C requires special (and hence expensive) isolator devices like the TI ISO1541.
  • SPI is typically slighly easier to debug using an oscilloscope since you know what device the data comes from for every individual pin. With I2C, you need to have a look at the data sent to find out what device tries to send data.
  • I2C sometimes experiences issues due to locked-up devices if an I2C communication is interrupted mid-byte (e.g. by a microcontroller restart) and hence causes a device’s state machine to remain in a state mismatched to the I2C master’s state. Most designers do not anticipate this issue and do not include I2C lockup mitigation in their firmware. This means that often a complete power cycle of a system is required in order to remove the bus lockup. The issue occurs more often during firmware development when microcontroller reboots are more frequent due to reprogramming, crashes and breakpoints and in production tests it’s often hard to create the specific conditions that create a lockup in deployment. SPI can never lock up because it will reset once the chip select pin is deasserted.
  • SPI can often be used to control logic ICs like th 74HC series so you don’t need separate pins to control logic devices. Note that whether this works

In what cases do you need to use a different interface (other than I2C or SPI)?

  • Long cables / lines. SPI and I2C operate reliably up to a few tens of centimeters depending on your layout and the speed of the bus. In case you have longer traces, you might need to slow down the bus (especially in the case of SPI). The main issue here is clock skew: A change of the voltage level on the clock pin takes too long to arrive at the device, hence the device “answers too late” (additionally the response from the device takes too long to arrive at the master). If you want to check if this is the case for your design, just slow down your bus to extremely slow speeds (like 20 kbit/s). If the issue persists, you don’t have an issue with clock skew. You can also debug that using an oscilloscope.
  • Electromagnetic noise from the environment, e.g. large motors starting in the vincinity of your device. Since both I2C do not use differential lines
  • Multi-master communication: I2C and SPI typically only communicate when a (pre-defined) master initiates the communication. In most configurations, it’s not possible for a device to initiate communication using only the I2C or SPI bus, so you often need to poll a device many times per second to check if a status has changed. I2C and SPI do not have a built-in collision detection mechanism that detects if multiple devices are trying to write to the bus at the same time.
  • Asynchronous communications: If you want to send/receive data independently from each other, you should use UART, Ethernet or a similar bus that has completely independent send/receive subsystems that do not depend on a common clock.
  • Very fast communication: FPGAs, fast ADCs/DACs, flash memories etc might use e.g.:
    • QSPI: SPI with multiple data pins (typically 4 data pins – hence the name quad SPI).
    • LVDS: High-speed differential bus system
    • JESD204B: Ultra-high speed (multi-gigabit) data link system for ICs. Don’t touch if you don’t know what you’re doing!
    • Parallel: Just a lot of pins without anything too special.

What other interfaces should you consider if communicating outside the circuit board?

  • RS485/RS422: Robust high-speed industrial bus (physical layer only, used in systems like Profibus). Fast (15 MBit/s). RS422 is like UART but differential. RS485 operates receive/transmit on the same differential line.
  • RS232: Old industrial bus system, not differential, requires +-15V to communicate (and hence requires a special IC to generate these voltage levels). Somewhat robust, but not as robust as it seems. Slow (0.1 MBit/s typical, but typically works up to ~0.5 Mbit/s under most circumstances, if all devices support it), does not support long cables, especially not in electromagnetically noisy environments.
  • LVDS: High speed, but not over long distances (a few meters at most). Differential and somewhat robust, but not that suitable for noisy industrial environments if used with long-ish cables. Requires knowledge of high-speed circuit design to do correctly.
  • Ethernet: Very complex to do right from a PCB standpoint (you need a special PHY = physial layer transceiver IC and a microcontroller that supports the MAC layer that generates the Ethernet messages = frames) but very fast (100 Mbit/s max for most microcontrollers, but FPGAs, processors etc) and very robust (differential, 32-bit CRC checksums). Very convenient to interface to computers ; switchable. Supports TCP/IP. PHYs and other hardware are very cheap since they are produced in large quantities. Note: PHYs are rather complex and if you don’t understand some basics of high-speed circuit design and read all the datasheets very carefully, you have a high likelyhood of your design not working – which is often complex to debug especially if you don’t have a multichannel Oscilloscope capable of at least 50 MHz of Bandwidth and some experience in high speed circuit debugging. The interface from the PHY to your microcontroller ist typically RMII for 100 MBit/s Ethernet, additionally you need and SMC interface which is like I2C in order to configure the PHY.
  • USB: Fast, but only goes up to 480 MBit/s under ideal circumstances if your IC actually supports it (many need an external transceiver = USB HS PHY). Most microcontrollers support only up to 12 MBit/s IC . Complex, unless you use ready-to-use ICs. Debugging is pretty hard in practice since USB firmware can fail in many non-straightforward ways (unless, again, for ready-to-use ICs that only perform USB-to-X-conversion). I recommend to use an USB-to-UART-converter IC like the FT230XQ. USB on microcontrollers sometimes tends not to work with some computers unless done completely right, so if possible to try to use a professionally-made USB example that has been tested with a variety of devices and try to not modify it too much. Or just use a ready-to-use converter IC in the first place.
  • UART: Useful for debugging but not robust. UART-to-USB ICs are widely available (I currently recommend the FT230XQ) to interface to computers. Somewhat fast (can do up to ~12 MBit/s with many modern microcontrollers, but it’s not always feasible to use it at that speed, especially not with long traces / cables due to signal degradation). USB-to-UART adapters for debugging are readily available & very cheap in China.
  • CAN: Used mostly in automotive systems. Not very fast (1 MBit/s) but has a priority system that allows high-priority message to be sent during transmission of lower-priority messages (which are interrupted and re-sent later). Differential and quite robust. Mostly easy to use on the IC level but hard to do completely right on the firmware level (there are a lot of non-straightforward configuration options).