
I2C Master ISR State Machine:

The I2C Master Finite State Machine (FSM) provides the user with the ability to transfer or receive a buffer of bytes over the I2C protocol. 

The I2C Master FSM uses Timer Interrupt to provide appropriate timing to generate START, STOP, RESTART and byte read or write. In case of byte read or write, Timer interrupt is responsible for generating clocks on SCL. The Timer interrupt is running at 4 times the Baud-rate. Since interrupt mechanism is used, it is the responsibility of the user to ensure that global interrupts are turned ON.

Variable Definitions:

uint16_t  I2CSWCounter - 
Holds the count of clocks during a data transfer. The initial value of this variable is set to 9 and is decremented after SCL clock during data transfer. The value of 9, accounts for 8 data bits and 1 ACK bit.

uint16_t  I2CSWData -
Holds the data to be transferred. The data is shifted on each clock pulse and the most significant bit of the data is output on SDA at each clock.

bool I2CNACKOut - 
Determines if the byte being read should be ACKed or NACKed.

bool I2CACKStatus -
Checking the value of the flag will indicate if the byte was ACKed by the slave. A value of 1, indicates the byte was ACKed while a 0 indicates the byte was NACKed.

uint16_t  I2CReadData -
Holds the value that is being received from the slave.

uint16_t i2cBaudTime - 
holds the 4 times the baud-rate value. This value is used by the timer to set its period.

uint16_t i2cDeviceaddress - 
Holds the slave device address.

uint8_t* i2cDevicetxBuffer -
Holds the pointer to the transmit data buffer.

uint8_t i2cDevicetxlen -
Determines the number of bytes of data that is to be transmitted to the slave. The number of bytes does not include the slave device address.

uint8_t* i2cDevicerxBuffer - 
Holds the pointer to the data received from the slave.

uint16_t i2cDevicerxlen -
Determines the number of data bytes to be received from the slave device. 


Usage Model:

/***************************************************************************************************************/
*
*
* void I2C_Initialize ( uint32_t baudrate, bool masterISREnable, bool busISREnable )
*
*
***************************************************************************************************************/


Summary:
This functions transfers data from the Master to the Slave. 

Function Parameters:
baudrate 		- sets the baud rate at which data transfer takes place. This value is used to calculate the timer value.
masterISREnable		- decides if the I2C Master interrupt using the IECx and IFSx registers is enabled in software. This interrupt will be triggered by software upon completion of a 			  	  STOP condition
busISREnable		- decides if the I2C Bus interrupt using IECx and IFSx registers is enabled in software. This will be triggered by software when a bus collision is detected.

Summary:
The first step is to initialize the I2C peripheral. Ithe SCL and SDA pins are configured as inputs with their respective Open-Dran configuration enabled. The baud-rate is accepted as a function parameter and is used to calculate the rate at which Timer interrupt happens. The timer period is set to trigger at 4 times the baud-rate which enables data transition in the middle of clock and to read the middle of high side of clock when the data is stable according to I2C specifications.  The Timer Interrupt is responsible for providing correct timing for START, STOP, RESTART and byte transfer operations.

*Note: I2C Master interrupt and Bus Exception interrupt refer to the same CPU interrupt that is defined in the Interrupt Vector Table and must be enabled and triggered using corresponding bits in IECx and IFSx registers respectively.

/***************************************************************************************************************/
*
*
*  I2C_OPERATION_STATUS DRV_I2C_MasterBufferWrite(uint16_t deviceaddress, uint8_t* txBuffer, uint16_t txbuflen)
*
*
/***************************************************************************************************************/

Summary:
This functions transfers data from the Master to the Slave. 

Function Parameters:
deviceaddress 	- device address of the slave
*txBuffer 	- pointer to data buffer that contains data to be written to the slave
txbuflen	- number of bytes to be transferred to the slave

Returns:
Status of I2C Bus

Description:
When the function is called, the status of the I2C bus is checked using i2cStatus before a buffer transfer operation commences on the I2C bus. If the flag i2cStatus is set at I2C_STOP_COMPLETE,I2C state machine is kicked off by invoking StartI2C(). For any other value of i2cStatus, it implies that an I2C transaction is in progress and the the function call returns an error.


/***************************************************************************************************************/
*
*
*  I2C_OPERATION_STATUS DRV_I2C_MasterBufferRead(uint16_t deviceaddress, uint8_t* rxBuffer, uint16_t rxbuflen)
*
*
/*****************************************************************************************************************/

Summary:
This function enables Master to read data from a slave device. 

Functiona Parameters:
deviceaddress 	- device address of the slave, 
*rxBuffer	- pointer to the data buffer into which data from slave is to be read
		  since this is a read operation, the R/W bit in the slave address will be set before sending out the address
rxbuflen	- Number of bytes to be read from the slave

Returns:
Status of I2C Bus

Description:
When the function is called, the status of the I2C bus is checked using the flag, i2cStatus before a buffer transfer operation commences on the I2C bus. If the flag i2cStatus is set at I2C_STOP_COMPLETE,I2C state machine is kicked off by invoking StartI2C(). For any other value of i2cStatus, it implies that an I2C transaction is in progress and the the function call returns an error.
This function reads the slave device, the number of data bytes that is read is specified by by the number of bytes to be read from slave (rxbuflen)

/**********************************************************************************************************************************************************/
*
*
* I2C_OPERATION_STATUS DRV_I2C_MasterBufferWriteRead(uint16_t deviceaddress, uint8_t* txBuffer, uint16_t txbuflen, uint8_t* rxBuffer, uint16_t rxbuflen)
*
*
/**********************************************************************************************************************************************************/


