TI MSP430 Microcontroller I2C Bit Bang Master

I2C Master Bit Banged code from Dan Bloomquist as posted to msp430@yahoogroups.com

I2C_master.h


//I2C_Master.h

/*
use i2cm_out(...) and i2cm_in(...) between calls to i2cm_start(...) and i2cm_stop(...)

typical use(...) 
{
//this is an example of reading the config register of a DS1631
//in this case 'device' is a select number of 0000xxx0

	i2cm_start( );
	
	if( i2cm_out( 0x90 | device ) ) //send write control byte
		return;
	
	else if( i2cm_out( 0xac ) )//send config command byte
		return;
	
	i2cm_start( );//device wants start again to read
	
	if( i2cm_out( 0x91 | device ) ) //send read control byte
		return;
	
	i2cm_in( buf, 1 ); //input the config byte to 'buf'

	i2cm_stop( );
	//device was not busy or failed...
	//set sucsess flag if needed before return
	
} typical use end......

i2cm_out(...) returns true if device did not ack output byte
with mspgcc compiled for optimum code size this is about 256 bytes

*/

//Defines the port to be used
#define I2C_MASTER_REN P1REN
#define I2C_MASTER_DIR P1DIR
#define I2C_MASTER_OUT P1OUT
#define I2C_MASTER_IN  P1IN
//port pins
#define IC2_MASTER_SCL BIT2
#define I2C_MASTER_SDA BIT3

//Declarations
//sends a start condition
//will set sda and scl high and delay before start
void i2cm_start( void );

//send stop condition
//will set sda low before delay and stop
void i2cm_stop( void );

//Output one byte
//assumes sda and scl low and leaves sda, scl low if ack.
//returns true if no ack from device
unsigned char i2cm_out( register unsigned int data );

//input count of bytes into buf[ ]
//Assumes scl low and leaves scl low
//sends ack to device until last byte then no ack
void i2cm_in( unsigned char* buf, int count );


I2C_Master.C


#include  <msp430x11x1.h>
#include "I2C_master.h"

static void __inline__ brief_pause( register unsigned int n )
{
__asm__ __volatile__ (
		"1: \n"
		" dec %[n] \n"
		" jne 1b \n" : [n] "+r"(n)
		);
}

//Send data byte out on bang i2c, return false if ack
//Assumes start has been set up or a next byte
//so  both lines are assumed low
// **Lower byte of data is sent**
unsigned char i2cm_out( register unsigned int data )
{
	volatile unsigned int i= 0; //will be register
	//output eight bits of 'data'
	for( ; i < 8; ++i )
	{
		//send the data bit
		if( data & 0x80 )
			I2C_MASTER_OUT|= I2C_MASTER_SDA;
		else
			I2C_MASTER_OUT&= ~I2C_MASTER_SDA;
		
		//Set Clock High
		I2C_MASTER_OUT|= IC2_MASTER_SCL;
		
		//Set Clock Low
		brief_pause( 0x04 );
		I2C_MASTER_OUT&= ~IC2_MASTER_SCL;
		
		//shift next data bit
		data= data << 1;
	}

	I2C_MASTER_DIR&= ~I2C_MASTER_SDA;

	//Set Clock High
	I2C_MASTER_OUT|= IC2_MASTER_SCL;

	//get the ack bit and leave sda in last state
	unsigned char ack= I2C_MASTER_IN & I2C_MASTER_SDA;
	if( ack )
		I2C_MASTER_OUT|= I2C_MASTER_SDA;
	else
		I2C_MASTER_OUT&= ~I2C_MASTER_SDA;
	
	//take the pin back for output
	I2C_MASTER_DIR|= I2C_MASTER_SDA;

	//Set Clock Low
	I2C_MASTER_OUT&= ~IC2_MASTER_SCL;

	return ack;
}

//Assumes the IC2_MASTER_SCL is low
void i2cm_in( unsigned char* buf, int count )
{
	unsigned char data;
	for( ; count--; )
	{
		data= 0;
		I2C_MASTER_DIR&= ~I2C_MASTER_SDA;
		volatile unsigned int i= 0;
		for( ; i < 8; ++i )
		{
			//Set Clock High
			I2C_MASTER_OUT|= IC2_MASTER_SCL;
			
			//shift the bit over
			data= data << 1;
		
			if( I2C_MASTER_IN & I2C_MASTER_SDA )
				data|= 0x01;
			
			//Set Clock Low
			I2C_MASTER_OUT&= ~IC2_MASTER_SCL;
		}
		//put the input data byte into the buffer, inc buffer pointer
		*buf++= data;
		
		//No Ack after last byte
		if( count )
			I2C_MASTER_OUT&= ~I2C_MASTER_SDA;
		else
			I2C_MASTER_OUT|= I2C_MASTER_SDA;

		//take sda to output ack
		I2C_MASTER_DIR|= I2C_MASTER_SDA;

		//Set Clock High
		I2C_MASTER_OUT|= IC2_MASTER_SCL;
		
		//Set Clock Low
		brief_pause( 0x04 );
		I2C_MASTER_OUT&= ~IC2_MASTER_SCL;
	}
}

void i2cm_start( void )
{
	I2C_MASTER_OUT|= I2C_MASTER_SDA;
	I2C_MASTER_OUT|= IC2_MASTER_SCL;
	
    brief_pause( 0x20 );
	I2C_MASTER_OUT&= ~I2C_MASTER_SDA;
	
    brief_pause( 0x20 );
	I2C_MASTER_OUT&= ~IC2_MASTER_SCL;
}

//Assumes the clock is low
void i2cm_stop( void )
{
	I2C_MASTER_OUT&= ~I2C_MASTER_SDA;
	
    brief_pause( 0x20 );
	I2C_MASTER_OUT|= IC2_MASTER_SCL;
	
    brief_pause( 0x20 );
	I2C_MASTER_OUT|= I2C_MASTER_SDA;
}

Questions: