Configuring I2C Bus Time-out Feature

This I2C module allows the user the option to implement a configurable bus time-out in both Master and Slave modes of operation. The bus time-out will occur whenever the Serial Clock (SCL) line has been held low, beyond the amount of time specified in the user configuration. The I2C protocol specification does not require a specific bus time-out period and typically, the slave device can hold (clock-stretch) the clock line low indefinitely. The SMBus protocol requires a bus time-out of 35 ms, and the PMBus™ protocol requires a bus time-out period of 25 to 35 ms. The purpose of implementing a bus time-out is to prevent stalled devices from indefinitely holding the bus during communication. Although not required by the normal I2C specification, a defined bus time-out may be advantageous as a fail-safe, in events where a stall in communication occurs.

In the event where a device on the bus stalls and the time-out expires, the module will be Reset and forced into an Idle state. The I2C bus time-out can be used in both Master and Slave modes. Refer to the device data sheet for more information about how bus time-outs and the respective interrupts are handled in each mode of operation. To configure the bus time-out, the I2C Bus Time-Out register (I2CxBTO) is used to select the timer resource that serves as the time-out time base. The Bus Time-Out Interrupt Flag (BTOIF) has a corresponding enable bit (BTOIE) that the user can set if they wish to implement an Interrupt Service Routine when a time-out occurs.

The following code snippet shows a simple initialization routine that enables the I2C as a master device and uses Timer4 as the bus time-out source. The bus time-out period has been configured to be 35 ms in this code snippet, to comply with SMBus and PMBus™ protocol specifications. With this implementation, Timer4 will begin counting when SCL is inactive, and if SCL is held in an Inactive state for more than 35 seconds, the module will force itself to Reset.

Setting up the I2C Bus Time-out using Timer4

// Configure Timer4 (I2C Bus Time-Out Source) – 35ms
T4CLKCON = 0x06;		// Timer4 Clock Source = MFINTOSC 31.25 KHz
T4HLT = 0x00;
T4RST = 0x00;
T4PR = 0xDA;		    // Timer4 PR = 218
T4TMR = 0x00;			
PIR7bits.TMR4IF = 0;    // Clear Timer4 Interrupt Flag
T4CON = 0x84;		   // T4CKPS 1:1, T4OUTPS 1:5, TMR4ON on

// Configure I2C Master with Bus Time-Out	
I2CxCON1 = 0x80;
I2CxCON2 = 0x00;
I2CxCLK = 0x00;		 // I2C CLK = FOSC / 4
I2CxCON0 = 0x87;		// I2C EN = 1, Mode = Master Mode (SMBus 2.0)
I2CxPIR = 0x00;		 // Clear I2C Interrupt Flags
I2CxPIE = 0x08;		 // ADRIE = 1 (Must be enabled in SMBus Mode)
I2CxERR = 0x00;		 // Clear I2C Error Register
I2CxBTO = 0x02;		 // Bus Time-Out Selection = TMR4 Postscaler Out
I2CxERRbits.BTOIE = 1;  // Enable I2C Bus Time-Out InterruptsSetting up the I2C