/******************************************************************************************************************
File Name    			: I2C_Driver.c 
RTCC 					: MC79410, 
Language Tool Suites 	: PIC16 family, C language. 
Dependencies 			: htc.h
Processor   			: PIC16F1937
Hardware     			: PIC18 EXPLORER(DM183032), MCP79410  RTCC PICtail Plus Daughter Card(AC164140)
I.D.E.       			: MPLAB v8.80
Compiler				: Hi-Tech PRO C V9.83
Company     			: Microchip Technology Inc. 
/*******************************************************************************************************************

                  SOFTWARE  LICENSE AGREEMENT    

"Microchip Technology Inc." ("Microchip") licenses this software to you 
solely for use with Microchip's Serial RTCC products.  
The software is owned by Microchip and/or its licensors, and is protected 
under applicable copyright laws.  All rights reserved.
SOFTWARE IS PROVIDED "AS IS."  MICROCHIP AND ITS LICENSOR EXPRESSLY 
DISCLAIM ANY WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING 
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 
FOR A PARTICULAR PURPOSE,OR NON-INFRINGEMENT. IN NO EVENT SHALL MICROCHIP 
AND ITS LICENSORS BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR 
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, HARM TO YOUR EQUIPMENT, 
COST OF PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY 
CLAIMS BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE 
THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER SIMILAR COSTS."
/******************************************************************************************************************
Firmware Description : 
This firmware assumes 10Mhz as system clock to PIC16F1937 and uses MSSP module in I2C master mode to communicate with MCP7941x.
For further details on firmware please refer AN1414. The firmware does not enable code protection for flash and data memory. 
It is the responsibility of the user to enable required code protection.
*******************************************************************************************************************/
/******************************************************************************************************************
Firmware Revision History
Date					Author 			Revision			Changes
March,10,2011			PM				1.0				Initial Release
*******************************************************************************************************************/
#include "..\Header\I2C_Driver.h"

/********************************************************************
 * Function:        void InitI2C(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *					
 * Side Effects:    None
 *
 * Overview:        Initializes MSSP module in I2C single master mode. Default I2C clock is set to 100Khz
 *******************************************************************/
void InitI2C(void)
{
	SSPEN = 0;
	LCDEN = 0;
	I2C_SCL_TRIS = 1;
	I2C_SDA_TRIS = 1;
	SSPADD = I2C_SSPADD_VAL;					//Set I2C clock = 100Khz when Fosc = 10Mhz
	SSPCON1 = 0x28;								//Configure MSSP module in I2C master mode with I2C Clock = Fosc/(4*(SSPADD + 1))
}

/********************************************************************
 * Function:        void CHECK_I2C_IDLE(void)
 *
 * PreCondition:    None
 *
 * Input:           None
 *
 * Output:          None
 *					
 * Side Effects:    None
 *
 * Overview:        This is a blocking function. It returns only if I2C module becomes idle
 *******************************************************************/
void CHECK_I2C_IDLE(void)
{
	unsigned char Temp = 0;
	do{
		Temp = SSPCON2 & 0x1F;
	}while(Temp != 0);
	while(R_nW);
}

/********************************************************************
 * Function:        void WRITE_I2C(unsigned char Slave_Add,unsigned char Add, unsigned char Val)
 *
 * PreCondition:    None
 *
 * Input:           I2C slave address, Address where data is to be written, Data to be written
 *
 * Output:          None
 *					
 * Side Effects:    None
 *
 * Overview:        Writes a byte to I2C slave at specified address
 *******************************************************************/
void WRITE_I2C(unsigned char Slave_Add,unsigned char Add, unsigned char Val)
{
	CHECK_I2C_IDLE();
	SEN = 1;									//Initiate Start condition on I2C bus
	while(SEN);									//Wait for Start condition to complete
	SSPBUF = Slave_Add;
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device

	SSPBUF = Add;		
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device

	SSPBUF = Val;		
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device
	
	PEN = 1;									//Issue stop condition
	
}

/********************************************************************
 * Function:        unsigned char READ_I2C(unsigned char Slave_Add,unsigned char Add)
 *
 * PreCondition:    None
 *
 * Input:           I2C slave address, Address from where data is to be read
 *
 * Output:          Returns a byte as data read from I2C slave
 *					
 * Side Effects:    None
 *
 * Overview:        Reads a byte from I2C slave from specified address
 *******************************************************************/
