// // Send a START Condition // // The SDA and SCL should already be high. // // The SDA and SCL will both be low after this function. // When writing the address, the Master makes them high. // // Return value: // true : software i2c bus is okay. // false : failed, some kind of hardware bus error. // boolean SoftwareWire::i2c_start(void) { i2c_sda_hi(); // can perhaps be removed some day ? if the rest of the code is okay i2c_scl_hi(); // can perhaps be removed some day ? if the rest of the code is okay if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); // Both the sda and scl should be high. // If not, there might be a hardware problem with the i2c bus signal lines. // This check was added to prevent that a shortcut of sda would be seen as a valid ACK // from a i2c Slave. uint8_t sda_status = i2c_sda_read(); uint8_t scl_status = i2c_scl_read(); if(sda_status == 0 || scl_status == 0) { return(false); } else { i2c_sda_lo(); if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); i2c_scl_lo(); if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); } return(true); }
// Send a STOP Condition // void SoftwareWire::i2c_stop(void) { i2c_sda_lo(); i2c_scl_hi(); // Check if clock stretching by the Slave should be detected. if( _stretch) { // Wait until the clock is high, the Slave could keep it low for clock stretching. // Clock pulse stretching during a stop condition seems odd, but when // the Slave is an Arduino, it might happen. unsigned long prevMillis = millis(); while( i2c_scl_read() == 0) { if( millis() - prevMillis >= _timeout) break; }; } if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); i2c_sda_hi(); // A delay after the STOP for safety. // It is not known how fast the next START will happen. if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); }
uint8_t SoftwareWire::i2c_readbit(void) { i2c_sda_hi(); // 'hi' is the same as releasing the line i2c_scl_hi(); // Check if clock stretching by the Slave should be detected. if( _stretch) { // Wait until the clock is high, the Slave could keep it low for clock stretching. unsigned long prevMillis = millis(); while( i2c_scl_read() == 0) { if( millis() - prevMillis >= _timeout) break; }; } // After the clock stretching, this delay has still be done before reading sda. if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); uint8_t c = i2c_sda_read(); i2c_scl_lo(); if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); return(c); }
// Send a STOP Condition // void SoftI2CMaster::i2c_stop(void) { i2c_scl_hi(); _delay_us(i2cbitdelay); i2c_sda_hi(); _delay_us(i2cbitdelay); }
// Inits bitbanging port, must be called before using the functions below // void SoftI2CMaster::i2c_init(void) { //I2C_PORT &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); //*_sclPortReg &=~ (_sdaBitMask | _sclBitMask); i2c_sda_hi(); i2c_scl_hi(); _delay_us(i2cbitdelay); }
// // Release the pins of the Software I2C bus for other use. // Also the internal pullup resistors are removed. // void SoftwareWire::end() { // Remember the pullups variable. // They will be used again when begin() is called. boolean pullupsCopy = _pullups; _pullups = false; i2c_sda_hi(); // release sda, remove any pullup i2c_scl_hi(); // release scl, remove any pullup _pullups = pullupsCopy; }
uint8_t SoftI2CMaster::i2c_readbit(void) { i2c_sda_hi(); i2c_scl_hi(); _delay_us(i2cbitdelay); uint8_t port = digitalPinToPort(_sdaPin); volatile uint8_t* pinReg = portInputRegister(port); uint8_t c = *pinReg; // I2C_PIN; i2c_scl_lo(); _delay_us(i2cbitdelay); return ( c & _sdaBitMask) ? 1 : 0; }
// // Initializes the Software I2C. // // The original i2c_init sets the SDA and SCL high at the same time. // // The code has been changed, since the first data to the software i2c did fail sometimes. // Changed into SCL high first, with a delay. // That would send a STOP if the SDA happens to be low. // Any Slave that was busy, will detect the STOP. // // After both lines are high, the delay is changed into 4 times the normal delay. // That did reduce the error with the first tranmission. // It was tested with Arduino Uno with clock of 100kHz (_i2cdelay=2). // void SoftwareWire::i2c_init(void) { i2c_scl_hi(); if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); i2c_sda_hi(); for( uint8_t i=0; i<4; i++) // 4 times the normal delay, to claim the bus. { if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); } }
// Send a START Condition // void SoftI2CMaster::i2c_start(void) { // set both to high at the same time //I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); //*_sclDirReg &=~ (_sdaBitMask | _sclBitMask); i2c_sda_hi(); i2c_scl_hi(); _delay_us(i2cbitdelay); i2c_sda_lo(); _delay_us(i2cbitdelay); i2c_scl_lo(); _delay_us(i2cbitdelay); }
void SoftI2CMaster::i2c_writebit( uint8_t c ) { if ( c > 0 ) { i2c_sda_hi(); } else { i2c_sda_lo(); } i2c_scl_hi(); _delay_us(i2cbitdelay); i2c_scl_lo(); _delay_us(i2cbitdelay); if ( c > 0 ) { i2c_sda_lo(); } _delay_us(i2cbitdelay); }
void SoftI2CMaster::i2c_repstart(void) { // set both to high at the same time (releases drive on both lines) //I2C_DDR &=~ (_BV( I2C_SDA ) | _BV( I2C_SCL )); //*_sclDirReg &=~ (_sdaBitMask | _sclBitMask); i2c_sda_hi(); i2c_scl_hi(); i2c_scl_lo(); // force SCL low _delay_us(i2cbitdelay); i2c_sda_release(); // release SDA _delay_us(i2cbitdelay); i2c_scl_release(); // release SCL _delay_us(i2cbitdelay); i2c_sda_lo(); // force SDA low _delay_us(i2cbitdelay); }
// // The i2c_writebit and i2c_readbit could be make "inline", but that // didn't increase the speed, and the code size increases. // // The sda is low after the start condition. // Therefor the sda is low for the first bit. // void SoftwareWire::i2c_writebit(uint8_t c) { if(c==0) { i2c_sda_lo(); } else { i2c_sda_hi(); } if (_i2cdelay != 0) // This delay is not needed, but it makes it safer delayMicroseconds(_i2cdelay); // This delay is not needed, but it makes it safer i2c_scl_hi(); // clock high: the Slave will read the sda signal // Check if clock stretching by the Slave should be detected. if( _stretch) { // If the Slave was strechting the clock pulse, the clock would not go high immediately. // For example if the Slave is an Arduino, that has other interrupts running (for example Serial data). unsigned long prevMillis = millis(); while( i2c_scl_read() == 0) { if( millis() - prevMillis >= _timeout) break; }; } // After the clock stretching, the clock must be high for the normal duration. // That is why this delay has still to be done. if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); i2c_scl_lo(); if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); }
// // Repeated START instead of a STOP // // TODO: check if the repeated start actually works. // void SoftwareWire::i2c_repstart(void) { i2c_sda_hi(); // i2c_scl_hi(); // ?????? i2c_scl_lo(); // force SCL low if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); i2c_sda_hi(); // release SDA if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); i2c_scl_hi(); // release SCL // Check if clock stretching by the Slave should be detected. if( _stretch) { // If the Slave was strechting the clock pulse, the clock would not go high immediately. // For example if the Slave is an Arduino, that has other interrupts running (for example Serial data). unsigned long prevMillis = millis(); while( i2c_scl_read() == 0) { if( millis() - prevMillis >= _timeout) break; }; } if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); i2c_sda_lo(); // force SDA low if (_i2cdelay != 0) delayMicroseconds(_i2cdelay); }