/* ----- file I2C_BUS.C66 ----- */ /* Use it for interfacing the devices connected to the I2C-bus */ #include "I2C_BUS.H" /****************************************************************************/ /* drive bus in inactive state, reenable eventually locked SDA-line */ void I2CInit(void) { /* re-enable SDA-line */ I2CDelay(); I2CPutSCL(0); /* preset SCL=0 to avoid accidential */ /* transmission of START condition */ /* by following SDA-transition */ I2CDelay(); I2CPutSDA(0); /* drive SDA to inactive state */ I2CDelay(); I2CPutSCL(1); /* set SCL for the first time */ I2CDelay(); I2CPutSCL(0); /* release SCL */ I2CDelay(); I2CPutSCL(1); /* set SCL for the second time */ I2CDelay(); I2CPutSCL(0); /* release SCL */ I2CDelay(); I2CPutSCL(1); /* set SCL for the third time */ /* I2C-bus is now going in the inactive state by the following commands */ I2CDelay(); I2CPutSDA(1); /* this is also the state after RESET*/ I2CDelay(); I2CPutSDA(1); /* setup SCL for START condition */ } /****************************************************************************/ /* writes a sequence of bytes to a device on I2C-bus */ /* */ /* *SourcePtr: Sourcepointer from RAM */ /* DestAddr: destination-address in I2C-device */ /* Size: length of sequence */ BYTE I2CWrite( BYTE *SourcePtr, BYTE DeviceID, BYTE DestAddr, WORD Size) { BYTE Result; I2CStart(); /* send START condition */ I2CWriteByte(DeviceID & 0xFE); /* send ID with cleared RD/WR bit */ if((Result = I2CReceiveAck()) != I2C_SUCCESSFUL) { /* is device responding ? */ I2CStop(); return(Result); } I2CWriteByte(DestAddr); /* write destination address */ if((Result = I2CReceiveAck()) != I2C_SUCCESSFUL) { I2CStop(); return(Result); } while(Size--) { /* loop until all bytes send */ I2CWriteByte(*(SourcePtr++)); if((Result = I2CReceiveAck()) != I2C_SUCCESSFUL) { I2CStop(); return(Result); } } I2CStop(); /* send STOP condition */ return(I2C_SUCCESSFUL); /* no error occured */ } /****************************************************************************/ /* reads a sequence of bytes from a device on I2C-bus */ /* */ /* *dest: destination-pointer from RAM */ /* source: source-address in I2C-device */ /* length: length of sequence */ BYTE I2CRead(BYTE *DestPtr, BYTE DeviceID, BYTE SourceAddr, WORD Size) { BYTE Result; I2CStart(); /* send START condition */ I2CWriteByte(DeviceID & 0xFE); /* send ID with cleared RD/WR bit */ if((Result = I2CReceiveAck()) != I2C_SUCCESSFUL) { /* is device responding ? */ I2CStop(); return(Result); } I2CWriteByte(SourceAddr); /* write source address */ if((Result = I2CReceiveAck()) != I2C_SUCCESSFUL) { I2CStop(); return(Result); } I2CStart(); /* send START condition */ I2CWriteByte(DeviceID | 0x01); /* send ID with set RD/WR bit */ if((Result = I2CReceiveAck()) != I2C_SUCCESSFUL) { I2CStop(); return(Result); } while(Size--) { /* loop until all data received */ *(DestPtr++) = I2CReadByte(); /* read data */ if(Size) /* send ACK to slave except last time*/ I2CSendAck(); } I2CStop(); /* send STOP condition */ return(I2C_SUCCESSFUL); /* no error occured */ } /****************************************************************************/ /* sends START condition on I2C-bus */ void I2CStart(void) { I2CDelay(); I2CPutSDA(1); /* this is also the idle bus state */ I2CDelay(); I2CPutSCL(1); /* this is also the idle bus state */ I2CDelay(); I2CPutSDA(0); /* generate START condition */ I2CDelay(); I2CPutSCL(0); /* drive SCL to inactive */ } /****************************************************************************/ /* sends STOP condition on I2C-bus */ void I2CStop(void) { I2CDelay(); I2CPutSCL(0); /* setup SCL (redundant) */ I2CDelay(); I2CPutSDA(0); /* setup SDA (redundant) */ I2CDelay(); I2CPutSCL(1); /* setup SCL for STOP condition */ I2CDelay(); I2CPutSDA(1); /* generate STOP condition */ } /****************************************************************************/ /* sends ACKNOWLEDGE condition, i.e. sends an bit-value=0 */ void I2CSendAck(void) { I2CSendBit(0); } /****************************************************************************/ /* receives ACKNOWLEDGE condition, i.e. receives an bit-value=0 */ BYTE I2CReceiveAck(void) { if (I2CReceiveBit() == 0) return(I2C_SUCCESSFUL); /* must be 0 if device responds */ else return(I2C_NO_ACKNOWLEDGE); } /****************************************************************************/ /* sends one bit to I2C-bus, also used for sending ACKNOWLEDGE condition */ void I2CSendBit(BYTE State) { I2CDelay(); I2CPutSCL(0); /* setup SCL (redundant) */ I2CDelay(); I2CPutSDA(State); /* setup SDA */ I2CDelay(); I2CPutSCL(1); /* enable SDA writing */ I2CDelay(); /* let SCL get stabilized High */ while(!I2CGetSCL()); /* wait until SCL-line is released */ I2CDelay(); I2CPutSCL(0); /* disable SDA writing (SDA is now */ /* clocked) */ I2CDelay(); I2CPutSDA(1); /* release SDA */ } /****************************************************************************/ /* receives one bit from I2C-bus, also used for receiving an ACKNOWLEDGE */ /* condition */ BYTE I2CReceiveBit(void) { BYTE State; I2CDelay(); I2CPutSCL(0); /* setup SCL (redundant) */ I2CDelay(); I2CPutSDA(1); /* setup SDA for input (TRISTATE) */ I2CDelay(); I2CPutSCL(1); /* enable SDA reading */ I2CDelay(); /* let SCL get stabilized High */ while(!I2CGetSCL()); /* wait until SCL-line is released */ I2CDelay(); State = I2CGetSDA(); /* read SDA state */ I2CPutSCL(0); /* disable SDA reading (SDA is now */ /* clocked) */ I2CDelay(); return(State); /* return state */ } /****************************************************************************/ /* sends a byte to I2C-device */ void I2CWriteByte(BYTE TransferData) { BYTE Loop; for(Loop = 0; Loop <= 7; Loop++) { I2CSendBit((TransferData & 0x80) == 0x80); TransferData = (TransferData << 1); } } /****************************************************************************/ /* reads a byte from I2C-device */ BYTE I2CReadByte(void) { BYTE Value, Loop; Value = 0; for(Loop = 0; Loop <= 7; Loop++) { Value = (Value << 1); /* 1. shift doesn't affect (value=0) */ Value = Value | I2CReceiveBit(); } return(Value); /* return byte read */ } /****************************************************************************/ /* ----- end I2C_BUS.C66 ----- */