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:
static void __inline__ brief_pause( register unsigned int n )James Newton of MassMind replies: That actually depends on the speed of the processor clock. This code is less than ideal because it does not tie the delay to the clock or to the allowed speed of the I2C interface. The value used when calling "brief_pause" will need to be adjusted by hand to compensate and provide the correct timing. Again, this code should only be used when there is no other alternative: The built in I2C provided by the chip is much preferred.
{
__asm__ __volatile__ (
"1: \n"
" dec %[n] \n"
" jne 1b \n" : [n] "+r"(n)
);
}
i want to know how much delay this function produce and how???