I wish to share with everyone this my sketch for I2C debugging.
here it is:
/*
* I2CSPY - a tool for log messages on I2C bus
*
* written by Alfio - from it.hobby.elettronica
*
* This sketch is able to recognize and send over serial line,
* all bits that throw from start and stop condition on I2C bus.
* It use 2 normal digital input and not dedicated I2c pins.
* I tested it on Mega2560 and ProMini boards.
* Since it make use of direct port access for speed reason, you should change
* port and pin definitions for others board type.
*
* 2 output pins are used for debug.
* pin 13 show bus activity time, is high from start to stop condition.
* pin 12 replicate SCL pin.
*
* Output to serial port can be in Text or Binary mode, choice by TEXT_OUTPUT symbol
* Text mode is useful for simple view with Arduino IDE Serial Monitor
* Binary mode is used by my Windows program I2CSPY
* Binary mode transmit bitStream structure plus 2 control bytes
* - initial header: fized character 0x2C
* - finale checksum: negate sum of all bytes transmitted
*/
//#define TEXT_OUTPUT
#if defined(__AVR_ATmega328P__)
#define PINSCL 0x04 // bit mask for digital pin 2
#define PINSDA 0x08 // bit mask for digital pin 3 (source of interrupt)
#define PINPORT PIND // port name for input pin 2&3
#define OUT12ON() PORTB|= 0x10 // out 12 on
#define OUT12OFF() PORTB&=~0x10 // out 12 off
#define LEDON() PORTB|= 0x20 // on board led on
#define LEDOFF() PORTB&=~0x20 // on board led off
#elif defined(__AVR_ATmega2560__)
#define PINSCL 0x10 // bit mask for digital pin 2
#define PINSDA 0x20 // bit mask for digital pin 3 (source of interrupt)
#define PINPORT PINE // port name for input pin 2&3
#define OUT12ON() PORTB|= 0x40 // out 12 on
#define OUT12OFF() PORTB&=~0x40 // out 12 off
#define LEDON() PORTB|= 0x80 // on board led on
#define LEDOFF() PORTB&=~0x80 // on board led off
#else
#error "Add pin configuration for your board HERE"
#endif
#define PINMASK (PINSCL|PINSDA)
#define readPins() (PINPORT&PINMASK)
#define readSCL() (PINPORT&PINSCL)
#define readSDA() (PINPORT&PINSDA)
struct bitStream
{
byte nBuf;
byte nBits;
byte overFlow;
byte bits[18]; // use a size greater then your biggest message size = 1+total_bits/8
};
bitStream bs[64];
bitStream *bsin;
bitStream *bsout;
byte bufcnt;
void SDA_falling ( void )
{
if( readPins()!=PINSCL ) // SCL not high ? is not a start condition
return;
LEDON(); // for debug
while( readSCL() ); // wait SCL low
OUT12OFF(); // for debug
byte bsb;
byte bsm=8;
byte *bsi=bsin->bits;
bsin->nBits=0;
bsin->overFlow=0;
for( ;; )
{
byte oldpin;
do oldpin=readPins();
while( !(oldpin&PINSCL) ); // wait SCL high
OUT12ON();
if( bsi>=bsin->bits+sizeof( bsin->bits ) ) // no room in buffer
bsin->overFlow++;
else
{
bsb<<=1;
if( oldpin&PINSDA )
bsb++;
if( !--bsm )
*bsi++=bsb,bsm=8;
bsin->nBits++;
}
byte newpin;
do newpin=readPins();
while( newpin==oldpin );
if( newpin&PINSCL ) // SCL still high, so is a stop or restart
{
if( bsin->overFlow )
bsin->overFlow--;
else // remove last bit in bitstream, last rise of SCL was not a data bit
{
if( bsm<7 )
*bsi=bsb<<bsm;
bsin->nBits--;
}
bsin->nBuf=++bufcnt;
if( ++bsin>=bs+sizeof( bs )/sizeof( *bs ) )
bsin=bs;
if( newpin&PINSDA ) // is a stop condition, so return from interrupt
break;
bsm=8;
bsi=bsin->bits;
bsin->nBits=0;
bsin->overFlow=0;
while( readSCL() ); // wait SCL low, to begin another frame
}
OUT12OFF();
}
LEDOFF();
}
void setup()
{
pinMode( 2,INPUT_PULLUP );
pinMode( 3,INPUT_PULLUP );
pinMode( 12,OUTPUT ); // for debug
pinMode( 13,OUTPUT ); // for debug
bufcnt=0;
bsin=bsout=bs;
Serial.begin( 38400L );
Serial.println( "Ready" );
while( digitalRead( 3 )==LOW );
attachInterrupt( digitalPinToInterrupt( 3 ),SDA_falling,FALLING );
}
bool nothingnew ( void )
{
return bsin==bsout;
}
void loop()
{
if( nothingnew() )
return;
#if defined( TEXT_OUTPUT )
if( bsout->nBuf<16 ) Serial.print( 0 );
Serial.print( bsout->nBuf,HEX ); // frame number
Serial.print( '.' );
if( bsout->nBits<16 ) Serial.print( 0 );
Serial.print( bsout->nBits,HEX ); // total bits in buffer
Serial.print( '.' );
if( bsout->overFlow<16 ) Serial.print( 0 );
Serial.print( bsout->overFlow,HEX ); // bits lost in this frame
byte *b=bsout->bits;
for( int i=(bsout->nBits+7)/8 ; i ; i--,b++ )
{
Serial.print( '.' );
if( *b<16 ) Serial.print( 0 );
Serial.print( *b,HEX );
}
Serial.println();
#else
byte cs=0x2C; // checksum
Serial.write( 0x2C ); // header
cs+=bsout->nBuf;
Serial.write( bsout->nBuf ); // frame number
cs+=bsout->nBits;
Serial.write( bsout->nBits ); // total bits in buffer
cs+=bsout->overFlow;
Serial.write( bsout->overFlow ); // bits lost in this frame
byte*bsend=bsout->bits+(bsout->nBits+7)/8;
for( byte*p=bsout->bits ; p<bsend ; p++ )
{
cs+=*p;
Serial.write( *p ); // bitstream
}
Serial.write( -cs ); // checksum
#endif
if( ++bsout>=bs+sizeof( bs )/sizeof( *bs ) )
bsout=bs;
}
It can works as standalone sketch by write result to serial line in text format, or can work with my Windows program, in this case the output is in binary format.
