Beispiel #1
0
// 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);
}
Beispiel #2
0
//
// 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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
//
// 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);
}
Beispiel #5
0
//
// 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);
}
Beispiel #6
0
// 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;
	}
}
Beispiel #7
0
//
// 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    
}