/**************************************************
**       I2C - prog                              **
***************************************************
** from: KoF                                     **
** date: 07.2004                                 **
** mail: King_of_Freaks@gmx.net                  **
**       King_of_Freaks@ist-einmalig.de          **
***************************************************
** compiler: mspgcc                              **
***************************************************
** simple I2C-basic funtions, to read and write  **
** @ I2C bus. the msp430 (i use an mspf149) is   **
** as master device. it generates an clock (SCL) **
** @ P6.2 and data (SDA) @ P6.3.                 **
***************************************************
** till now, i couldn`t test it, so i don`t know **
** if it`s working :(                            **
** please try it, correct it if necessary and    **
** reporte me, please                            **
**************************************************/ 


#include "io.h"
#include "signal.h"
//P6.2  SCL
//P6.3  SDA

#define TRUE  1
#define FALSE 0

#define SDA_1       P6OUT |=  BIT3              //SDA = 1
#define SDA_0       P6OUT &=~ BIT3              //SDA = 0
#define SCL_1       P6OUT |=  BIT2              //SCL = 1
#define SCL_0       P6OUT &=~ BIT2              //SCL = 0
#define DIR_IN      P6DIR &=~ BIT3;  SDA_1      
#define DIR_OUT     P6DIR |=  BIT3              
#define SDA_IN      ((P6IN >> 3) & 0x01)        //lese SDA

typedef	unsigned char byte;
typedef unsigned int word;
typedef unsigned long dword;

typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;

typedef unsigned char bool;




void I2C_vDelay(unsigned int n)
{
   unsigned int i;
   for (i=0; i<n; i++) {;}
}

void I2C_vInit()
{
    P6DIR |=  BIT2;         // clock "scharf" stellen
    SCL_1;                  // clock auf high (1)  
    SDA_1;                  // daten auf high (1)  
}

void I2C_vSendStart()
{
    SCL_1;                  // clock auf high
    SDA_1;                  // daten auf high  
    I2C_vDelay(5);          // kurze pause
    SDA_0;                  // daten auf low
    I2C_vDelay(5);          // kurze pause  
    SCL_0;                  // clock auf low
    I2C_vDelay(5);          // kurze pause
}

void I2C_vSendStop()
{
    SDA_0;                  // daten auf low
    nop();                  // kurze verzögerung
    nop();
    SCL_1;
    I2C_vDelay(5);
    SDA_1;
}

uchar I2C_ucReadAcknowledge()
{
    DIR_IN;
    SCL_1;
    I2C_vDelay(2);
    if(SDA_IN == 0)
    {
        I2C_vDelay(3);
        SCL_0;
        I2C_vDelay(5);
        DIR_OUT;
        return 't';
    }
    I2C_vDelay(3);
    SCL_0;
    I2C_vDelay(5);
    DIR_OUT;
    return 'f';
}

void I2C_ucSendNotAcknowledge()
{
    SDA_1;
    nop();
    nop();
    SCL_1;
    I2C_vDelay(5);
    SCL_1;
    nop();
    nop();
    SDA_0;
    I2C_vDelay(5);
}

void I2C_ucSendAcknowledge()
{
    I2C_ucSendAcknowledge();
    SDA_0;
    nop();
    nop();
    SCL_1;
    I2C_vDelay(5);
    SCL_0;
    I2C_vDelay(5);
}

unsigned char I2C_ucReadByte()
{
    uchar ucBitcount_;	     //temporäre Zählvariable
	uchar ucData_ = 0x00;	 //temporäre Datenvariable
	
    DIR_IN;
	for(ucBitcount_ = 0; ucBitcount_ < 8; ucBitcount_++)
	{
	    ucData_ = ucData_ << 1;		 //Bits um eine Stelle shiften
	    SCL_1;
	    I2C_vDelay(2);
	    if(SDA_IN == 1)
	    {
	         ucData_ |= 0x01;		 //Bit 0 setzen
		}
		else
		{
             ucData_ &= 0xFE;		 //Bit 0 löschen	
		}
		I2C_vDelay(3);
		SCL_0;
		I2C_vDelay(5);
	}
	DIR_OUT;
	return ucData_;
}
	
void I2C_vSendByte(uchar ucByte)
{
    uchar ucBitcount_;       //temporäre Zählvariable
    uchar ucData_;	         //temporäre Datenvariable
    
    ucData_ = ucByte;
    
    for(ucBitcount_ = 0; ucBitcount_ < 8; ucBitcount_++)
	{
		
		if(ucData_ & 0x80)			//MSB gesetzt?
		{
		    SDA_1;
        }
        else
        {
            SDA_0;
        }
        nop();
        nop();
        SCL_1;
        I2C_vDelay(5);
        SCL_0;
        I2C_vDelay(5);
        ucData_ = ucData_ <<1;
    }
}

uchar I2C_ucWriteByte(uchar ucAddress, uchar ucBuffer)
{

	I2C_vSendStart();			
	ucAddress &= 0xFE;		//Bit 0 zum aktivieren des Schreibmodus löschen
	I2C_vSendByte(ucAddress);
	if(!I2C_ucReadAcknowledge())
	{
		I2C_vSendStop();
		return FALSE;	
	}  
	I2C_vSendByte(ucBuffer);
	I2C_ucReadAcknowledge();
	I2C_vSendStop();
	return TRUE;
}

uchar I2C_ucReceiveByte(uchar ucAddress, uchar* pucBuffer)
{
	
	I2C_vSendStart();
	ucAddress |= 0x01;		//Bit 0 zum aktivieren des Lesemodus setzen
	I2C_vSendByte(ucAddress);
	if(!I2C_ucReadAcknowledge())
	{
		I2C_vSendStop();
		return FALSE;	
	}
	
	*pucBuffer = I2C_ucReadByte();
	I2C_ucSendNotAcknowledge();
	I2C_vSendStop();
	return TRUE;
}

int main (void)
{
	uchar MAI_ucData;
    I2C_vInit();
	I2C_ucWriteByte(0x91, 0x00);
	for(;;)
	{
		I2C_ucReceiveByte(0x90, &MAI_ucData);     // = 10010001
        I2C_ucWriteByte(0x91, 0x00);
	}
	return 0;
}


