...
SDA = Serial Data = Streams/Receives binary data onto the bus
SCL = Serial Clock = Synchronizes binary data. SDA is sampled on the rising edge of SCL
Take an example waveform:
...
We notice that I2C is an uses 8-bit communication protocol, meaning that for data frames. For every 8 bits, we receive an ACK/NACK on the 9th bit. We can also take note of the following characteristics:
START BIT = Pulling SDA low while SCL is high
END BIT = Pulling SCL SDA high while SDA SCL is lowhigh
ACK/NACK BIT = This is the 9th bit. ACK means the message was received properly, bit will be 0. NACK means the message was not received, bit will be 1
We define the bus in an “idle” state when both SDA and SCL are high, and we sample always on the rising edge
Standard I2C Communication Steps:
...
Open-Drain:
The defining characteristic of I2C buses is that both SCL and SDA are open-drain pins. Put simply, this , the pins are driven by a single transistor(MOSFET), When Vin is HIGH, Vout = GND. However, when Vin is LOW, we notice that Vout is left floating. That's when the pull-up resistor pulls the line HIGH
...
Notice that there is only 1 NMOS transistor that controls Vout. A Pull-up/Pull-down GPIO has two transistors. The drain is connected to the signal, and the source is tied to ground. This means the STM32 can only pull the line LOW. It needs a pull-up resistor to go back HIGH, as the pin is left floating. This plays a crucial role in preventing contention (Covered in arbitration and clock stretching)
...
Notice that there is only 1 NMOS transistor that controls Vout. A Pull-up/Pull-down GPIO has two transistors. When Vin is HIGH, Vout = GND. However, when Vin is LOW, we notice that Vout is left floating. That's when the pull-up resistor pulls the line HIGH.
I2C Speeds
Standard Mode (100 kbps)
Fast Mode (400 kbps)
Fast Mode Plus (1 Mbps)
Compared to SPI and CAN it is slower.
and leaving the output in something called “High-Z”. If you’re still confused by the purpose of Pull Up/Pull Down Resistors, see this document.
Pull-up Resistors:
The value of your pull-up resistor plays a crucial role in efficient communication. The following relations are important in choosing your pull-up resistance:
Higher supply voltage → Higher pull-up resistor (V/I = R)
More resistance → Lower power and current consumption (V2/R = Power) (V/R = I)
Lower resistance → Higher bandwidth/frequencies; faster rise time
More capacitance → Lower pull-up resistor
Generally, you should check the GPIO pins source/sinking current to determine the sizing of the pull-up/down resistor. Common values are 1k, 4.7k, 10k, but that will always depend on the scenario)
https://www.youtube.com/watch?v=sCHK3P5tn7s
Take this example from a random forum online https://electronics.stackexchange.com/questions/102611/what-happens-if-i-omit-the-pullup-resistors-on-i2c-lines
...
The first image captures an I2C waveform with a very high pull-up resistor. This is evident in the slow rise time and incomplete waveform. The poster was actually using the internal pull-up resistors of the ATMEGA Arduino board (20k-50k ohms)
...
The poster added 4.7k ohm pull-up resistors, increasing the rise time significantly. Make sure to choose the appropriate pull-up resistance for your application! Also having I2C test points can really save your sanity 🤠
Note: This also goes into a different discussion of using good practices when probing signals(close ground return paths)
Multi-Slave Busses
I2C buses can hold up to 127 slaves on a single bus. Unlike SPI, I2C does not have a chip select line to control communication. Instead, I2C relies on IC addressing (each IC on the bus has a different address). Typically each slave has alternative addresses that can be configured in the situation two slaves have the same address.
...