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 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); }
// Perform one step of the I2C FSM static void i2c_step(void) { switch(g_i2c_state) { // Idle states case I2C_IDLE: // Idle bus with SCL and SDA high break; case I2C_READY: // Bus ready for activity with SCL and SDA low break; // Start states case I2C_START: i2c_init(); // Sets SDA and SCL to 1 g_i2c_state = I2C_START_2; break; case I2C_START_2: i2c_sda(0); // SDA falling while SCL 1 => Start bit g_i2c_state = I2C_START_3; break; case I2C_START_3: i2c_scl(0); // Now SDA and SCL are both 0, ready for bus activity g_i2c_state = I2C_READY; break; // Write states case I2C_WRITE: i2c_sda(g_i2c_to_write & (1 << g_i2c_bit)); // SDA reflects data bit g_i2c_state = I2C_WRITE_2; break; case I2C_WRITE_2: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_WRITE_3; break; case I2C_WRITE_3: i2c_scl(0); // Toggle SCL low if(g_i2c_bit == 0) g_i2c_state = I2C_WRITE_ACK_1; else { g_i2c_bit--; g_i2c_state = I2C_WRITE; } break; case I2C_WRITE_ACK_1: i2c_sda(1); // Release SDA to allow the slave to ACK or NACK g_i2c_state = I2C_WRITE_ACK_2; break; case I2C_WRITE_ACK_2: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_WRITE_ACK_3; break; case I2C_WRITE_ACK_3: if(i2c_sda_read()) // Read the acknowledgement bit g_i2c_state = I2C_WRITE_GOT_NACK; else g_i2c_state = I2C_WRITE_GOT_ACK; i2c_scl(0); // Toggle SCL low break; case I2C_WRITE_GOT_ACK: break; case I2C_WRITE_GOT_NACK: break; // Read states case I2C_READ: i2c_sda(1); // Release SDA to allow the slave to transmit data g_i2c_state = I2C_READ_2; break; case I2C_READ_2: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_READ_3; break; case I2C_READ_3: if(i2c_sda_read()) g_i2c_read |= (1 << g_i2c_bit); i2c_scl(0); // Toggle SCL low if(g_i2c_bit == 0) g_i2c_state = I2C_READ_4; else { g_i2c_bit--; g_i2c_state = I2C_READ_2; } break; case I2C_READ_4: i2c_sda(0); // Reassert control over SDA again and pull it low for an ACK g_i2c_state = I2C_READ_ACK_1; break; case I2C_READ_ACK_1: i2c_scl(1); // Toggle SCL high g_i2c_state = I2C_READ_ACK_2; break; case I2C_READ_ACK_2: i2c_scl(0); // Toggle SCL low g_i2c_state = I2C_READ_ENDED; break; case I2C_READ_ENDED: break; // Stop states case I2C_STOP: i2c_sda(0); g_i2c_state = I2C_STOP_2; break; case I2C_STOP_2: i2c_scl(1); g_i2c_state = I2C_STOP_3; break; case I2C_STOP_3: i2c_sda(1); g_i2c_state = I2C_IDLE; break; // Default state default: break; } }
// // printStatus // ----------- // Print information to the Serial port // Used during developing and debugging. // Call it with the Serial port as parameter: // myWire.printStatus(Serial); // This function is not compatible with the Wire library. // When this function is not called, it does not use any memory. // void SoftwareWire::printStatus( HardwareSerial& Ser) { Ser.println(F("-------------------")); Ser.println(F("SoftwareWire Status")); Ser.println(F("-------------------")); Ser.print(F(" F_CPU = ")); Ser.println(F_CPU); Ser.print(F(" sizeof(SoftwareWire) = ")); Ser.println(sizeof(SoftwareWire)); Ser.print(F(" _transmission status = ")); Ser.println(_transmission); Ser.print(F(" _i2cdelay = ")); Ser.print(_i2cdelay); if( _i2cdelay == 0) Ser.print(F(" (free running)")); Ser.println(); Ser.print(F(" _pullups = ")); Ser.print(_pullups); if( _pullups) Ser.print(F(" (enabled)")); Ser.println(); Ser.print(F(" _timeout = ")); Ser.print(_timeout); Ser.println(F(" ms")); Ser.print(F(" SOFTWAREWIRE_BUFSIZE = ")); Ser.println(SOFTWAREWIRE_BUFSIZE); Ser.print(F(" rxBufPut = ")); Ser.println(rxBufPut); Ser.print(F(" rxBufGet = ")); Ser.println(rxBufGet); Ser.print(F(" available() = ")); Ser.println(available()); Ser.print(F(" rxBuf (hex) = ")); for(int ii=0; ii<SOFTWAREWIRE_BUFSIZE; ii++) { if(rxBuf[ii] < 16) Ser.print(F("0")); Ser.print(rxBuf[ii],HEX); Ser.print(F(" ")); } Ser.println(); Ser.print(F(" _sdaPin = ")); Ser.println(_sdaPin); Ser.print(F(" _sclPin = ")); Ser.println(_sclPin); Ser.print(F(" _sdaBitMast = 0x")); Ser.println(_sdaBitMask, HEX); Ser.print(F(" _sclBitMast = 0x")); Ser.println(_sclBitMask, HEX); Ser.print(F(" _sdaPortReg = ")); Ser.println( (uint16_t) _sdaPortReg, HEX); Ser.print(F(" _sclPortReg = ")); Ser.println( (uint16_t) _sclPortReg, HEX); Ser.print(F(" _sdaDirReg = ")); Ser.println( (uint16_t) _sdaDirReg, HEX); Ser.print(F(" _sclDirReg = ")); Ser.println( (uint16_t) _sclDirReg, HEX); Ser.print(F(" _sdaPinReg = ")); Ser.println( (uint16_t) _sdaPinReg, HEX); Ser.print(F(" _sclPinReg = ")); Ser.println( (uint16_t) _sclPinReg, HEX); Ser.print(F(" line state sda = ")); Ser.println(i2c_sda_read()); Ser.print(F(" line state scl = ")); Ser.println(i2c_scl_read()); #ifdef ENABLE_I2C_SCANNER // i2c_scanner // Taken from : http://playground.arduino.cc/Main/I2cScanner // At April 2015, it was version 5 Ser.println("\n I2C Scanner"); byte error, address; int nDevices; Ser.println(" Scanning..."); nDevices = 0; for(address=1; address<127; address++ ) { // The i2c_scanner uses the return value of // the Write.endTransmisstion to see if // a device did acknowledge to the address. beginTransmission(address); error = endTransmission(); if (error == 0) { Ser.print(" I2C device found at address 0x"); if (address<16) Ser.print("0"); Ser.print(address,HEX); Ser.println(" !"); nDevices++; } else if (error==4) { Ser.print(" Unknow error at address 0x"); if (address<16) Ser.print("0"); Ser.println(address,HEX); } } if (nDevices == 0) Ser.println(" No I2C devices found\n"); else Ser.println(" done\n"); #endif }