I2C driver using bit bang

Sathyanarayana Hadadi March 24, 20138 comments Coded in C

I2C driver using bit bang. This can be used with any microcontroller which has 2 GPIO lines which can be configured as input/output

typedef struct 
{
  unsigned int PIN0:1;
  unsigned int PIN1:1;
  unsigned int PIN2:1;
  unsigned int PIN3:1;
  unsigned int PIN4:1;
  unsigned int PIN5:1;
  unsigned int PIN6:1;
  unsigned int PIN7:1;
} PORT;

/* TODO: Example address shown, but the proper address */
#define PORT0 *(volatile PORT *)0x1234

/* Define the port used for I2C data and clk as shown above to access them pin wise */
#define I2C_DATA PORT0.PIN0
#define I2C_CLK  PORT0.PIN1

#define HIGH 1
#define LOW  0

/* I2C Start - bit bang */
void I2C_START(void)
{
    /* I2C Start condition, data line goes low when clock is high */
    I2C_DATA = HIGH;
    I2C_CLK = HIGH;
    I2C_DATA = LOW;
    I2C_CLK = LOW;
}

/* I2C Stop - bit bang */
void I2C_STOP (void)
{
    /* I2C Stop condition, clock goes high when data is low */
    I2C_CLK = LOW;
    I2C_DATA = LOW;
    I2C_CLK = HIGH;
    I2C_DATA = HIGH;
}

/* I2C Write - bit bang */
void I2C_WRITE(unsigned char data)
{
	unsigned char outBits;
	unsigned char inBit;
	
 	/* 8 bits */
	for(outBits = 0; outBits < 8; outBits++) 
	{
	    if(data & 0x80)
		    I2C_DATA = 1;
		else
		    I2C_DATA = 0;
      	data  <<= 1;
		/* Generate clock for 8 data bits */
		SCLK = HIGH;
		SCLK = LOW;					
	}
	
	/* Generate clock for ACK */
	I2C_CLK = HIGH;
        /* Wait for clock to go high, clock stretching */
        while(I2C_CLK);
        /* Clock high, valid ACK */
	inBit = I2C_DATA;
	I2C_CLK = LOW;					
}

unsigned char I2C_READ (void)
{
	unsigned char inData, inBits;

	inData = 0x00;
	/* 8 bits */
	for(inBits = 0; inBits < 8; inBits++)
	{
		inData <<= 1;
		I2C_CLK = HIGH;
      	inData |= I2C_DATA;
		I2C_CLK = LOW;					
	}

   return inData;
}

/* Examble for writing to I2C Slave */
void writeI2CSlave (unsigned char data)	
{
    /* Start */
  	I2C_START();
	/* Slave address */
   	I2C_WRITE(0xAA)
	/* Slave control byte */
   	I2C_WRITE(0xBB);
	/* Slave data */
   	I2C_WRITE(data);
	/* Stop */
   	I2C_STOP();
}

/* Examble for reading from I2C Slave */
unsigned char readI2CSlave(unsigned char data)
{
   	unsigned char inData;

	/* Start */
  	I2C_START(); 
	/* Slave address */
   	I2C_WRITE(0xAA);
	/* Slave control byte */
   	I2C_WRITE(data);
	/* Stop */
   	I2C_STOP();
	
	/* Start */
   	I2C_START();
	/* Slave address + read */
   	I2C_WRITE(0xAA | 1);
	/* Read */
	inData = I2C_READ();

   	return inData;                 
}