[I2C] Yet another I2C logging program

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.

Please put this and the source of the Windows application on Github.
I asked a moderator to remove your other post, because a Windows executable from unknow source is not something I would run on my computer.
Can you also fix the it.hobby.elettronica that link does not exist.

Koepel:
I asked a moderator to remove your other post, because a Windows executable from unknow source is not something I would run on my computer.
Can you also fix the it.hobby.elettronica that link does not exist.

very pittoresque :slight_smile:

the executable i attached to my previous message can't run on your computer if you don't do it expressly, or do you think this forum has some kind of autostart for attached programs ?

it.hobby.elettronica is a correct name for a Newsgroup, do you know usenet ?

alfionet:
do you know usenet ?

Yes, that was something that was popular between 1980 and 1993. Are you a time traveler ?

Koepel:
Yes, that was something that was popular between 1980 and 1993. Are you a time traveler ?

:slight_smile:
no, but just old enough.
usenet is still alive in 2020