×

Our Technical Support team will be out of the office on Wednesday, April 23 starting at 12pm. Tech Support will reopen with normal hours on Thursday, April 24 at 9am. Thank you

According to Pete - SPI and I2C


In today's edition of "According to Pete," SparkFun's Director of Engineer Pete Dokter will again talk about serial communication - this time specifically about SPI vs I2C. Check it out:


Vimeo version found here.

If you have any questions, comments, or suggestions, please them leave in the comment section below. Otherwise, we'll see you in a couple weeks with more "According to Pete."


Comments 30 comments

  • So a few comments on SPI:

    • All datasheets that define an SPI waveform will NEVER have a straight up/down lines for waveforms. This is to show that there is rise/fall time. Why are rise/fall times important? In digital logic, there are things called setup hold/delay timing. This is mostly defined for flip-flops, but they are applicable in synchronous timing. So the marks in the middle in the rise/fall is where logic low changes to logic high and vice versa. By defining timing this way allows you to meet the timing waveforms easier.

    • TIMING IS IMPORTANT! All calculations should be based off of the MCU’s clock unless stated otherwise.

    • Logic Analyzers are your friends. Don’t assume the way you set up your comm is right (even if Arduino IDE does it for you). Buy a logic analyzer when doing UART/SPI/I2C debugging. Worth the investment.
    • Bit-banging is easy here, but try to avoid it, the MCU has an SPI subsystem, so let the MCU handle it.

    Comments on I2C:

    • A tougher comm standard to use due to bi-directional communication. This means you have to know how your code is suppose to work.
    • If you are needing to read/write data all the time, interrupts are best, but sometimes data gets out of sync and you can get garbage (even with a start/stop bit).

    Final comments on comm standards:

    • Try to avoid bit-banging pins. Yes it works, but it makes it harder to handle and things can get out of sync.
    • Use Interrupts instead of polling. Polling is nice, but if you have other subsystems that need clock cycles, polling isn’t the best idea.

    Okay, done with my rant.

    • Comments on your comments: Rise and fall times have nothing to do with setup and hold time.

      Rise and fall time tell you how fast the driver can transition a signal from one logic state to the other. The main reason to be concerned about these times is so that a signal doesn’t linger at an “undefined” level between valid logic states. This causes odd switching and can be a real problem on clock signals. Also, the faster the rise/fall time, the more you have to worry about signal integrity and termination and all of that. Note that rise and fall times are not special to SPI; they apply to ALL digital logic signals, synchronous or not.

      Setup time indicates when a data signal needs to be stable before a clock edge. Hold time indicates how long a data signal needs to remain stable after a clock edge. These parameters are critical for all synchronous logic circuits, including not only flip-flops but also synchronous memory elements (RAMs, ROMs, FIFOs). If it’s got a clock, it’s got setup and hold-time requirements.

      So the waveform displays which exaggerate the effect of rise and fall time and show you 10% and 90% levels are nice, but in the real world you just measure timing at the middle of the transition.

      Note that there’s a reason why SPI clocks data out on one edge and clocks it in on the other. It’s so you don’t have to deal with setup and hold time and driver clock-to-out calculations at all.

      Consider what some might call a “fast” SPI bus, with a 20 MHz (50 ns period) clock. Say the receiver has a setup time spec of 2 ns and a hold time spec of 2 ns. Say the driver has a clock to out time of 1 ns. If the driver and receiver were clocked on the same edges, then at clock edge 0, 1 ns later the data line transitions. At the same edge, the receiver looks at the input. Now a 1 ns clock-to-out means the signal is stable at the receiver 49 ns early (easily meeting setup) BUT it failed to meet hold time since it changed 1 ns after the clock but hold time says the receiver needs it stable 2 ns after the clock.

      Now clock in on the rising edge and out on the falling edge. 1 ns after the falling edge, the signal transitions (clock to out delay). With 2 ns setup time required at the receiver, you have 22 ns of slack (period - requirement - clock-to-out). Also, the signal is held at the receiver for 26 ns after the rising edge so you can’t fail hold-time requirements.

      So there it is. Now I haven’t mentioned why in most synchronous logic systems we don’t clock out on one edge and in on the other. That’s because it halves your maximum clock frequency. And in a synchronous system where you’re using the same technology and your clock tree is designed for minimum skew then you can, by design, guarantee not failing setup and hold time. SPI is meant to interface any arbitrary devices so it trades off maximum frequency for guaranteed setup and hold time.

  • spi makes my head hurt.

  • Wheres the hat?

    • …on the hat rack? Dude, sometimes my fat head has to breathe.

      • Great. My fat head is getting upvoted. Although I did recently get a most righteous winter hat that makes me look like a chicken (OK, just a mohawk). Same day I got a twitter account. Meh. Wacky old guy making his way into the 21st century with a chicken hat. When I write an autobiography, that’ll be the title.

  • Hi Pete, nice example to illustrate the insanity that’s sometimes called SPI and explain I2C, maybe I can add a few useful points.

    — SPI —

    • SPI of course is a popular interface on complicated chips like the signal generator you mentioned. But fundamentally you can think of two shift registers (one in master, one in client). In the bidirectional case (using MOSI and MISO) the two shift registers will have exchanged their content after the required number of bits have been pulsed out of the clock line. In practice you can even put cheap HC166-shift-registers there to expand a small micro to an arbitrary number of IOs.

    • With all the variety you mention, the possibly variations for clock polarity and phase (idle-state of clock line, sample or shift edge) are normally called “mode-0” … “mode 3”. With some luck you’ll find this information in the datasheet, configure your master device (or bit-bang library) for mode-X and are set.

    • I second the comment from “sgrace” to always try using the SPI subsystem if some exists on your platform of choice. The integrated peripherals are very powerful, features include:

      . Most often bug-free in comparison to a lot of the home-grown code (of course also mine).

      . Alignment of odd bit-numbers to native word-sizes, LSB/MSB first swap in hardware (=fast).

      . Counter for doing a number of transfers in a row, maybe even DMA from/to internal memory

      . Multi-slave support by keeping track of several chip-select lines and switching automatically between configurations for several devices (to be found on higher-end CPUs)

      . Support for related standards, for example I2S that is used with audio-ADCs/DACs

    After setup of the controller, the long while()-loop that Pete did show might be reduced to a simple…

      SDR = data; /* put data in SPI data register, needs 1 CPU cycle to perform */
    

    …and your processor will be free to do more important tasks. There will be a bit in the SPI controller that changes once the transfer is finished, or a interrupt can be triggered. Mandatory as soon as you want to move any significant amount of data, e.g. from ADCs.

    — I2C —

    • The I2C standard is actually very readable, just search for “The I2C-bus specification”.

    • I2C generally is a little slower, so there’s no big performance gain in using the included hardware, but it is generally well implemented. It has dedicated hardware for stuff that is generally hard to implement efficiently in software like detecting the start-condition/bit or collision in multi-master setups.

    • I don’t remember if it has been mentioned in the video: The name “wire” originates from device manufacturers avoiding to call the bus “I2C”, maybe bececause they don’t want to pay royalties to Philips. They call it “TWI/Two Wire Interface” instead.

    — General —

    • If you start to explore an devices, it can be very handy to just connet them to a linux-pc. Doesn’t matter if workstation or something like a raspberry-pi. Linux has good support for SPI and I2C on a multitude of interfaces (GPIOs on a parallel port, I2C on that old VGA connector, …). With this you can prototype code, or manually play with your device using simple 10-line python scripts on /dev/i2c-# or /dev/spi-#.

    • Be careful about the voltage levels, modern chips might have 1.8V, your computer might spit out 5V and fry the chip.

    • Especially more complicated devices (gps receivers, 3D magnetometers, …) often can be switched between several modes with a configuration pin (async serial, SPI, I2C).

  • Great timing. I confused some people in my g+ feed with a rant about mfg choice to all use different names for SPI lines a few days ago. MOSI connects to MOSI… SDI connects to SDO. It gets really fun when you have MOSI/MISO SDI/SDO and SI/SO all in one project if you don’t think about it as you connect things.

    • Try connecting two MCUs (one as master, one as slave) and two other devices as slaves. Oh yeah, then like Pete mentioned make them all use different standards. MISO->MISO->SDO->D0.

      Edit: oops, I even messed it up now :)

  • So if I2C devices have a “fixed” address, wouldn’t that exclude you having 2 of the same device on the bus?

    • Pretty much yes. If the devices you are talking to have no output and you want them to do the same thing, at the same time, then this is not a problem. But I have often run into issues where I want to use 10 of the same sensors on a system, but they all have the same I2C address. The only solution to this is to multiplex the I2C lines, which defeats the purpose of I2C because a nice 2 wire serial interface, turns into a 10 wire PCB mess.

      There are some I2C devices I have seen that have programmable addresses which totally solves the issue. But these are few and far between. I think the I2C standard should really have something built into it that forces manufacturers to allow at least several bits of programmable address space.

    • On a lot of devices you can hard-wire part of the address (often 1 or 2 bits, using 2 pins, connect to ground for 0 and to VCC for 1). That allows the use of 4x the same device on one bus for example. Thomas.

    • Try looking at the NXP datasheet on I2C >> AN10216-01 I2C MANUAL — >> http://ics.nxp.com/support/documents/interface/pdf/an10216.pdf

    • Not necessarily. A recent tutorial on Adafruit explains using 8x8 LED panels over I2C and two have the same address as they display the same pictures (LED eyes!). So it comes down to the situation.

      • Well thats like NXP’s AN10900 FM+ I2C on LPC1300 pg 5 Fig 1 >> http://www.nxp.com/documents/software/AN10900.zip

      • As long as you want multiple I2C devices to do the exact same thing in sync (LED eyes, as suggested above; or for example PWM drivers you want to pulse the same channels at the same rates) and you don’t need to read any data back from them, you should have no issue. If you need to be able to read data back from them or need them to do different things you’re out of luck.

      • There are also I2C multiplexers that can create sub-buses to allow two devices with the same address to co-exist, at the cost of overhead (I2C commands switch between the multiplexed devices).

        Or you could use standard multiplexers at the cost of more pins.

        • 2-channel —– PCA9540B >> http://www.nxp.com/documents/data_sheet/PCA9540B.pdf

          8-channel W-reset PCA9547 >> http://www.nxp.com/documents/data_sheet/PCA9547.pdf

          4-channel W-INT PCA9544A >> http://www.nxp.com/documents/data_sheet/PCA9544A.pdf

          2-channel W-INT PCA9542A >> http://www.nxp.com/documents/data_sheet/PCA9542A.pdf

          8-channel W-rest PCA9548A >> http://www.nxp.com/documents/data_sheet/PCA9548A.pdf

          You can find more here >> http://www.nxp.com/search?q=i2c-bus+multiplexer&type=keyword&rows=10

  • IF you are having problems with WIRE and need repeating starts for your I2C you might want to look over at www.dsscircuits.com. His Arduino I2C Master Library has some great ideas >> http://www.dsscircuits.com/articles/arduino-i2c-master-library.html

    Dsscircuit’s idea of making an I2C GPS looks real cool too.

    BUT the one that takes the cake (and I wish SP would carry it- but in a shield format) is the wyolum.com ’s GPS over I2C! >> http://wyolum.com/?p=925

    You might want to take a look at their GPS Disciplined RTC >> http://wyolum.com/?p=795

    I like their thoughts on how to determin the TimeZone (again I wish SparkFun Could look into carring this).

  • Half an hour. Kee-ripes. I guess we shoulda split it into two, yeah? It’s really hard to tell how long these things are going to be while we’re shooting it. Ah, well. Bring on the torches and pitchforks!

  • Definitely buy a Saleae Logic … saved me days and days of debug, I use it all the time. The “basic” version is more than enough in 99.999% of the cases (that’s the one I have), the Logic16 seems interesting but a lot more expensive. SPI is the simplest of the protocols (well, after UART, of course), can run fast, simple to debug, very easy to get handled by a DMA … I²C is crap, its speed is limited, it is a nightmare to debug, and you have to handle TONS of different interrupts to get it working. If you have the choice, definitely prefer SPI over I²C. Thomas.[EDIT] Another thing … any slave can lock the whole I²C bus by pulling clock or data lines to 0, and then you'r screwed. With SPI, if things go out of control, release CS to stop transmission, pull it low again and you'r in a known state. DEFINITELY prefer SPI over I²C :D

  • The other thing about SPI, is that it data may be passed both ways simultaneously. For instance, if two micros use it to communicate, they both send and receive at the same time. This is what makes it a much faster protocol than I2C. I need to check this, but I think on NXP Arms for each byte writtent, you need to read a byte as well, even if you throw that byte away. It’s a couple of years since I wrote that code !


This Week

This Month

Heartbleed

Happy Arduino Day!