9 ms·
I2C in a Nutshell
- Isamu 7y agoVery 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 7y agoArticle 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 7y agoCAN 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 7y agoI 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.
- inamberclad 7y agoProbably 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!
- dws 7y agoTo 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 7y agoI'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.
- Ives 7y agoI 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.
- shortsightedsid 7y agoOn 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 7y agoFor 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 7y agoFor what it's worth, here is a good doc on I2C resets: https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf https://www.analog.com/media/en/technical-documentation/appl...
- pslam 7y agoSame. 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.
- whalesalad 7y agoI'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.
- neillyons 7y agoSounds cool. Can you access the GPIO pins directly from Elixir?
- whalesalad 7y agoYes. 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 https://github.com/elixir-circuits/circuits_gpio
- fpgaminer 7y ago> 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.
- whalesalad 7y agoThe 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.
- neillyons 7y agoThis 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
- Zenst 7y agoWorth reading this afterwards: https://hackaday.com/2019/04/18/all-you-need-to-know-about-i2s/ https://hackaday.com/2019/04/18/all-you-need-to-know-about-i...
- fra 7y agoYes! 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 7y agoAgreed, 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 7y agoThanks for the kind words! I was up late last night writing this up, it's encouraging to see folks enjoy it.
- danellis 7y agoIn an article about I2C? They're not related, and I2S is far more specialized.
- nlfwhulsdhouv 7y agoI2S is much closer to SPI than I2C. It really has nothing to do with I2C other than it connects chips together on a board.
- blattimwind 7y agoI2S isn't really related to I2C beyond the similar name and the fact that both used to be commonly used in audio devices (I2C for control, I2S for audio data transport). I2S is pretty much just a specific incarnation of SPI with more bit-lines for more channels and a channel select line.
- linker3000 7y agoHere 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
- TOGoS 7y agoI'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 7y agoIf 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 7y ago1-wire is pretty slow (kbps max in normal mode) and very tolerant of devices with a wide range of timing skew.
- agapon 7y agoI 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 7y agoOne 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.
- skybrian 7y agoI 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 7y agoThis. 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 7y agoIf 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 7y agoWhat are locking headers?
- nlfwhulsdhouv 7y agoA 'header' is a board-to-board or wire-to-board connector: https://www.digikey.com/product-detail/en/w-rth-elektronik/61300411121/732-5317-ND/4846827 https://www.digikey.com/product-detail/en/w-rth-elektronik/6... This is the type of connector most commonly used in hobby electronics, such as on the Arduino and Raspberry Pi. 0.1" is the 'pitch', the distance between pins. I picked a 1x4 (meaning <rows> x <pins> or <rows> x <pins per row>) version, but they come in many different pin and row counts. The version above is very simple, just bare pins that would get soldered to a PCB. There are many that come with additional 'features' that could be useful. For instance, you could get a locking header that has a tab to retain the connection against vibration or tugging. Or you can get a key or shroud that forces the connector to be inserted in the correct orientation. They also come in versions that support soldering directly to a PCB, vertically or at a right angle, or connecting to wires directly. Here is a locking header: https://www.digikey.com/product-detail/en/molex/0022232041/WM4202-ND/26671 https://www.digikey.com/product-detail/en/molex/0022232041/W... If you scroll down to 'mating products' you can find wire-to-board connectors designed to mate with it.
- AceJohnny2 7y ago> 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...)
- jhallenworld 7y agoHere'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
- imagiko 7y agoI 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 7y agoThanks! 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.
- vic20forever 7y agoComparison of I2C and SPI: https://news.ycombinator.com/item?id=9303405 https://news.ycombinator.com/item?id=9303405
- bsder 7y agoI'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).
- otterpro 7y agoI 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 7y agoThe right-click-to-save-as-PNG-or-SVG feature is quite nice as well.
- jgalt212 7y agoam I correct on the I2C use cases? - reduce number of wires / overall length of cable runs - more sensors/actuators than GPIO pins
- nehagup 7y agoWas this a nutshell??
- thesh4d0w 7y agoFYI you're missing a word in "for pulse on the SCL line", I think is supposed to read "for every pulse"
- metaphor 7y ago> 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
- shivji 7y agohttps://12minuteaffiliatereviews.blogspot.com https://12minuteaffiliatereviews.blogspot.com