I2C in a Nutshell | Interrupt

I2C is perhaps the most commonly used bus to connect ICs together. As such, firmware engineers encounter it on most project. In this post, we explain how I2C works, explore common bugs and investigate how to debug these issues.


This is a companion discussion topic for the original entry at https://interrupt.memfault.com/blog/i2c-in-a-nutshell

I think it is worth mentioning that the I2C bus can be stuck and then require a bus reset if the master cannot finish an access. It can happen if the master soft reset during a communication and the slave does not.

The issue is described and solved in the application note: https://www.analog.com/media/en/technical-documentation/application-notes/54305147357414AN686_0.pdf

Thank you for sharing all these blog posts. This is rare and good content.

Thanks for the note! Youā€™re right, I should have mentioned wedged buses. Iā€™ll update the post later today, and add a link to that app note.

Glad you enjoy the blog! Weā€™re always looking for folks who would want to write something, so let me know if you or anyone you know would like to :-).

Hiā€¦Good read to understand I2C.
I guess it would be better if you had mentioned about Multiple Masters on the bus and topic like bus arbitration.
Thanks.!!

Francois,

Very good post here.

Thought it may be useful to note that the I2C bus can support speeds in excess of 3 Mbps.

In such a case, the I2C master must transmit a ā€œmaster codeā€. The master code must be transmitted at a standard speed and is intended to allow multiple masters to arbitrate. It is up to the system integrator to ensure each I2C master on a single bus has a unique master code.

If the master code is transmitted without issue (no arbitration), the transaction will begin. Due to the high speed, the I2C master actively drives the busā€“hence the need to ensure arbitration is handled at a standard speed.

Hi - New to digital logic, so I might be misunderstanding something fundamental hereā€¦I have two questionsā€¦

Looking at almost all of the examples, the example says that it will transmit 0xC6, but the binary representation as 1100110 isnā€™t 0xC6ā€¦Why are they different?

Second question - if the I2C address size is 7-bits, how could you address 0xC6 which would require 8-bits to represent?

Other than that I thought it was a great piece.

Thanks

1 Like

I also find this explanation a little bit strange.

From what I learned and what Iā€™ve seen in data sheets: the address is always 8 bits, but an I2C slave device occupies effectively two addresses: one for read and one for write. Both addresses differ only in the LSB: ā€˜1ā€™ to read, ā€˜0ā€™ to write.

In the example, 0xCC would be the write address and 0xCD the read address.

Otherwise, thanks for this blog post! Nice introduction and good overview.

You canā€™t really connect 127 devices. There are a number of reserved adresses, general call addresses and backward compatibility locations for CBUS. Not only that, but the bus load for such a number of devices would be too big. You would have to use bus extenders to overcome the capacitive load ( it can be done. Many telecom and server racks use i2c for rack management such as bay temperature voltage and adressing ). You can extend a single bus beyong that number by using adressable i2c multiplexers. They basically create ā€˜subnetsā€™ on the bus.
I2C has many more modes like Fast mode and Fast mode plus that go beyond 4Mbit/s.
There are active terminators ( active pull-ups) that contain switchable current sources. Linear technologies makes those.
A stuck bus can be cleared by giving clockpulses until SDA goes high , then pulling SDA low , raising SCL followed by raising SDA ( effectively clocking until the data line goes high and then forcing a STOP operation. The bus arbitration mechanism of the I2C standard guarantees this behavior. Even in a multimaster system this procedure is valid.

Shameless plug: I wrote this a while ago https://www.elektor.com/mastering-the-i2c-bus-e-book ,
which is based on the original work i did back in the late mid 90ā€™s by writing The I2C FAQ on sci.electronics.faq

Thanks for the note @ftheile and @xerxesb. Youā€™re both correct, I used the ā€œ8-bit addressā€ instead of the correct 7-bit address (see more on the two here: https://www.totalphase.com/support/articles/200349176-7-bit-8-bit-and-10-bit-I2C-Slave-Addressing).

Iā€™ve fixed the post to refer to the 7-bit address: 0x66.

Thanks again!

1 Like

Thanks for the great information!

You are right of course, there are practical limitations to adding many devices to a bus. I think the main point here though is that i2c is multi-slave.

I chose to omit high speed mode, as in my experience few devices support it. For example, popular microcontrollers like the STM32 only go up to ā€œfast-mode-plusā€ (1MHz).

Iā€™ll add a note about clearing a stuck bus, thatā€™s definitely important and missing from this guide.

Stumbled on this old post @ francois. Quite informative. Keep the blogs coming. WRT to this i2c debug post and flowchart, perhaps thereā€™s one more step to be added. Iā€™ve seen cases [in multi-slave configs, or just in general when power is cycled mid transaction, for example] where the slave holds the SDA line low. General debug technique here, and you can programmatically automate this part is where youā€™d send a few clocks from the master to help the slave transition out of whatever ā€˜corruptedā€™ state it may be in.

At the end of every byte, the transmitter releases the SDA line, and on the next clock cycle the receiver must pull the line low to acklowledged the byte.

Can you change this to

At the end of every byte, the transmitter releases the SDA line, and on the next clock cycle the receiver must pull the SDA line low to acknowledge the byte.

This is a common misunderstanding. The spec states that Addresses are 7 bits, plus a read-write bit. When you implement the controller, its simple to treat the r/w bit as an address bit, and youā€™ll find older device that do it this way.

Because of this, its always better to specify which form of address youā€™re discussing. On schematics at work, we usually make 7-bit/8bit address tables to eliminate the ambiguity.