
/****************************************************************************
 Title	:   C  file for the I2C FUNCTIONS library (i2c.c)
 Author:    Chris efstathiou hendrix@otenet.gr
 Date:	    13/Jul/2002
 Software:  AVR-GCC with AVR-AS
 Target:    any AVR device
 Comments:  This software is FREE.

*****************************************************************************/

#include <io.h>
#include "i2c.h"

#ifndef CONCAT1
#define CONCAT1(a, b) CONCAT2(a, b)
#endif

#ifndef CONCAT2
#define CONCAT2(a, b) a ## b
#endif


/* Conversion of microseconds to the right value for the delay function */
#define I2C_DELAY	   ( (I2C_DELAY_TIME*(F_CPU/60000))/100 )  
#define I2C_TIMEOUT	   ( (I2C_TIMEOUT_TIME*(F_CPU/60000))/100 ) 

/* Register name forming */
#define I2C_SDA_OUT_REG   CONCAT1(PORT, I2C_SDA_PORT)
#define I2C_SCL_OUT_REG   CONCAT1(PORT, I2C_SCL_PORT)
#define I2C_SDA_DDR_REG   CONCAT1(DDR, I2C_SDA_PORT)
#define I2C_SCL_DDR_REG   CONCAT1(DDR, I2C_SCL_PORT)
#define I2C_SDA_PIN_REG   CONCAT1(PIN, I2C_SDA_PORT)
#define I2C_SCL_PIN_REG   CONCAT1(PIN, I2C_SCL_PORT)

/* Conversion of microseconds to the right value for the delay function */
#define I2C_DELAY	  ( (I2C_DELAY_TIME*(F_CPU/60000))/100 )  
#define I2C_TIMEOUT	  ( (I2C_TIMEOUT_TIME*(F_CPU/60000))/100 ) 

/* Pin states */
#define SCL_1() 	  cbi(I2C_SCL_DDR_REG, SCL_PIN)
#define SCL_0() 	  sbi(I2C_SCL_DDR_REG, SCL_PIN)
#define SDA_1() 	  cbi(I2C_SDA_DDR_REG, SDA_PIN)
#define SDA_0() 	  sbi(I2C_SDA_DDR_REG, SDA_PIN)

#define RELEASE_I2C_BUS() { SCL_1(); SDA_1(); }

/*#################################################################################################*/

static void delay(unsigned long us)
{

   while ( us ) { us--; }  /* 6 cpu cycles per loop */
 
}
/*#################################################################################################*/

void i2c_init(void)
{
	cbi(I2C_SDA_OUT_REG, SDA_PIN);
	cbi(I2C_SCL_OUT_REG, SCL_PIN);
	RELEASE_I2C_BUS();
	delay(I2C_TIMEOUT);
	i2c_start();
	delay(I2C_TIMEOUT);
	i2c_stop();
	delay(I2C_TIMEOUT);


return;
}
/*#################################################################################################*/

void i2c_start(void)
{
	RELEASE_I2C_BUS();
	delay(I2C_DELAY);
	SDA_0();
	delay(I2C_DELAY);
	SCL_0();
	delay(I2C_DELAY);

return;
}
/*#################################################################################################*/

void i2c_stop(void)
{
	SDA_0();
	SCL_1();
	delay(I2C_DELAY);
	SDA_1();
	delay(I2C_DELAY);
	SCL_0();
	delay(I2C_DELAY);

return;
}
/*#################################################################################################*/

unsigned char i2c_transmit(unsigned char data)
{
register unsigned char bit=0;

	for(bit=0; bit<=7; bit++)
	  {
	      if( data & 0x80 ) { SDA_1(); } else { SDA_0(); }
	      SCL_1();
	      delay(I2C_DELAY);
	      SCL_0();
	      delay(I2C_DELAY);
	      data = (data<<1);
	  }
	/* Look for AKNOWLEDGE */
	RELEASE_I2C_BUS();
	delay(I2C_DELAY);


	if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) )
	 {
	     SCL_0();
	     delay(I2C_DELAY);
	 }
	else{
		 delay(I2C_TIMEOUT);
		 if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) )
		  {
		     SCL_0();
		     delay(I2C_DELAY);
		  }
		 else { return(I2C_ERROR_DEVICE_NOT_RESPONDING); }
	    }


	if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) ) 
	 { 
	       delay(I2C_TIMEOUT);
	       if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) ) { return(I2C_ERROR_DEVICE_BUSY); }
	 }   


return(I2C_NO_ERROR);	  
}
/*#################################################################################################*/

unsigned char i2c_receive(unsigned char ack)
{
register unsigned char bit=0, data=0;

	SDA_1();
	for(bit=0; bit<=7; bit++)
	  {
	      SCL_1();
	      delay(I2C_DELAY);
	      data = (data<<1);
	      if( bit_is_set(I2C_SDA_PIN_REG, SDA_PIN) ) { data++; }
	      SCL_0();
	      delay(I2C_DELAY);
	  }
	
	/* if CONTINUE then send AKNOWLEDGE else if QUIT do not send AKNOWLEDGE (send Nack) */	     
	if(ack==I2C_CONTINUE) { SDA_0(); }  else { SDA_1(); }
	SCL_1();
	delay(I2C_DELAY);
	SCL_0();
	delay(I2C_DELAY);

return data;
}
/*#################################################################################################*/


