
I2C in a Nutshell - fra
https://interrupt.memfault.com/blog/i2c-in-a-nutshell
======
inamberclad
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
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!

~~~
hartzell
I've found the
[I2CDriver]([https://www.adafruit.com/product/4267](https://www.adafruit.com/product/4267))
device to be really useful with debugging, poking, and otherwise prodding I2C
devices.

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

~~~
fra
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.

~~~
clarry
> 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.

~~~
danellis
That's still seven bits of address, though. If you're lucky, the hardwired
part will be different enough between chips that you can still have a
significant number of them on a bus.

~~~
rcxdude
I've yet to get above 4 devices without conflicts. Even with evenly
distributed addresses, you reach about 50% chance of conflict with 13 devices
because of the birthday paradox.

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

~~~
PinguTS
I would not call bit-resynchronization as "autobaud". Because CAN has no
autobaud.

That said, with Classical CAN you can implement an autobaud (better: automatic
bit rate detection) like mechanisms when you can make some assumptions on the
used bit rates. With CAN FD and the upcoming CAN XL you cannot do that.

PS: Baud is a term specifically applying to communication systems that
transmit symbols and a symbol can represent more than a bit. That is why I2C,
SPI, LIN, CAN, Ethernet have a bit rate. While RS232 has a baudrate, which is
different from the bit rate depending on the type of symbol used.

------
linker3000
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](https://github.com/linker3000/shukran)

------
Zenst
Worth reading this afterwards: [https://hackaday.com/2019/04/18/all-you-need-
to-know-about-i...](https://hackaday.com/2019/04/18/all-you-need-to-know-
about-i2s/)

~~~
fra
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
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
Thanks for the kind words! I was up late last night writing this up, it's
encouraging to see folks enjoy it.

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

------
metaphor
> _In doubt, go to 2K resistors._

I find handwaving recommendations like this rather pervasive and annoying,
especially in a professional setting.

If you're serious about I2C after gratifying yourself with this bootcamp-style
smashbang intro, I highly recommend reading the actual spec[1] (which is more
like a casual app note IMHO); the blog apparently doesn't link to it. It's
free, relatively short, and oh by the way, there's an entire section which
properly addresses pull-up resistor sizing and then some. You'll also be able
to spot inaccuracies like:

> _It has transfer rates up to 400Kbps_

[1] [https://www.nxp.com/docs/en/user-
guide/UM10204.pdf](https://www.nxp.com/docs/en/user-guide/UM10204.pdf)

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

~~~
bsder
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](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.

~~~
nlfwhulsdhouv
I agree overall but that's a weird comparison with the tag connect. It's not
meant to be small, it's meant to avoid soldering a header down to the target
board for programming. It's useful for Z-height or cost savings, not for XY
savings.

~~~
bsder
Sadly, it's not uniquely useful for _that_ either.

I can solder a set of pins (or pogo pins) on a .100 spacing and mate into the
.100 header holes. Or I can offset the .100 holes very slightly so they
friction grab a .100 2x2 male header in the holes.

Or I can buy a breakout board that does the same thing for $7.00 for 2 rather
than $50 per cable like Tag-Connect:
[https://www.pcbway.com/project/gifts_detail/PogoProg_Model_D...](https://www.pcbway.com/project/gifts_detail/PogoProg_Model_D_Pogo_Pin_Programmer___2_Pack.html)

.100" headers are hard to beat for general effectiveness.

------
otterpro
I don't know if anyone else noticed, but the web page uses SVG for signal
graph, which I originally thought was an image. The way SVG is used is very
subtle but very nice looking.

~~~
metaphor
The right-click-to-save-as-PNG-or-SVG feature is quite nice as well.

------
bsder
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).

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

~~~
jlangemeier
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
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.

------
jhallenworld
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](https://github.com/jhallen/i2cmon)

------
TOGoS
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)

~~~
AWildC182
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
1-wire is pretty slow (kbps max in normal mode) and very tolerant of devices
with a wide range of timing skew.

~~~
agapon
I wouldn't call it very tolerant. Some timings are pretty tight, like 1 to 15
microseconds, and every microsecond can count. And I am not talking about the
overdrive mode where the timings are much tighter.

~~~
andyjpb
One of the datasheets I have here says:

\----- During the initialization sequence the bus master trans- mits (TX) the
reset pulse by pulling the 1-Wire bus low for a minimum of 480µs. \-----

There is no maximum time limit for the reset pulse.

\----- The bus master then releases the bus and goes into receive mode (RX).
When the bus is released, the 5kΩ pullup resistor pulls the 1-Wire bus high.
When the DS18B20 detects this rising edge, it waits 15µs to 60µs and then
transmits a presence pulse by pull- ing the 1-Wire bus low for 60µs to 240µs.
\-----

A tolerance of 15uS to 60uS on the device side and 60uS to 240uS on the driver
side seems pretty wide to me.

Now, it's hard to actually get a good figure for these specifications because
different datasheets give different values, which further suggests the
tolerances are large.

Another datasheet that I have here says that the presence pulse should be
sampled after 72uS. This leaves at least 12uS slack for rise times, long
wires, etc.

To give an idea of whether 10uS is very long or not, remember that the cycle
time on, for example, an 8MHz AVR as you might find in an Arduino, is 125nS.
That gives you 80 instructions every 10uS (at the AVR8's advertised
1MIPS/MHz). This is plenty of time to implement the 1-Wire driver in software.

~~~
agapon
It seems that you didn't reach the part of the spec that describes how to read
and transmit data bits.

Also, even for simplest slaves there is still a need to keep track of time
which requires additional hardware (an oscillator or some such).

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

~~~
neillyons
ha me too. I wanted to learn micro python and record the altitude of my
quadcopter.

------
vic20forever
Comparison of I2C and SPI:
[https://news.ycombinator.com/item?id=9303405](https://news.ycombinator.com/item?id=9303405)

------
AceJohnny2
> _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...)

------
shivji
[https://12minuteaffiliatereviews.blogspot.com](https://12minuteaffiliatereviews.blogspot.com)

------
thesh4d0w
FYI you're missing a word in "for pulse on the SCL line", I think is supposed
to read "for every pulse"

------
jgalt212
am I correct on the I2C use cases?

\- reduce number of wires / overall length of cable runs \- more
sensors/actuators than GPIO pins

------
nehagup
Was this a nutshell??

