// 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); }
// // 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); }
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); }
// // 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); }
// Interrupt service routine to handle the compass communications void __ISR_COMPASS_I2C(void) // Called at 24896Hz { // I2C clock stretching if(i2c_scl_read() != g_i2c_scl_cmd) return; // Step the low level FSM i2c_step(); // Retrieve the current high level FSM command const struct Command* cmd = &g_script[current_entry]; // Perform the required action for the command switch(cmd->type) { // Signal a start condition case CMD_START: if(g_i2c_state == I2C_IDLE) i2c_start(); else if(g_i2c_state == I2C_READY) current_entry++; break; // Write a byte of data case CMD_WRITE: switch(g_i2c_state) { case I2C_READY: i2c_write(cmd->data); break; case I2C_WRITE_GOT_ACK: g_i2c_state = I2C_READY; current_entry++; break; case I2C_WRITE_GOT_NACK: g_i2c_state = I2C_READY; current_entry++; break; default: break; } break; // Read a byte of data case CMD_READ: switch(g_i2c_state) { case I2C_READY: i2c_read(); break; case I2C_READ_ENDED: read_data[cmd->data] = g_i2c_read; g_i2c_state = I2C_READY; current_entry++; break; default: break; } break; // Signal a stop condition case CMD_STOP: if(g_i2c_state == I2C_READY) i2c_stop(); else if(g_i2c_state == I2C_IDLE) current_entry++; break; // Process the last read data and loop back to a particular command (zero-based index in g_script) case CMD_LOOP: ProcessData(); current_entry = cmd->data; break; // Wait some time case CMD_WAIT: if(wait_counter == 0) wait_counter = cmd->data; else if(wait_counter == 1) { wait_counter = 0; current_entry++; } else wait_counter--; break; // Should never happen 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 }