// // 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); }
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 soft_i2c_init(void){ // input with pull-up in input mode, push/pull in output mode GPIOA->CR1 = 0x06; // interrupts disabled in input mode, output at 2MHz in output mode GPIOA->CR2 = 0x00; i2c_sda_lo(); i2c_sclk_hi(); i2c_bit_delay(); started = 0; }
void soft_i2c_stop(void){ i2c_sda_lo(); i2c_bit_delay(); while(soft_i2c_read_sclk() == 0){ // add timeout } i2c_bit_delay(); if(soft_i2c_read_sda() == 0){ // arbitration lost return; } i2c_bit_delay(); started = 0; }
// 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 soft_i2c_writebit(uint8_t bit){ if(bit){ i2c_sda_hi(); } else { i2c_sda_lo(); } i2c_bit_delay(); while(soft_i2c_read_sclk() == 0){ // add timeout } if(bit && soft_i2c_read_sda() == 0){ // arbitration lost return; } i2c_bit_delay(); i2c_sclk_lo(); }
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); }