#ifndef __I2CSIG_C #define __I2CSIG_C #include "i2csig.h" void i2csig_init() { I2CSIG_SCL_HI; //internal pullups also activ ??????? I2CSIG_SDA_HI; //internal pullups also activ ??????? sbi( SCLSIGDIRPORT, SCLSIG); // set SCLSIG as output sbi( SDASIGDIRPORT, SDASIG); // set SDASIG as output I2CSIG_SCL_HI; I2CSIG_SDA_HI; } #define I2CSIG_START { I2CSIG_SDA_LO; \ I2CSIGQDEL; \ I2CSIG_SCL_LO; \ } #define I2CSIG_STOP { I2CSIG_SDA_LO; \ NOP; \ I2CSIGQDEL; \ I2CSIG_SCL_HI; \ I2CSIGQDEL; \ I2CSIG_SDA_HI; \ I2CSIGQDEL; \ } BYTE _i2csig_putbyte(BYTE val) { int i; BYTE ack,b; //first sending address of device //bit-data is set on middle of low-clock-period b = val; for (i=7;i>=0;i--) { I2CSIGQDEL; if ( b & (1<<i) ){ I2CSIG_SDA_HI; } else { I2CSIG_SDA_LO; } I2CSIGQDEL; //complete high-clock-period, where receiver can //read data I2CSIG_SCL_HI; I2CSIGQDEL; I2CSIGQDEL; I2CSIG_SCL_LO; } //the nineth clock for getting the acknowledge I2CSIGQDEL; I2CSIG_SDA_HI; // set sda high ( enable pullups ) cbi(SDASIGDIRPORT, SDASIG); // change direction to input on SDASIG line I2CSIGQDEL; //a complete clock for receiver to set its stuff I2CSIG_SCL_HI; I2CSIGQDEL; I2CSIGQDEL; //we read it at end of clock, so receiver have a lot of time ack = inp(SDASIGREADPORT) & (1<<SDASIG); // get the ACK bit NOP; I2CSIG_SCL_LO; I2CSIGQDEL; sbi(SDASIGDIRPORT, SDASIG); // change direction back to output NOP; return (ack); // return ACK value } /* Send a byte sequence on the I2CSIG line */ BYTE i2csig_send(BYTE dev, BYTE sub, WORD length, BYTE *data) { //start sequence //we avoid a high scl for min. QDEL time before //and a high SDA line I2CSIG_START; if( _i2csig_putbyte(dev & 0x0fe) != 0 ){ //we set a stop condition, also if an error I2CSIG_STOP; return( I2C_NO_ACKNOWLEDGE ); } if(_i2csig_putbyte(sub) != 0){ I2CSIG_STOP; return( I2C_NO_ACKNOWLEDGE ); } // send the data while (length--){ if( _i2csig_putbyte(*data++) != 0 ){ I2CSIG_STOP; return( I2C_NO_ACKNOWLEDGE ); } } I2CSIG_STOP; return( I2C_SUCCESSFUL ); } /* Retrieve a byte sequence on the I2CSIG line */ BYTE i2csig_receive(BYTE dev, BYTE sub, WORD length, BYTE *data) { int i; BYTE c,b = 0; WORD j = 0; BYTE *p = data; //start sequence //we avoid a high scl for min. QDEL time before //and a high SDA line I2CSIG_START; //deviceid if( _i2csig_putbyte(dev & 0x0fe) != 0 ){ //we set a stop condition, also if an error I2CSIG_STOP; return( I2C_NO_ACKNOWLEDGE ); } //sending slave address with cleared read-flag if( _i2csig_putbyte(sub) != 0 ){ I2CSIG_STOP; return( I2C_NO_ACKNOWLEDGE ); } //Here we have to start the reading sequence //At this time SCL is low since a quarter low-period //SDA is output //first we have to do a startcondition again I2CSIG_SDA_HI; I2CSIGQDEL; //fullfill low-period I2CSIG_SCL_HI; I2CSIGQDEL; //new start I2CSIG_START; //sending device-address with set read-flag if( _i2csig_putbyte(dev | 1) != 0 ){ I2CSIG_STOP; return( I2C_NO_ACKNOWLEDGE ); } //now we can read the data //At this time SCL is low since a quarter low-period //SDA is output //first we set it to input I2CSIG_SDA_HI; // set sda high ( enable pullups ) cbi(SDASIGDIRPORT, SDASIG); // change direction to input on SDASIG line // receive data bytes while (j < length){ //reading bits per byte b = 0; for (i=7;i>=0;i--) { I2CSIGQDEL; I2CSIG_SCL_HI; I2CSIGQDEL; I2CSIGQDEL; //we read bit at end of high-clock-period c = inp(SDASIGREADPORT) & (1<<SDASIG); b <<= 1; if (c){ b |= 1; } I2CSIG_SCL_LO; I2CSIGQDEL; } //first storing received byte *p = b; p++; j++; //at this time SCL is low since a quarter period //now handling the ack-bit //for the last byte we have to set a nak ( high ) //for all other an ack ( low ) sbi(SDASIGDIRPORT, SDASIG); // change direction to output on SDASIG line NOP; if( j < length ){ I2CSIG_SDA_LO;//ack I2CSIGQDEL; I2CSIG_SCL_HI; I2CSIGQDEL; I2CSIGQDEL; I2CSIG_SCL_LO; I2CSIGQDEL; cbi(SDASIGDIRPORT, SDASIG); // change direction to input on SDASIG line NOP; } else { I2CSIG_SDA_HI;//nak I2CSIGQDEL; I2CSIG_SCL_HI; I2CSIGQDEL; I2CSIGQDEL; I2CSIG_SCL_LO; I2CSIGQDEL; } } //here we should have SDA set to output, //and SCL low since a quarter-clock-period //and the nak for the last received byte is //send before I2CSIG_STOP; return( I2C_SUCCESSFUL ); } #endif