//------------------------------------------------------------------------------ // Writes a byte to I2C and checks acknowledge // returns 0 on success //------------------------------------------------------------------------------ i2cError_t i2cSoftWriteByte(uint8_t txByte) { uint8_t mask; i2cError_t err=0; for (mask = 0x80; mask > 0; mask >>= 1) //shift bit for masking (8 times) { if ((mask & txByte) == 0) { I2C_SDA_LO(); //write a bit to SDA-Line } else { I2C_SDA_HI(); } udelay(1); I2C_SCL_HI(); udelay(5); I2C_SCL_LO(); udelay(1); } I2C_SDA_IN(); //release SDA-line I2C_SCL_HI(); //clk #9 for ack udelay(5); if (I2C_SDA_GET() != 0) { err = I2C_ACK_ERROR; //check ack from i2c slave } I2C_SCL_LO(); udelay(5); //udelay(20); //delay to see the package on scope I2C_SDA_OUT(); return err; //return error code }
//------------------------------------------------------------------------------ // Reads a byte from I2C // Returns the byte received // note: timing (delay) may have to be changed for different microcontroller //------------------------------------------------------------------------------ uint8_t i2cSoftReadByte(i2cAck_t ack) { uint8_t mask, rxByte=0; I2C_SDA_IN(); //release SDA-line for (mask = 0x80; mask > 0; mask >>= 1) //shift bit for masking { I2C_SCL_HI(); //start clock on SCL-line udelay(4); if (I2C_SDA_GET() != 0) { rxByte = (rxByte | mask); //read bit } I2C_SCL_LO(); udelay(1); //data hold time } if (ack) { I2C_SDA_LO(); //send acknowledge if necessary } else { I2C_SDA_HI(); } udelay(1); I2C_SCL_HI(); //clk #9 for ack udelay(5); I2C_SCL_LO(); I2C_SDA_IN(); //release SDA-line udelay(5); //udelay(20); //delay to see the package on scope return rxByte; //return received byte }
/* * Toggles in a single byte in master mode. * * Entry: SCL low, SDA any * Exit: SCL low, SDA low with ack set, high else * * Change SDA only when SCL is low! * Sample SDA short before setting SCL low! */ static uint8_t TwGet(GPIO_TWICB* icb, uint8_t ack) { uint8_t rc = 0; int i; /* SDA is input. */ I2C_SDA_HI(); NutMicroDelay (1 * icb->delay_unit); for (i = 0x80; i; i >>= 1) { NutMicroDelay (2 * icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); while(I2C_SCL_GET() == 0) { /* Clock stretching*/ NutMicroDelay (2 * icb->delay_unit); } if (I2C_SDA_GET()) { rc |= i; } I2C_SCL_LO(); } if (ack) { /* Master sets acknowledge */ I2C_SDA_LO(); } NutMicroDelay (2 * icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); I2C_SCL_LO(); NutMicroDelay (2 * icb->delay_unit); return rc; }
//------------------------------------------------------------------------------ //Initializes the ports for I2C //------------------------------------------------------------------------------ void i2cSoftInit(void) { I2C_SDA_OUT(); I2C_SCL_OUT(); I2C_SDA_LO(); I2C_SCL_LO(); I2C_SDA_HI(); I2C_SCL_HI(); }
/* * Toggles out an acknowledge bit in master mode. * * Entry: SCL low, SDA any * Exit: SCL low, SDA high */ static void TwAck(GPIO_TWICB* icb) { I2C_SDA_LO(); NutMicroDelay (icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); I2C_SCL_LO(); NutMicroDelay (1 * icb->delay_unit); I2C_SDA_HI(); }
/* * Toggles out a single byte in master mode. * * Entry: SCL low, SDA any * Exit: SCL low, SDA high * * Change SDA only when SCL is low! * Sample SDA short before setting SCL low! */ static int TwPut(GPIO_TWICB* icb, uint8_t octet) { int i; for (i = 0x80; i; i >>= 1) { /* Set the data bit. */ if (octet & i) { I2C_SDA_HI(); } else { I2C_SDA_LO(); } /* Wait for data to stabilize. */ NutMicroDelay (2 * icb->delay_unit); /* Toggle the clock. */ I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); while(I2C_SCL_GET() == 0) { /* Clock stretching*/ NutMicroDelay (2 * icb->delay_unit); } I2C_SCL_LO(); } /* Release data line to receive the ACK bit. */ I2C_SDA_HI(); NutMicroDelay (2 * icb->delay_unit); I2C_SCL_HI(); NutMicroDelay (2 * icb->delay_unit); if (I2C_SDA_GET()) { i = -1; } else { i = 0; } I2C_SCL_LO(); NutMicroDelay (2 * icb->delay_unit); return i; }