[HN Gopher] I2C in a Nutshell
       ___________________________________________________________________
        
       I2C in a Nutshell
        
       Author : fra
       Score  : 185 points
       Date   : 2020-01-22 17:28 UTC (5 hours ago)
        
 (HTM) web link (interrupt.memfault.com)
 (TXT) w3m dump (interrupt.memfault.com)
        
       | linker3000 wrote:
       | Here is a shameless plug for a build-it-yourself multi-function
       | FT232H-based (USB interface) board that can do I2C among other
       | things (JTAG/SPI/UART/GPIO) and has a few extras compared to
       | similar commercial boards from elsewhere (pullups and some
       | blinkenlights).
       | 
       | The board works with various apps and frameworks, including
       | OpenOCD and CircuitPython.
       | 
       | Full build details and some other resources are here:
       | 
       | https://github.com/linker3000/shukran
        
       | bsder wrote:
       | I'm happy to see all the discussion against I2C in the comments
       | here. I thought I was the only one who loathed debugging I2C
       | stuff.
       | 
       | The only things I take exception in the article to is:
       | 
       | > When a single device is on the bus, UART may work just as well.
       | 
       | The problem with UART is _clock drift_. It 's remarkably easy for
       | your two chips to get out of sync if they don't use crystals and
       | don't have autobaud (normally rare). That is one thing that I2C,
       | SPI, and CAN do better. They either don't care as they have a
       | single master clock (I2C and SPI) or they autobaud detect and
       | then adjust (CAN).
        
       | skybrian wrote:
       | I wonder what people think about i2c connectors? I see that
       | Sparkfun has Qwiic and Adafruit has Stemma, and there are others
       | like Grove.
       | 
       | I'm designing my first circuit board and I'm wondering if I
       | should bother with JST connectors or just use header pins.
        
         | kaik wrote:
         | This. I would also love to know what connectors I should use
         | for my hobby projects. I'm also designing my first PCB board
         | and something as simple as choosing connectors is daunting...
        
           | nlfwhulsdhouv wrote:
           | If it's your first project, stick with common 0.1" headers
           | unless you need something very specific (small, high pin
           | count, etc). You can buy locking versions if needed.
        
             | skybrian wrote:
             | What are locking headers?
        
           | bsder wrote:
           | Through-hole .100 headers. Always. Unless you have a _REALLY_
           | good reason otherwise. (weatherproofing, signal integrity,
           | compatibility with existing solution, etc.)
           | 
           | First, if you have a small number of pins (up to about 4-6),
           | a 2x2 or 2x3 .100 header isn't that much larger than any
           | alternative. Compare this: https://www.tag-
           | connect.com/product/tc2030-fp-footprint to a 2x2 of .100
           | headers. It's actually bigger, and now you need a special
           | cable instead of that bag of .100" jumper wires you have.
           | 
           | If you have something like 20 genuinely used pins (not 6
           | active and 14 unused), okay, you may need a different
           | connector. But are you really sure about this? 20 pins
           | communicating simultaneously has signal integrity needs and
           | small connectors have _WAY_ more coupling than .100 "
           | spacing.
           | 
           | Second, through-hole is always way more stable than no-
           | through hole. Once you give your smaller pitch connector
           | through holes, is it really smaller than .100"?
           | 
           | Third, manufacturers have no problems with .100" headers.
           | Smaller pitches may increase the cost of your board. Try
           | costing out a board that can mount and route a modern USB-C
           | connector which has both surface mount and through-hole at
           | small pitch. You're probably going to get a cost bump.
           | 
           | Fourth, you can buy _really_ long .100 " headers which allow
           | you to conect to them _and_ put a scope probe underneath.
           | That 's really convenient for debugging.
           | 
           | So, go through-hole .100" header until you've got a good
           | reason otherwise.
        
             | skybrian wrote:
             | I have a bunch of male and female header and wires, but now
             | I'm looking at whether to buy right-angle header because I
             | will have a couple of boards that are close together and
             | having straight-up pins on the bottom board gets awkward.
             | 
             | Then I start looking into various kinds of connectors, and
             | wonder if I'm overthinking it.
        
         | fra wrote:
         | They're all roughly equivalent. I would choose a cost effective
         | one and move on.
         | 
         | One thing to watch out for: i2c is not designed for long wires,
         | so you may have signal integrity issues beyond a 1-2 feet.
         | You'll want to switch to differential signaling beyond that
         | (e.g. with https://www.sparkfun.com/products/14589).
        
         | TOGoS wrote:
         | http://www.nuke24.net/docs/2019/WSTYPE-4106-I2C-over-GX16-4....
         | 
         | Or GX12-4, if you want something a little smaller.
        
       | AceJohnny2 wrote:
       | > _We're partial to Saleae devices, which come with an easy to
       | set up I2C decoder._
       | 
       | I can vouch for these. We have a couple for our team to debug HW
       | issues, and I was amused, once in a Chinese factory, to be handed
       | one there when I asked for a logic analyzer (I know Saleae had
       | issues with clones in the past, and had to implement
       | countermeasures some years ago...)
        
       | Ives wrote:
       | I really don't like I2C. Yes, in principle it's pretty simple,
       | but if you consider NACKS, slaves holding SCK low, what happens
       | if your master resets while the slave is trying to send a 0 bit
       | (hint: power cycle!), etc, it's so easy for the peripheral to get
       | stuck.
       | 
       | SPI is much easier to write correctly, and pretty much only has
       | the extra wire (usually not a problem) and the phase polarity
       | issues as a negative point.
        
         | fpgaminer wrote:
         | I built a battery powered project designed to run continuously
         | for ten years. Of all the things in that design, the I2C bus
         | makes me the most nervous (1). Every time the MCU wakes up it
         | has to use I2C to read from the RTC. If at any point in that
         | ten year span the I2C bus gets jammed ...
         | 
         | I mitigated the issues by doing I2C resets on every read (see
         | the Analog Devices I2C reset documentation linked in another
         | comment) and reading multiple times to filter out any spurious
         | bit errors.
         | 
         | Other than that I just have my fingers crossed that a bit
         | doesn't accidentally flip and overwrite something in the RTC.
         | Or that the bus somehow gets stuck driven between sleeps and
         | drains the battery early. _sigh_ SPI would have been so much
         | nicer.
         | 
         | (1) I mean, okay, the massive lithium battery exploding is
         | perhaps the most nerve racking component, but I2C is a close
         | second.
        
         | shortsightedsid wrote:
         | On the other hand you need a lot more pins for SPI.
         | 
         | One more advantage of SPI that I see is higher data rates,
         | full-duplex communication etc..
        
         | uep wrote:
         | For exactly that reason, I've encountered peripherals getting
         | stuck during i2c transactions far too many times. At least a
         | handful of times I've had to add boot (and sometimes runtime)
         | logic to clear stuck transactions, due to the lack of a
         | dedicated way to reset said peripheral.
         | 
         | It's quite annoying because one stuck device can block all
         | other communication on the bus. Let's hope your reset pin (if
         | you have it), isn't on an i2c expander on the same i2c bus.
        
           | fra wrote:
           | For what it's worth, here is a good doc on I2C resets:
           | https://www.analog.com/media/en/technical-
           | documentation/appl...
        
         | pslam wrote:
         | Same. I really dislike I2C, but it's universal and it's been
         | around for decades, and it's hard to avoid designs without it.
         | I2C keeps causing these additional issues which the article
         | doesn't touch on:
         | 
         | * No way to safely bring the bus back to idle from mid-
         | transaction. By "safely" I mean not accidentally transmit an
         | extra byte which could e.g overwrite EEPROM memory. There is no
         | combination of transitioning the 2-wire bus from an arbitrary
         | state back to idle which works in the general case. If it's
         | important, you end up adding a dedicated reset wire.
         | 
         | * No safe, universal way to bring the bus from tristate, or
         | low, to pulled-up. There are designs where this ends up being
         | necessary. You end up with a spurious transaction, which may
         | wedge the bus, or having to add a reset wire or buffer.
         | 
         | * The protocol is extremely hostile to devices with non-zero
         | latency response. It's designed as a simple "Address this
         | register and then immediately read out a byte in the next clock
         | cycle". Works great for trivial devices, but for anything more
         | complex it ends up needing a bank of register acting as a
         | "proxy" to access the higher latency side of the chip. At this
         | point I2C is an awesomely bad choice, but people keep doing
         | this, because it's so universal.
        
           | fra wrote:
           | > No way to safely bring the bus back to idle from mid-
           | transaction. [...] No safe, universal way to bring the bus
           | from tristate, or low, to pulled-up.
           | 
           | These are great points, and I'll add a note about them in the
           | article. Thanks!
           | 
           | > The protocol is extremely hostile to devices with non-zero
           | latency response. [...]
           | 
           | Technically, this is what clock-stretching is for. In
           | practice, you're right that complex devices implemented proxy
           | registers. I've seen it on DP->MIPI bridges for example.
        
           | russdill wrote:
           | There is a safe, out of band way to do this that system
           | designers can utilize. Reset all the other peripherals on the
           | bus.
        
           | amelius wrote:
           | > No way to safely bring the bus back to idle from mid-
           | transaction.
           | 
           | Why would you want to do that? Not having the ability to do
           | this is part of the contract. If you design your device such
           | that it always completes the transaction, then there should
           | be no problem, unless one of the devices on the bus doesn't
           | play fair but then you have a different problem.
        
         | ajross wrote:
         | > SPI is much easier to write correctly
         | 
         | I'm not sure that I buy that. A daisy chained SPI bus is a rats
         | nest of configuration hassle and basically impossible to debug.
         | You're trading hardware robustness for software complexity, and
         | that's not always a win.
         | 
         | And as far as hardware messes: SPI doesn't synchronize anything
         | beyond the bit level (modulo an out of band chip enable or
         | reset, of course, which would work to "fix" an I2C device too),
         | making shift/offset bugs a real danger.
         | 
         | Board-level digital interfacing is just hard. That's why we do
         | it as little as possible and put everything on the SoC these
         | days.
        
         | fra wrote:
         | I think I2C and SPI have very different use cases. Over I2C,
         | you can interact with 127 devices with just 2 pins. To do the
         | same with SPI, you'd need 130 (4 + an additional CS for every
         | device on the bus).
         | 
         | You may think of the extra pins as not a problem, but on every
         | product I've worked on we've been pin-limited on the MCU.
        
           | andyjpb wrote:
           | If you only want to select one device at a time (which is
           | often the case) then you only need log2(devices) pins on the
           | microcontroller because you can decode that binary number
           | into the appropriate chip select.
           | 
           | Obviously that requires more hardware on the board tho'.
        
           | Ives wrote:
           | Agreed, but most I2C busses only have 2 or 3 devices on them.
           | There are some boards with 16 or so devices on the same bus,
           | but much more than that and you'd better hope you can either
           | program their addresses or order them with a specific
           | address, or you might end up with 2 chips with the same
           | address.
        
             | fra wrote:
             | I've worked on server hardware with dozens of devices on a
             | bus :-). Making sure addresses were programmable was a must
             | indeed.
        
           | nlfwhulsdhouv wrote:
           | I don't think I've ever run more than 5 or 6 devices on an
           | I2C bus without running into rise time, bus contention, or
           | address collision issues. Some devices scoop tons of
           | addresses, and most only allow re-assignment to a few
           | alternate addresses.
           | 
           | I agree it's still lower pin count than SPI, but
           | realistically you don't get anywhere near 127 devices.
        
           | tropo wrote:
           | For that many devices on SPI, run 7 pins to an address
           | decoder that fans out to 128. You can do this in the spare
           | pins of an FPGA that you might have for some other purpose,
           | and the 7 pins are cut down to one or less if you've already
           | put much into the FPGA. For example, the FPGA provides 4096
           | bytes of registers (12 address bits) to the MCU but only
           | needs 3700 registers, so use one of the spare bytes to
           | control which SPI CS is enabled.
           | 
           | I've also seen JTAG as an alternative to I2C and SPI. JTAG
           | can be part of normal operation.
        
           | clarry wrote:
           | > Over I2C, you can interact with 127 devices with just 2
           | pins.
           | 
           | In practice, I don't see that many chips offering 7 bits of
           | address configuration. You buy a chip, it has a hardwired
           | address. Maybe a pin or two for selecting another address.
        
             | photojosh wrote:
             | There was the design I did quite a few years ago now.
             | Grabbed a old design, changed the board shape, put a third
             | I2C device on. Everything powered up beautifully first
             | go... and it was only then we worked out two of the devices
             | from different vendors had the same I2C address. <facepalm>
        
           | vvanders wrote:
           | Not always the case that you need the pin count, a good
           | number of SPI devices support daisy chaining[1].
           | 
           | [1] https://www.maximintegrated.com/en/design/technical-
           | document...
        
             | fra wrote:
             | Cool! I've never seen this before.
        
               | amelius wrote:
               | The downside is of course that you need a lot of clock
               | cycles before the data reaches the corresponding device,
               | which makes this too inefficient for certain
               | applications.
        
           | TickleSteve wrote:
           | Don't forget the reset lines to each device that you need to
           | release the bus when they get locked up!
        
             | fra wrote:
             | No reason why you need to reset them individually ;-).
        
         | [deleted]
        
       | whalesalad wrote:
       | I've been having a lot of fun learning how to work with I2C on a
       | Raspberry Pi with the Nerves framework. tl;dr it's an end-to-end
       | development framework for deploying Elixir to embedded devices.
       | 
       | I2C was easy enough to understand, but understanding the obscure
       | ways to configure and speak to a device has been really
       | challenging. Spending a ton of time reading datasheets and
       | experimenting with assembling binary messages.
       | 
       | The next time you are frustrated and unhappy with the state of
       | modern web development (REST and/or GQL) take a ublox GPS chip
       | for a spin and try to get it to give you high frequency location
       | data. You will think, hey gee this isn't so bad after all
       | compared to encoding and decoding a binary protocol by hand.
        
         | fpgaminer wrote:
         | > Spending a ton of time reading datasheets and experimenting
         | with assembling binary messages.
         | 
         | That's embedded development in a nutshell. The only part you're
         | missing is wasting a week of your life tracking down a compiler
         | heisenbug, because embedded devices have niche, poorly
         | maintained compilers.
         | 
         | Though to be honest it's a matter of taste; natural sadists
         | tend to "enjoy" embedded.
        
           | keithnz wrote:
           | not to mention bugs in the micros themselves. I lost a few
           | weeks of my life to one that would corrupt the stack in
           | certain situations in an interrupt. The only way to debug it
           | was with a logic anaylzer on all the memory / data lines /
           | interrupts and decode it into opcodes and see what it was
           | doing in the interrupts. Then when found, get bacck to the
           | manufacturer who eventually gets back and says they already
           | knew about it, but hadn't done and errata for it.... so
           | yeah.... these days I mainly do backend/front end stuff :)
        
           | whalesalad wrote:
           | The weekend project was recompiling the kernel and adding
           | missing wifi drivers. By the end of the huge yak shave (just
           | to use an external wifi antenna instead of onboard wifi of
           | pi4) I was so relieved to see the device boot and have the
           | wlan get an address.
        
           | jlangemeier wrote:
           | Take the sadomasochism one step further; do FPGA programming,
           | learn the joys of properly enumerated case statements (or the
           | hell of finding what one is blowing up your flip-flop/latch
           | diagram).
        
             | fpgaminer wrote:
             | You don't know true embedded BDSM until you've debugged
             | incorrect timing constraints on an FPGA ... with a customer
             | on the other side of the planet ... only to realize later
             | that they have no idea how to design an HDMI compliant
             | board and none of it was your own fault.
             | 
             | Or spending three weeks trying to achieve timing closure on
             | a design, only to finally realize after much inspection of
             | the routed designs by myself and an IntelFPGA FAE that the
             | router was smoking digital crack the whole time and had no
             | clue how to route their own divider units?
             | 
             | Or maybe the programming facility reversed bit ordering on
             | a batch of the FPGA's flash chips and you only learn of
             | that after a very, very long couple of nights of language
             | barrier back and forth with a flummoxed customer.
             | 
             | The joys are endless.
        
         | neillyons wrote:
         | Sounds cool. Can you access the GPIO pins directly from Elixir?
        
           | whalesalad wrote:
           | Yes. You're running on Linux (buildroot) so you can basically
           | do anything Linux can do.
           | 
           | Here is the library you would use to do this via Elixir,
           | https://github.com/elixir-circuits/circuits_gpio
        
       | neillyons wrote:
       | This article has appeared at the perfect time for me. I was just
       | trying to use i2c with a BMP180 temperature/pressure/altitude
       | sensor and a micro python board and was rather confused. Love
       | Hacker News
        
         | chasd00 wrote:
         | hah i'm doing the same thing, building an altimeter for my
         | son's model rocket. There are altimeters out there for sale but
         | i wanted to get into embedded programming as a hobby.
        
       | jhallenworld wrote:
       | Here's an I2C to RS-232 serial converter for long term monitoring
       | of an I2C bus. I needed this at one point, and made it with the
       | cheapest FPGA board available on eBay:
       | 
       | https://github.com/jhallen/i2cmon
        
       | Zenst wrote:
       | Worth reading this afterwards:
       | https://hackaday.com/2019/04/18/all-you-need-to-know-about-i...
        
         | nlfwhulsdhouv wrote:
         | I2S is much closer to SPI than I2C. It really has nothing to do
         | with I2C other than it connects chips together on a board.
        
         | fra wrote:
         | Yes! I considered adding a bit about i2s, but since the article
         | is already clocking at ~2500 words I thought I'd leave it to
         | another time.
         | 
         | I2S is everywhere in audio.
        
           | Zenst wrote:
           | Agreed, you can oversaturate the learning process and what
           | you have is elegant, laid out well and wonderful, also covers
           | the subject and I2S would be another subject.
        
             | fra wrote:
             | Thanks for the kind words! I was up late last night writing
             | this up, it's encouraging to see folks enjoy it.
        
       | vic20forever wrote:
       | Comparison of I2C and SPI:
       | https://news.ycombinator.com/item?id=9303405
        
       | imagiko wrote:
       | I just want to take a moment to thanks folks over at memfault for
       | bringing us in depth content from the world of embdedded systems.
       | Be sure to check out their articles on ARM, RTOS etx.
        
         | fra wrote:
         | Thanks! We've been writing all the content we wish had existed
         | when we started out as embedded software engineers. It's
         | fantastic to hear from folks who enjoy reading it as much as we
         | do writing it.
        
       | Isamu wrote:
       | Very nice! I especially like that it starts with a discussion of
       | why you would choose to use I2C, as well as why you may not,
       | depending on your application:
       | 
       | >I2C is not appropriate for all applications however: When higher
       | bandwidth is required, SPI may be the right choice and can be
       | found in many NOR-flash chips. MIPI can go even faster, and is
       | often used in displays and cameras. If reliability is a must, CAN
       | is the bus of choice. It is found in cars and other vehicles.
       | When a single device is on the bus, UART may work just as well.
        
         | _sbrk wrote:
         | Article misses two of the best features of CAN: Built-in, non-
         | corrupting collision resolution (lowest CAN ID wins) and CRC-
         | protected frames. The latter feature is usually done by
         | hardware, just as in Ethernet.
        
           | bsder wrote:
           | CAN also autobauds so if you have frequency drift it
           | compensates. That's why it forces bit transitions via bit
           | stuffing if it gets too many 1's or 0's in a row.
        
       | inamberclad wrote:
       | Probably one of the least painful digital buses.
       | 
       | If anyone is wondering how to access an I2C bus from a Linux
       | computer, say, a raspberry pi:
       | 
       | int fd = open("/dev/i2c-1", O_RDWR);
       | 
       | ioctl(fd, I2C_SLAVE, [slave address here]);
       | 
       | Then you can read() and write() to the device with the kernel
       | taking care of all the transmission details. Usually all that's
       | exposed is a few bytes for the registers. To set a register,
       | write two bytes: first the register address, and then the value.
       | To read a register, write the register address and then read a
       | byte. Most of the devices have linear address spaces, so reading
       | out multiple registers is as simple as reading multiple bytes.
       | 
       | The i2c-tools package has some very handy CLI tools for exploring
       | an I2C bus.
       | 
       | Electrically, the bus is an open-collector design on both ends,
       | so devices can only pull the lines to low, and they release them
       | to set them high. Don't forget pull-up resistors!
        
         | inamberclad wrote:
         | A quick note: buy one of the really cheap (~$10) logic
         | analyzers on ebay and use Sigrok/Pulseview to to watch the bits
         | get sent over the wire! It's an absolutely invaluable tool for
         | the price.
         | 
         | The hardware inside those logic analyzers is fascinating in its
         | own right, too!
        
         | dws wrote:
         | To avoid clock-stretching problems, using one of the small
         | Arduinos that support USB serial to handle the I2C bus can help
         | considerably, at the expense of a bit more programming
         | complexity.
        
           | zeta0134 wrote:
           | I'm not at all familiar with this space, but I'm a bit
           | surprised the kernel isn't wrapping the I2C transmission and
           | helping to work around clock stretching issues anyway. Can
           | someone who's more familiar with this implementation weigh
           | in? It seems like that'd be the primary feature of writing to
           | the /dev/i2c* device instead of manually bit-banging the GPIO
           | pins from userland.
        
             | opencl wrote:
             | The Pi's hardware i2c has buggy silicon and does not handle
             | clock stretching properly. There's also a kernel driver to
             | bitbang i2c over the GPIO pins and clock stretching _does_
             | work properly with that.
        
               | BubRoss wrote:
               | Does the PI 4 also have this problem?
        
       | TOGoS wrote:
       | I'd like to know why 1-wire isn't more common. It seems to me
       | like a more elegant protocol than I2C. Not least because every
       | device has a unique baked-in address so you don't need to worry
       | about address collisions or dip switches to alter them.
       | 
       | (Also: needs one fewer wire)
        
         | londons_explore wrote:
         | Programming a globally unique ID per device is a large added
         | cost for <$0.01 devices. The device needs fuses or equivalent
         | so it can 'remember' it's 64 bit ID. it needs logic to both
         | program as well as read the fuses.
         | 
         | Think of applications like LED controllers - previously with
         | I2C all they needed was an 8 bit shift register + comparator
         | for their address, and an 8 bit shift register for their
         | 'brightness', and an 8 bit comparator and +-50% RC oscilator
         | for their actual operation. Probably ~400 transistors.
         | 
         | With onewire, they need a 64 bit address shift register, an
         | oscilator, a state machine for bus states, a counter to act as
         | a timer for long/short bits, multiple comparators on the timer
         | output. I don't think you could do it in less than 1000
         | transistors. Doesn't sound like much, but when every LED in a
         | million pixel LED wall needs one of these circuits, it adds up!
        
         | AWildC182 wrote:
         | If I had to guess, using clock-less (serial) protocols like 1
         | wire and UART requires some logic on each RX side to figure out
         | what the clock of the incoming signal is, usually a PLL of some
         | sort, and you'll need lots of crystal oscillators to ensure
         | that clocks are sufficiently stable and accurate as to ensure
         | reliable communication.
        
           | andyjpb wrote:
           | 1-wire is pretty slow (kbps max in normal mode) and very
           | tolerant of devices with a wide range of timing skew.
        
         | andyjpb wrote:
         | I have wondered this too.
         | 
         | Maxim have documentation about the fact you can get device IDs
         | but I've never actually worked out how to get some. I guess
         | people didn't want to be reliant on Maxim as the numbers
         | authority?
         | 
         | It's pretty popular for simple serial number / "Number In A
         | Can" applications tho'.
        
         | londons_explore wrote:
         | I was under the impression it used to be patent/licensing
         | encumbered?
        
       ___________________________________________________________________
       (page generated 2020-01-22 23:00 UTC)