In an I2C communication each device takes a designated role. It is either a master or a slave. These terms refer to the one who dictates the speed of the clock, i.e. who actually generates it. Unlike an RS232 scenario the actual Baud rate is not fixed to a constant value. Instead, the master device pulses the clock for each transmitted bit. The slave has to follow this speed. Since even slaves need to rest sometimes, it is possible for a slave device to hold down the clock line until it is ready to continue communication. This mechanism is referred to as clock stretching and assures that a slave device has the ability to protect itself from beeing addressed too quickly.
Whilst it is next to trivial to implement an I2C single master on a microcontroller the same is merely possible in many cases for a slave. A master generates a clock and drives the communication whenever it is ready to do so. In contrast, a slave device has to always be ready to detect and process a start condition and to recognize its address. This is relatively easy to achieve with a hardware state machine and extremely difficult with a microcontroller, especially if it is busy with other tasks, too. The challenge is to assure that at any point in time and regardless of the application state the microcontroller is ready to process a master request at the maximum clock speed allowed for the communication.
I2C Slave on a PC
Another rather tricky issue is to implement a slave interface for a PC.
The purpose of such interface is usually to simulate an I2C slave by PC software. This in turn means that the interface needs to talk to a PC application in order to know how to react to a master request. This introduces a timing issue and since none of the popular PC operating systems has real-time capabilities there are no easy solutions to this.
Let’s assume we want to build a slave device which returns the square of a given number. It listens to the I2C address 0x56, receives a byte as input and returns the square value of this byte (without any carry) in response to a subsequent read operation.
Now the master puts the 0x56 on the bus in write mode and sends a 7 afterwards.
The slave interface recognizes that it has been addressed and reads in the 7. Now it needs to do the processing and has to contact the PC for this to calculate the 49.
Depending on the used connection this takes anything between 80 µs and several ms. The interface could stretch the clock, but unfortunately there are many master mode implementations out that behave like dispots and do not allow clock stretching. In any case, many masters have a timeout for maximum clock stretching somewhere around 1 ms, which comes quite close to the delay caused in PC communication.
There are I2C interfaces for PCs which include a slave. E.g. Tracii 400 implements a slave mode and since it uses a parallel port connection the delays introduced are quite acceptable for many applications.