Hacker News new | past | comments | ask | show | jobs | submit login
I2C in a Nutshell (memfault.com)
375 points by fra 34 days ago | hide | past | web | favorite | 107 comments



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!


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!


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


Interesting. This intro to Sigrok looks like it covers things pretty well too:

https://www.youtube.com/watch?v=dobU-b0_L1I

That, and a cheapo Saldae clone might be all I need for learning how to use a logic analyser finally. :)


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.


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.


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.


Does the PI 4 also have this problem?


There's a claim that it was fixed here:

https://www.raspberrypi.org/forums/viewtopic.php?p=1484482#p...

Apparent confirmation here (by mapping a different I2C bus?):

https://www.raspberrypi.org/forums/viewtopic.php?p=1544123&s...


I'm not sure about the 4, though it was present at least from the original up through the 3B+.


Not all i2c devices can be read that way. There are several devices that require an address (on top of the device address) to be written before data can be read, but without a second stop bit after writing the address. You end up with like double start condition. These require either using the smbus stuff or I2C_RDWR ioctl.


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.


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.


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


There is a safe, out of band way to do this that system designers can utilize. Reset all the other peripherals on the bus.


Wow


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


Say you’ve asked an I2C ROM for a block read. After the first byte something, also on the bus, asserts an interrupt via a side band GPIO. I can’t read the something until the block read finishes.


The specific case I was thinking of was the host suffering an incident where it is not possible or practical for its software to know where it left off.

For example, you get a kernel panic, or soft-reset for some reason. When you recover, you now have a bus in an unknown state, possibly mid-transaction, and if you pick the wrong order in which to bring the bus back to idle, you might wedge it or accidentally cause a side-effect (e.g overwrite a byte in an EEPROM).


But doing bus communication from software is generally a bad idea. Best is to use a hardware controller dedicated to the task. Do you have examples for bus protocols that can be run from software?


I assert NACK, and the block read terminates. Then I service the interrupt.


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.


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.


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


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>


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.


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.


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.


I've worked on server hardware with dozens of devices on a bus :-). Making sure addresses were programmable was a must indeed.


This happened to me once. Used proximity infrared sensors that used I2C with a fixed address. Needed to use multiple of them. I was able to fix it with a tri-state buffer, but quite the pain to figure out why things were not working and coming up with a solution.


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.


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


Cool! I've never seen this before.


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.


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


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.


this is a very good point, and i have had the same experience. its also super common for very cheap, very low end custom ics to use i2c for the same reason; keeping the pin count and package size down


Don't forget the reset lines to each device that you need to release the bus when they get locked up!


No reason why you need to reset them individually ;-).


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.


For what it's worth, here is a good doc on I2C resets: https://www.analog.com/media/en/technical-documentation/appl...


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


There are so many buggy I2C devices out there, I wouldn't say you're gaining hardware robustness, either.


I2C has caused me probably the most grief out of all the buses, as it's been the most painful to work with when designing the schematic (because even with only 3 devices you have to deal with address conflicts), initially writing the software (because the specification is quite lax on what can happen when, inevitably the interface between hardware and software is quite complex and a lot of it is very latency sensitive. A lot of hardware for it is quite buggy or just poorly designed as well), and in terms of ongoing bugs and issues (because of said latency sensitivity and propensity for locking up).

I try to avoid it as much as possible. If I need a peripheral, I prefer SPI, if I need a bus for connecting devices I control, I use CAN. If I'm connecting two systems together, a UART.


This sounds much like a brown-out where only half the system resets or worse, parts of it go into an undefined state. The proper way to deal with this is a complete reset/power cycle.

Granted, that's not easy to do if your peripherals have no reset pin or their power source cannot be switched by the bus master.

Would your problems go away if you had I2C plus a dedicated reset pin on all peripherals?


SMBus (which is close enough to call I2C) is also a major pain in the ass for Linux integration. If a master goes out of sync with a slave, or a poorly programmer slave tries to multi-master the bus or something, your kernel will hang and crash.


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


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.


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.


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.


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.


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



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.


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.


Thanks for the kind words! I was up late last night writing this up, it's encouraging to see folks enjoy it.


In an article about I2C? They're not related, and I2S is far more specialized.


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.


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


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.


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.


> 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


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.


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


I use 0.1" (2,54mm) pads (with headers) for all my prototypes. I don't like to use connectors when first developing a product or proof-of-concept: I cannot easily connect a scope/multimeter to a JST connector or its exposed pins.

In electronics, there is nothing better than a good piece of wire soldered between two boards. Connectors are a convenience feature.


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


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.


Good advice, except for debugging (SWD). For that I would definitely go with Tag-Connect (see my article at https://partsbox.io/blog/choosing-a-debug-programming-connec...). Main reasons: 1) my boards are space-limited, 2) I really enjoy using a single debug connector for all my boards (and many third-party boards as well), 3) I really like the idea of having a debug connector that costs $0 on the board.

As for other connectors: for Li-Ion batteries I use JST-PH connectors, standardizing on the pinout used by AdaFruit for batteries they sell.

For any custom "future extension" type connectors with I2C or SPI: 0.1" header holes. I can use them to either solder wires or place pin headers if needed.


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.


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

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


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.


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.


What are locking headers?


A 'header' is a board-to-board or wire-to-board connector:

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/W...

If you scroll down to 'mating products' you can find wire-to-board connectors designed to mate with it.


Let's assume you just want to hook up a BME280 to an Arduino or RasPi, that would be the quickest way to end up dealing with i2c. https://www.bosch-sensortec.com/products/environmental-senso...


http://www.nuke24.net/docs/2019/WSTYPE-4106-I2C-over-GX16-4....

Or GX12-4, if you want something a little smaller.


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.


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


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


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.


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


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.


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


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


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.


I had to rely to this, BTDT ;)


Sounds cool. Can you access the GPIO pins directly from Elixir?


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


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


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)


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!


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.


1-wire is pretty slow (kbps max in normal mode) and very tolerant of devices with a wide range of timing skew.


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.


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.


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


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


I was under the impression it used to be patent/licensing encumbered?


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


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.


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



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



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


am I correct on the I2C use cases?

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


Was this a nutshell??




Applications are open for YC Summer 2020

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: