Tradeoffs when considering SPI or I2C?

  • What tradeoffs should I consider when deciding to use an SPI or I2C interface?

    This accelerometer/gyro breakout board is available in two models, one for each interface. Would either one be easier to integrate into an Arduino project?

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

    enter image description here

    I2C and SPI have their strenghts. I2C is more complex to set-up, once stable you can so easily extend (as long as your bus wiring doesn't get too long or large). SPI is easy to set-up.. you can bitbang it very easily if required. Expansion eats I/O with all the chip selects. If I have the luxury of I/O and connector space and don't need busses, I'd always go with SPI.

    How is I2C more complex? I have used both buses on different micros (small PICs and decent sized ARMs) and in every case I2C setup was simpler (i.e. less registers to write). If anything, SPI is more complex because of the clock polarity and data sampling options.

    @Armandas -- no way! SPI has 4 possible modes for clock/data polarity, and two of them dominate -- almost all SPI devices update their MISO output on the falling edge of a clock and read their MOSI input on the rising edge of a clock. You can figure out which one in a few minutes by looking at the data sheet, and then you're done. If you pick the wrong mode by mistake, you'll figure it out quickly once you look at oscilloscope traces. SPI data errors are rare and don't get you stuck in weird states the way I2C does.

    I say I2c is way more complex because I have once had to write an I2C driver at an ARM proccesor. I followed the state machine of NXP documents, and it was about 20 states long. It took me a decent time to figure out the acknowledge, when the last byte is read/written, etc. I've never had any of these issues with SPI, just have to get the clock & data lined up.

    @JonL, well frankly, I am the only one to have provided a complete answer so far, since I am the only one to discuss the issue of the particular breakout board the OP wants to use, and point out that it is *not* available in both SPI and I2C, but only I2C -- so he *has* to use I2C if he wants to use this particular board. The others only dealt with which interface (SPI or I2C) is easier to interface, which I also covered.

    @Hans: The I2C implementation documented by NXP includes provisions for things like multi-master arbitration which are not needed in a typical application, and is also designed around a state-based approach. Code for a procedure-driven I2C master is a lot simpler than such documentation would suggest.

  • stevenvh

    stevenvh Correct answer

    8 years ago

    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.

    I have not yet met a microcontroller which handles all the corner cases of I2C need to handle proper error detection and recovery in a way that is useable without having to be an I2C expert. I've always had to drop back down from a "smart" I2C peripheral to bitbanging temporarily to handle the missed-clock case when SDA is being held low, which is a complete pain./

    (but +1 since I agree with the rest of your answer)

    There are even I2C devices around that work at 3.4MHz, but I am uncertain whether these can be combined with slower devices (as all devices need to be able to follow the bus addressing). I also believe the timings of 3.4MHz I2C is little bit different.

    @Hans - HS I2C seems to be downwards compatible with the more common 400kbit devices. Frankly, (without thorough research) I've never seen a microcontroller which supports HS (yet), that's why I didn't want to mention it.

    @stevenvh: Some controllers' two-wire implementations (e.g. Cypress PSOC) require that SCK be low for at least one or two cycles of an internal clock before they will latch it, and will malfunction badly it isn't. I don't know why they can't detect and clock-stretch an I2C start condition without a system clock pulse, but such behaviors mean that when such a chip is running at a low system clock speed, all I2C transactions on the bus must be run slowly). Even 400Khz operation is too fast for a PSOC running at 3MHz.

    It should be noted that many SPI devices require SS to be used appropriately, even if they are the only device on the bus. SS doesn't just enable a single slave, but also provides synchronization. The leading edge of SS is often used to indicate the start of a new message, with associated re-sync by the slave device logic.

    @stevenvh: *But doesn't the SS only inhibit the clock?* No, and that's the point. Many devices use leading edge of SS to indicate a new message. For example, a EEPROM might take the first two bytes after SS as the address, then subsequent bytes as data. It is very common with A/Ds that meaningful bits are transmitted at a fixed position relative to SS, then after that it keeps sending 0s or undefined bits. That allows for easier compatibility with hardware that can only do fixed multiples of bits, like 8 or 16. For some devices the first byte is a opcode, the rest dependent on that opcode.

    @stevenvh: The vast majority of SPI devices use SS for synchronization and require that it remain valid through a transaction. Some devices have a *separate* clock-enable wire, which will cause them to ignore clock pulses during a transaction. This can be useful if an interrupt-service routine may need to access one device on an SPI bus while "main-line code" is accessing some other devices (such as a flash-memory chip).

    @Olin, supercat - last night in bed I realized my comment about SPI synchronization is completely wrong. Wrong. I don't know what I had been smoking. I'll delete it and edit my answer.

    @stevenvh: Bidirectional SPI requires four lines; many SPI devices only use unidirectional transfer and require three. Although shift registers are commonly used on an SPI bus and allow daisy-chaining, and a few more-complex peripherals do as well, such devices are the exception rather than the rule.

    @stevenh The LPC1300/1700/1800/4300 series claim to support 1 Mbit/s operation. What I haven't seen is a peripheral to connect to it!

    @OlinLathrop: One ADC interface design I rather liked would output 16 bits in big-endian order (which the processor could start clocking out even while the conversion was in process, provided that it didn't clock out any particular bit until it was available) followed by those same 16 bits in little-endian order. This meant that even if a hardware platform only had a little-endian synchronous serial port, it could read a conversion in its native bit order by simply skipping the first two bytes and reading the next two.

  • (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.

    Your religious dislike of IIC has no place here. Both IIC and SPI are good at what they do and each have their place. Most of your objections to IIC come from inappropriate use of it. IIC should be thought of as on-board only, although it is used routinely in the power supply industry for controlling intelligent supplies. If you find yourself wanting IIC buffers, then that's a strong indication IIC isn't the right solution. However, IIC works very well for low speed devices all on the same board.

    *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*. No, this is wrong. IIC logic thresholds are at fixed voltages. You can trivially mix 5 V and 3.3 V systems by pulling up the lines to only 3.3 V.

    Olin -- can you point out the fixed voltage thresholds in a spec? I was under the impression that they were fixed as well (SMBus thresholds *are* fixed) but I looked on the NXP I2C User Manual (UM10204) and they cite the thresholds as 0.3VDD and 0.7VDD.

    It's not a religious dislike of I2C, it's a practical dislike of I2C. You're right about it being much easier with on-board systems; I'll use it when it makes sense, but it adds software cost, and too many hardware engineers just stick an I2C device on a board without discussing the tradeoffs that cause more software headaches.

    I don't remember exactly where I saw it, and digging around a little there does seem to be some confusion and different options, but I'm pretty sure I remember 1.5V as being the maximum logic low threshold, for example.

    IIC is a little easier to implement electrically, and SPI perhaps a little easier in the firmware. Both are however pretty easy and straight forward in both respects.

    I2C is designed for use in electrically-clean environments, and cannot be easily "fortified" for use in more hostile environments. That having been said, I2C can be much more convenient than SPI for inter-processor communications in electrically-clean environments. UARTs can be nicer yet, but processors never seem to have enough, and the way many controllers' UARTs are integrated with their clock systems makes it hard to change clock speed without corrupting any data which the other end might have decided to send asynchronously.

    @Olin - the fixed 1.5 V threshold seems to be used in the past, but according to the latest version of the spec thresholds are indeed 0.3 Vcc and 0.7 Vcc. This quotation from the spec mentions the 1.5 V for legacy devices.

    @JasonS So it's been 6 years, and there's been lots of useful discussions in the comments. Is it possible we can have a list of cases, I2C reliability and error modes in each one? E.g. when writing to a single device, seems 100% fine. When writing to multiple devices, some may mis-interpret the data. When reading from a single device, you may have to bit-bang and reset. When reading from multiple devices, a full power cycle may be required to get off a deadlock?

  • 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.

    Another reason to pick SPI over I2C: All the lines are unidirectional, which makes things like level shifters a bit easier.

    @markrages, I checked the datasheet for a 5v Arduino CPU and discovered my simple pullup solution doesn't work since the minimum input for the I2C is 0.7*Vcc, or 3.5v. So a level shifter would be needed. I modified my answer to indicate this, and recommend a chip to use. I agree the level shifting for SPI is simpler, since you only have one CPU input line to deal with (MISO) -- the outputs can be handled with voltage dividers.

    I2C is easier than SPI?! The only thing about I2C that's easier is the connectivity if you can just hook everything together. Otherwise the signal integrity is tougher in I2C, and robust software implementation is way tougher in I2C.

    @JasonS, I have completed dozens of embedded software projects using I2C, and have never run into the lock-up problems you mention in your post. I can understand your not liking it due to your bad experiences. I currently have a product out in the marketplace using an I2C DAC to output audio, while simultaneously reading the next buffer of data off of an SD card over SPI. Works great. I couldn't use SPI for both the DAC and SD card since I was getting bus contentions and the audio broke up. The micro (a low-end one) only has one SPI and one I2C port.

    I'm impressed that you can output audio to an I2C DAC! (what's the max clock rate?) If you're using onboard IC's with short runs, the probability of running into lockup is extremely small, but it still exists. (Also you'd never run into it if you're just writing data to I2C. It requires you to read from a device that is willing to wait forever for what it thinks is a missing / extra clock.)

    @JasonS, the audio is only voice quality, 8KHz -- I am using a 128 us interrupt to output each 16-bit sample. The I2C also runs on its own interrupt. The spare time is used to read data off of the SD card. Good point about lockup never occurring on writing. Except for ADCs, I generally have used I2C for output devices. However -- did you know the read-only interface (2 buttons, accelerometer, and joystick) between the Wii remote and Wii Nunchuck (which is over a 3' cable) is I2C at 400 KHz? Lots of info on the web re hacking this device interface.

    @JasonS: For communication between two microcontrollers, the lack of handshaking in SPI is a real pain.

    Apologies for my downvote; if you make a token edit (add whitespace or whatever) I'll remove the downvote.

    JasonS, I edited my answer to make it clearer I meant the I2C bus is generally easier to use from a hardware standpoint (level transition issues notwithstanding).

    -1 --------> +1

  • In general, SPI is a faster bus - the clock frequency can be in a range of MHz. However, SPI requires at least 3 lines for bi-directional communication and an additional slave select for each device on the bus.

    I2C only requires 2 lines, regardless of how many devices you have (within limits, of course). The speed, however, is in the range of kHz (100-400kHz is typical).

    Most microcontrollers, nowadays, have hardware support for both buses, so both are equally simple to use.

    -1: Both are not equally simple to use. I2C has a lot of complex error handling and recovery which is not often handled by microcontroller peripherals (certainly not in PIC18, PIC30, or TI C28xx DSPs -- you get a peripheral that will handle most of I2C but will fail to handle all the cases.)

    @Jason: You seem to have some predjudice against IIC, but it's unfair to ding other people on account of it. Both IIC and SPI are "easy", with each having their own wrinkles. SPI needs extra lines, which can be not easy. IIC is a little more complicated, but it's still easy to do all firmware implementations, which I have done may times. It doesn't take all that much code. Both have their place and both are easy enough for that not to be a factor to anyone that knows what they are doing.

    Not unfair. I'm happy to upvote when the statement of "equally simple to use" is corrected or at least clarified. I challenge anyone to write software on a microprocessor with intelligent I2C and SPI peripherals to interface with an IC series that has both I2C and SPI variants, and show me the software complexity via any objective measure (lines of code, # of states, cyclomatic complexity, etc.) to show that they're equally simple to use. Examples: Microchip 24LC256/25LC256 EEPROM, MCP23017/23S17 I/O expander.

    @Jason: I just checked, and my generic IIC code for *firmware* implementation of IIC on 8 bit PICs is only 311 lines, and probably over half of that are comments. That gets you a procedural interface to the IIC bus at the level of routines for start, put, get, stop, etc. Big deal. A module calling that to drive a simple EEPROM is 272 lines, again 1/2 comments probably, and that includes some high level management like default data, UART debug interface, etc. This is all so trivial that arguing whether it take 10 instructions less than SPI is pointless.

    @JasonS: Just because *you* don't find I2C easy to use doesn't make it difficult for everyone. I've designed plenty of industrial equipment using I2C and have never run into the issues you describe in your answer. I think Olin is right: you've misapplied I2C and have grown a very strong dislike for it. Nothing wrong with an opinion, and you make some good points, but to slag it off in almost every answer here and to continue to defend your stance... that's not practical dislike; that's religious fanaticism. Your answer was very good. There's no need to comment on everyone else's too.

    @AndrewKohlsmith: In fairness to Jason, there are some tricks with bit-bang I2C which can make things much easier, but device documentation doesn't usually present them, and many hardware implementations don't support them. It is often easier, for example, to have a read-byte routine send an ACK before reading each byte after the first, and call a NAK routine after reading the last byte, than have a read-byte routine which uses a parameter to specify whether to ACK or NAK, since one might not know until after one has read a byte whether one will want another.

    Ok, I'd like to apologize for taking an angry tone both in my comments to other posts and my own answer. What I will concede, is that there are ways to write I2C software using on-chip peripherals which are relatively easy, neglecting certain rare error conditions. Having said that, I still think saying that I2C is easy is misleading. And I don't think I've misapplied I2C. Look at the TMP75 -- an I2C temperature sensor. You can put up to 27 of them onto the bus. (We have a system with 8.) Would anyone put them all on one board? The datasheet doesn't warn you of off-board problems.

    Olin: just curious -- is your implementation blocking or non-blocking (e.g. state-driven)? I can see that a blocking implementation could handle error conditions w/o too much trouble. I have a system which has hard real-time requirements and I have to break up my I2C processing into a state machine because of all the different error cases -- whereas the SPI processing is a piece of cake; we just switch our CS address, lower the CS enable line, put transmit data into the queue, wait a few microseconds, raise the CS enable line, and read the receive data.

    Andrew: "never run into the issues you describe in your answer." Sure, especially if the I2C bus is on-board with relatively short traces. Less noise = probability of a missed I2C clock goes down to a very small amount. We have 8 TMP75 sensors in an industrial noisy system. (In retrospect I wish our designer had used analog temperature sensors.) If it were occasional data errors (which we do get), it wouldn't be so bad. But the problem is you can get deadlock, and even if the error's probability is remote, once you're there your probability of escaping is 0 without the right error-handling.

    @Armandas: Apologies for my downvote; if you make a token edit (add whitespace or whatever) I'll remove the downvote.

    @JasonS that is my point: I2C is designed for on-board applications. It can be stretched to be transmitted on cables but that's not its intended application, and you've got to design for the added complexity. As far as zombie devices goes: no sane I2C slave would stretch the clock indefinitely, and if you've got control over the clock you can abort the I2C transfer and reset the bus. It's not the crazy difficult system you seem to make it out to be.

    @Andrew Kohlsmith - `I2C is designed for on-board applications.` - Apparently I2C device manufacturers disagree with you. Take the TMP100. The product page explicitly states: `The TMP100 and TMP101 are ideal for extended temperature measurement in a variety of communication, computer, consumer, environmental, industrial, and instrumentation applications.` The same is true for the TMP75

    For what it's worth, I've run 8 TMP100 on a I2C bus that was ~15' long, but the environment had little noise. The whole I2C interface for that project was bit-banged, and it was a pain in the ass.

    I think this whole argument boils down to people having different perspectives. You have Jason S, who seems to be designing extremely high-reliability, hard-real-time industrial control systems, and Andrew Kohlsmith and Olin Lathrop, who design more consumer oriented devices(?). I2C may well not be viable in a setting where that 0.001% error rate is a significant and serious problem (particularly if you cannot wait ~1 second for things to time-out). However, in many situations, such a error is sufficiently improbable to not cause problems, or the delay it would introduce is not problematic.

    Personally, I'd go with SPI over I2C, but that's more because I'm pretty bad at programming, and find the complexity of one additional lead-wire to be trivial. YMMV.

    @JasonS No worries, it's a simple answer and point-wise it's around where it should be.

    @FakeName the TMP100 doesn't state anywhere that it is meant for off-board temperature sensing. Your quote simply states it's ideal in certain applications. You can sense temp with the device in those applications. Standard marketing fluff, that's all. Maxim is particularly bad for listing a gazillion applications for any device.

    @FakeName When I built a hot wire anemometer I used dual transistor devices which were connected via twisted pairs to a standard SMBus temperature/fan controller. SMBus is enhanced I2C as you know, but the chip was on-board and never had any comm troubles. I think you misapplied the temperature sensor.

    @FakeName You're incorrect; I spent 13 years doing industrial power electronics. (starting and monitoring LARGE three phase mtors is a VERY noisy environment) It's not about SPI being more reliable, it's about designing the system with all failure modes planned and accounted for, and having recovery options built in to the system where needed. I've never, ever had a noise spike kill my I2C (or SPI for that matter) comms, but I also never relied exclusively on the I2C controller to do everything for me. It's a matter of planning and design, not of one bus being better.

    "but I also never relied exclusively on the I2C controller to do everything for me" -- that's not easy, which was my point.

    @akohlsmith: Single-master single-slave I2C should be robust with a "bit-bang" master. If there are multiple slaves and two simultaneously get "confused" in different ways, the bus might get unrecoverably locked up (e.g. if two or more memory chips which are filled with zeroes both think the master is trying to read them, but their bit counters are out of sync, then each will only release SDA during times when the other is asserting it, and nothing the master can do will free up the bus unless it can drive a "high" powerful enough to overdrive all slaves.

  • SPI can be run much faster than I2C (some SPI devices go over 60MHz; I don't know if the "official" I2C spec allows devices over 1MHz). Implementation of a slave device using either protocol requires hardware support, while both allow easy implementation of "software bit-bang" masters. With relatively minimal hardware, one can construct an I2C-compliant slave which will operate correctly even if the host may arbitrarily decide to ignore the bus for up to 500us at a time, without need for additional handshaking wires. Reliable SPI operation, however, even with hardware support, generally requires that one either add a handshake wire, or else that the host "manually" add a delay after each byte equal to the slave's worst-case response time.

    If I had my druthers, controllers' SPI support would contain a few simple extra features to provide 8-bit-transparent bidirectional data transfers between controllers with handshaking and wake-up abilities, using a total of three unidirectional wires (Clock and MOSI [master-out-slave-in] from the master; MISO [master-in-slave-out] from the slave). By comparison, efficient and reliable communication between microcontrollers with "stock" SPI ports, when both processors might independently be delayed for arbitrary lengths of time, requires the use of a lot more wires (Chip-Select, Clock, MISO, and MOSI to start with, plus some sort of acknowledge wire from the slave. If the slave might asynchronously start having data to send (e.g. because someone pushed a button), then one must either use yet another wire as a "wakeup" signal or else have the master repeatedly poll the slave to see if it has data yet.

    I2C does not provide all the abilities my "improved" SPI would have, but it does offer built-in handshaking abilities which SPI lacks, and in many implementations it can be kludged to provide wake-up as well, even if the master is a software bit-bang. For inter-processor communication, I would therefore strongly recommend I2C over SPI except when higher speeds are needed than SPI can supply, and the use of extra pins is acceptable. For inter-processor communications where low pin count is needed, UARTs have a lot to recommend them.

    There's a high-speed version of I2C which allows 1MHz; normal I2C is 400kHz.

    @TheResistance: I know that normal I2C was 400kHz, but versions were spec'ed up to 1MHz. What I don't know is whether faster versions have been specified.

    According to the specification 400kbps (not kHz, I used the wrong units there) is Fast-mode, 1Mbps is Fast-mode Plus, and there's a High-speed mode up to 3.4Mbps. Ultra-fast goes up to 5Mbps, but is unidirectional.

    @TheResistance: Thanks. I hadn't heard of those later versions. What exactly do you mean by 'unidirectional'? I know that the speed of SPI slave-to-master communication can go faster than master-to-slave because the slave is guaranteed to get its clock after the master, but I'm not sure of an equivalent concept for I2C. Got a linky?

    Find the spec here. On page 23 it says that Ultra-fast can be used for devices which don't send data back (write only), not even ACK.

    @TheResistance: The ultra-fast format seems a bit curious. When I've need push-pull communication to talk to a CPLD with minimal wires, I used SPI but had the communications interface reset if it received two or more rising edges on MOSI while clock was low (generated by switching MOSI to general-purpose I/O). Such an approach allowed use of almost any controller's SPI master hardware (many I2C implementations can't be configured as push-pull), and didn't require an extra clock after every byte.

  • This question has been thoroughly explored in the excellent answers here, but perhaps there's one more point of view to I2C I could offer from a chip maker's point of view.

    The I2C's electrical interface is an open collector. Now breathe and think of the implications. Using I2C, I can design a chip which is totally agnostic to the operating voltage of the bus. All that I need to be able to do is pull the SDA line low if it pleases me to do so, and compare the voltages of SCL and SDA to some ground-referenced threshold voltage, which I can choose. And if I leave out the normal high side protection structures and replace them with other structures, I can make a chip which can totally live its own life undependent from the rest of the system - SCL, SDA never feed any current to my chip and I certainly won't feed any current to those pins. That's why it's such a nice bus for real-time clocks and other low power stuff like that.

  • One thing I haven't seen mentioned in the other answers is that I2C supports multiple masters on the same bus. If you need bidirectional communication and don't want to use a polling-based method, I2C will get the job done.

    Over longer distances, CAN has the same capability and is more robust. But CAN is an asynchronous protocol that requires hardware support and a transceiver, so it may not be an option in a low-cost system.

    Good point (on multi master), I've also seen SPI devices with interrupt pins, while one device still is the master, both can instantiate (bi-directional) communication. For remote devices there, of course are more solid and better options (such as CAN).

  • Use the SPI protocol and write your bits directly to the device whenever the sync clock is rising. The xnor logic circuit can be used to match the "homemade" address from a memory to select the wanted device as if it was an i2c device.

    The i2c is integrating the authorial circuit inside the format of the device, standard...etc are complex and different, with a spi you can use a spi memory to display a video on screen, but not i2c.

License under CC-BY-SA with attribution


Content dated before 6/26/2020 9:53 AM