Summary:
This function enables Master to write and read data from a slave device without relinquishing the I2C bus. 

Function Parameters:
deviceaddress 	- device address of the slave
*txBuffer 	- pointer to data buffer that contains data to be written to the slave
txbuflen	- number of bytes to be transferred to the slave
*rxBuffer	- pointer to the data buffer into which data from slave is to be read
		  since this is a read operation, the R/W bit in the slave address will be set before sending out the address
rxbuflen	- Number of bytes to be read from the slave

Returns:
Status of I2C Bus

When the function is called, the status of the I2C bus is checked using the flag, i2cStatus before a buffer transfer operation commences on the I2C bus. If the flag i2cStatus is set at I2C_STOP_COMPLETE,I2C state machine is kicked off by invoking StartI2C(). For any other value of i2cStatus, it implies that an I2C transaction is in progress and the the function call returns an error.
This function is used to index to a slave register address and read the contents thereon as specified by the number of bytes to be read from slave (rxbuflen)


/***********************************************************/
*
*
* I2C_OPERATION_STATUS DRV_I2C_MASTEROpStatus(void)
*
*     
/***********************************************************/

Summary: 
This function can be called to check the status of an I2C operation.

Function Parameter:
None.

Returns:
Status of I2C operation

Description:
This function returns the status of an I2C operation. If the status returned is other than I2C_STOP_COMPLETE, a new I2C transaction cannot be started on the bus.

/***********************************************************/
*
*
* I2C State Machine:
*
*
/***********************************************************/

The various states in the I2C Finite State Machine (FSM)are invoked through Timer interrupt. The Timer interrupt is triggered at 4 times the baud-rate which is the rate at which the I2C FSM progresses through each state. The specific state in I2C FSM that will execute depends on where the I2C bus is at during a data transaction.

**Note: To reduce interrupt latency, Shadow Register Set should be used. This is achieved by using the PRISS register and including the "SRS" attribute (iplxSRS) in Timer interrupt declaration.

Start Condition:
The START condition is only generated if the I2C Bus is determined to be idle. The bus is idle only if both the SCL and SDA are in high. 

I2C_SDA_LOW_START - 
	Pulls the SDA line low, SCL is still high
I2C_SDA_LOW_START_CHECK - 
	Idle state occuring after 1/2 BRG time. SDA is low
I2C_SCL_LOW_START - 
	After another 1/2 BRG time has expired pull SCL low. This creates START condition on the bus
I2C_SCL_LOW_START_CHECK
	Start operation is complete. The I2C FSM then proceeds to the next stage to transmit the first byte, the slave device address byte.

Data Transfer Operation:
Transfers each byte of data until all the data in the trasmit buffer is empty or the data in receive buffer is full. The four states pertinent to data transfer operation is mentioned below. A progression through each state denotes transfer of one byte. The states are called repeatedly to acoomplish transfer or reception of multiple byte. The data is transitions in the middle of the low level of the SCL.

I2C_SCL_LOW_DATA_CHECK -
	This is the start of low period of clock and the SCL is set to low. 

I2C_SCL_LOW_DATA-

	The purpose of this state is two fold. First, it outputs or receives the data bit on the SDA. Second, if all the data bytes have been transmitted or received, the FSM transitions to 	I2C FSM state that outputs a STOP condition on the bus.

	Each bit of data is put onto the SDA line. On the ninth clock, the SDA line is kept floating allowing the slave to ACK or NACK the byte when data is transferred from Master to Slave 	(WRITE). In case when data is received from Slave (READ), on the ninth clock, the Master outputs a LOW on SDA indicating more data is expected from the slave. The Master can also 		float the line HIGH on the ninth clock (NACK), to indicate the slave that the Master does not expect any more data.
	
	If either any of the data byte transmitted is NACKed by the slave, the rest of the data is not transmitted and the I2C FSM will prepare to initiate a STOP condition on the bus.

I2C_SCL_HIGH_DATA - 
	This is the start of High period of the clock and SCL is pulled high.

I2C_SCL_HIGH_DATA_CHECK -
	In a WRITE operation, the middle of the ninth clock is checked to determine if the data sent to the slave was ACKed. In case of read operation, data is sampled at the middle of the 		high part of SCL.

Restart Condiiton:

I2C_SDA_HIGH_RESTART -
	SDA line is pulled high to initiate restart.

I2C_SDA_HIGH_RESTART_CHECK 
	Keeps SDA high for 1/4 baud-rate time more from the I2C_SDA_HIGH_RESTART.

I2C_SCL_HIGH_RESTART - 
	SCL line is pulled high after 1/4 baud-rate time more from I2C_SDA_HIGH_RESTART_CHECK.

I2C_SCL_HIGH_RESTART_CHECK -
	SCL line is kept high for 1/4 baud-date more I2C_SCL_HIGH_RESTART

After another 1/4 baud rate time has expired, the I2C FSM to set to the state that creates a start condition on the bus.

Stop Condition:

I2C_SCL_SDA_LOW_STOP:    
	Set SCL and SDA low.
I2C_SCL_SDA_LOW_STOP_CHECK:
	Keeps SCL and SDA low of 1/4 of baud-rate time.
I2C_SCL_HIGH_STOP
	Set SCL High
I2C_SCL_HIGH_STOP_CHECK
	Wait for another 1/4 baud rate time.
I2C_SDA_HIGH_STOP - 
	Pull SDA high after another 1/4 baud rate time.
I2C_SDA_HIGH_STOP_CHECK:
	Wait another 1/4 baud rate time to complete STOP condition.



 

