I2C-SPI: Architecture (I2C)

In the pictured CMOS inverter, A is the input, and Q is the output. When A is low, the top transistor is on, and the bottom one is off. As a result, the top transistor connects Q to Vdd; thus, when A is low, Q is high. On the other hand, when A is high, the top transistor is off, and the bottom one is on. So the bottom transistor connects Q to Vss. So when A is high, Q is low. The output of this small circuit, Q, is the inverted version of A. That is why the circuit is called an inverter.

Now, if we had two of these inverters, and if we wanted to connect their outputs to each other such as in an I2C bus, the nature of I2C necessitates that these two inverters have their Qs tied together. But what if one inverter outputs a high on Q and the other outputs a low on Q? This would create a low impedance, high current short circuit, which is a hazard for the design. 

We can resolve this by simply removing the top transistor (in the general case, this would be removing the pull-up network of the output gate). Now, when A is low, Q only sees a floating voltage (since the bottom transistor is off). In this sense, the inverter can only pull Q low; it cannot drive Q to a logic high. We still need a pull-up resistor to create a path to the Vcc when A is low. Eventually, it becomes safe if two devices try to drive the SDA to different values.

Although it may not seem like it due to their different roles, masters and slaves that use I2C are the same from a component standpoint. Masters and slaves can affect the output of the SDA (which is tied to a pull-up resistor) by switching the transistor on or off. 

Additionally, due to the half-duplex nature of I2C, the master or slave connection to the SDA can be used as either an input or an output. Similar to how a GPIO can be configured as an input or output, a tri-state buffer is used to switch between the two. When the tri-state buffer is shorted, the master or slave can receive data from the SDA as an input. When the tri-state buffer is in high impedance, the master or slave can safely output data on the SDA (without this data feeding back into the logic circuit). 

It’s also worth noting that the maximum capacitive load on the SDA is 400 pF, which limits the bus length and the number of slaves.

From the architecture point of view, an I2C master or slave is comprised of a state machine, two shift registers, and a clock generator. The state machine implements the basics of byte transmission and reception, allowing the I2C peripheral to package or interpret data correctly. Each I2C peripheral has a transmit shift register and a receive shift register, in addition to buffers for each shift register. These shift registers are responsible for storing the data to be transmitted or received, respectively. Finally, the clock generator, as the name implies, allows the master to produce the clock signal that drives the synchronous communication.

When the peripheral is configured as a master, the peripheral loads the target slave address into the transmit shift register to begin transmission. Depending on whether the communication is a read or a write, the master can then enter transmitter mode or receiver mode, thus “activating” the respective register for output/input, respectively.


If the peripheral is instead configured as a slave, the peripheral will receive the first byte and compare it to its address. If there is a match, the peripheral then enters transmitter mode or receiver mode depending on the read/write bit value. In slave transmitter mode, the peripheral periodically sends data until it receives a NACK from the master. In slave receiver mode, the peripheral sends an ACK after receiving each byte until it encounters a stop condition.