unsigned char READ_I2C(unsigned char Slave_Add,unsigned char Add)
{
	unsigned char Ret_Val;
	CHECK_I2C_IDLE();
	SEN = 1;									//Initiate Start condition on I2C bus
	while(SEN);									//Wait for Start condition to complete
	SSPBUF = Slave_Add;
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device
	
	SSPBUF = Add;								//Place address to be read from I2C slave device
	CHECK_I2C_IDLE();	
	while(ACKSTAT);      						//Check for ACK from I2C slave device
	
	Slave_Add = Slave_Add | 0x01;				//I2C Read operation
	RSEN = 1;									//Initiate Restart condition on I2C bus
	while(RSEN);								//Wait for Restart condition to complete
	SSPBUF = Slave_Add;
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device
	
	RCEN =1;									//Prepare I2C master device for recepetion
	while(RCEN);								//Wait until read operation is completed
	Ret_Val = SSPBUF;
	ACKDT = 1;
	ACKEN = 1;
	while(ACKEN);
	PEN = 1;									//Issue stop condition
	
	return(Ret_Val);
}

/********************************************************************
 * Function:        void WriteI2CMultipleByte(unsigned char Slave_Add,unsigned char Add,unsigned char Cnt_Byte, unsigned char *ptrToData)
 *
 * PreCondition:    None
 *
 * Input:           I2C slave address, Address from where data is to be written, Number of bytes to be written, 
 *					Address of the buffer from where data is to be read and written to I2C slave device
 *
 * Output:          None
 *					
 * Side Effects:    None
 *
 * Overview:        Writes more than a byte to I2C slave device 
 *******************************************************************/
void WriteI2CMultipleByte(unsigned char Slave_Add,unsigned char Add,unsigned char Cnt_Byte, unsigned char *ptrToData)
{
	CHECK_I2C_IDLE();
	
	SEN = 1;									//Initiate Start condition on I2C bus
	while(SEN);									//Wait for Start condition to complete
	SSPBUF = Slave_Add;
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device

	SSPBUF = Add;		
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device
	do
	{
		SSPBUF = *(ptrToData++);
		CHECK_I2C_IDLE();
		while(ACKSTAT);      					//Check for ACK from I2C slave device
		Cnt_Byte--;
	}while(Cnt_Byte != 0);
	PEN = 1;									//Issue stop condition
}

/********************************************************************
 * Function:        void ReadI2CMultipleByte(unsigned char Slave_Add,unsigned char Add,unsigned char Cnt_Byte, unsigned char *ptrToData)
 *
 * PreCondition:    None
 *
 * Input:           I2C slave address, Address from where data is to be read, Number of bytes to be read, 
 *					Address of the buffer from where the read data(from I2C slave device) is to be written
 *
 * Output:          None
 *					
 * Side Effects:    None
 *
 * Overview:        Reads more than a byte from I2C slave device 
 *******************************************************************/
void ReadI2CMultipleByte(unsigned char Slave_Add,unsigned char Add,unsigned char Cnt_Byte, unsigned char *ptrToData)
{
	CHECK_I2C_IDLE();
	
	SEN = 1;									//Initiate Start condition on I2C bus
	while(SEN);									//Wait for Start condition to complete
	SSPBUF = Slave_Add;
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device
	
	SSPBUF = Add;								//Place address to be read from I2C slave device
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device
	
	RSEN = 1;									//Initiate Restart condition on I2C bus
	while(RSEN);								//Wait for Restart condition to complete
	SSPBUF = Slave_Add | 0x01;
	CHECK_I2C_IDLE();
	while(ACKSTAT);      						//Check for ACK from I2C slave device
		
	do{
		RCEN =1;								//Prepare I2C master device for recepetion
		while(RCEN);							//Wait until read operation is completed
		*ptrToData++ = SSPBUF;
		CHECK_I2C_IDLE();
		ACKDT = 0;
		if(Cnt_Byte == 1)
		{
			ACKDT = 1;
		}
		ACKEN = 1;
		while(ACKEN);
		Cnt_Byte--;
	}while(Cnt_Byte != 0);
	PEN = 1;									//Issue stop condition
}

/********************************************************************
 * Function:        bit CHECK_I2C_ACK(unsigned char Slave_Add)
 *
 * PreCondition:    None
 *
 * Input:           I2C slave address
 *
 * Output:          None
 *					
 * Side Effects:    None
 *
 * Overview:        Returns 0 if ACK received or 1
 *******************************************************************/
bit CHECK_I2C_ACK(unsigned char Slave_Add)
{
	CHECK_I2C_IDLE();
	SEN = 1;									//Initiate Start condition on I2C bus
	while(SEN);									//Wait for Start condition to complete
	SSPBUF = Slave_Add;
	CHECK_I2C_IDLE();
	return(ACKSTAT);
}