I’m working on a project which involves an i2c communication between a master and some slaves. The master device is using an LPC2148 microcontroller running at 60 MHz and the slave ones have a low-cost PIC microcontroller. Each slave device runs a different task and some of them are more CPU-intensive than others.
The nature of this i2c communication is essentially some kind of Query-Response protocol in which the master requests some processing from the slaves and they send back the results to the master. The processing time varies from one slave to another and sometimes it will be higher than the master ‘clock’ time.
This leaded me to find a way to stop the master until the slave is done with its processing: clock stretching. The slave will pull the clock line down, causing the master to stop until it’s done with its task and then releases the SCL line (going high due to the required pull-ups of the i2c signals).
As I was writing the slave C code using PICC compiler, there was no way to implement this technique directly from the supplied i2c functions therefore I’d got to implement it by myself:
#bit CKP = PIC_SSPCON.4 // 1 = Release Clock, 0 = Holds Clock Low (clock stretch)
#define SCL_STRECTHING_ON bit_clear(PIC_SSPCON, 4); // CLK STRETCHING
#define SCL_STRETCHING_OFF bit_set(PIC_SSPCON, 4); // release clock to master
if(state >= 0x80) //Master is requesting data
delay_us(400); // Simulate processing delay
Please, note that the values defined for SSPCON register / bits are for PIC16F677 microcontroller and it might differ from the one you’re using.
Below you can see an screenshot of the Logic Analyzer output I used for testing purposes. You can see the 400 us delay between two consecutive readings from the master while the SCL line remains low.
All in all, it’s a well known technique described in the protocol specification but as far as I’m concerned by googling a little bit, its usage is not very extended and there are not so much source code out there addressing this issue.