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???