Skip to content

Multi Master Considerations

chuck todd edited this page Mar 15, 2018 · 1 revision

MultiMaster

Given a situation where two I2C Master devices are controlling one Slave device, for Example a 24LC512 (64kB EEPROM), The low lever I2c Bus arbitration feature will correctly allocate bus control base on nonvolatile rules. But, the App level code must be correctly structured to politely handed these brusk accessess denials. The following code illustrates one synerio, Master A writing a 32bit integer value to 0xFE. Since the 24LC512 uses a 128byte write buffer and a four byte value starting at 0xFE has two bytes on page 0x80..0xFF and the two bytes on page 0x100..0x17F. This operation requires two distinct Write operations:

uint8_t err = 0;
uint16_t addr = 0xff;
uint32_t value = random(0,ULON_MAX);
uint32_t failCount=0;
uint32_t successCount=0;
delayMicroseconds(value % 41); // put some variability into the execution time
while(failCount<500){
  do{
    Wire.beginTransmission(id); 
    Wire.write(highByte(addr)); // highbyte of address
    Wire.write(lowByte(addr)); // low byte of address;
    Wire.write((value>>24)&0xFF);
    Wire.write((value>>16)&0xFF);
    err=Wire.endTransmission(true); // send stop must be true to post write
    }while(err!=0); // keep trying until successfully writes high byte

  do{
    Wire.beginTransmission(id); 
    Wire.write(highByte(addr+2)); // highbyte of address
    Wire.write(lowByte(addr+2)); // low byte of address;
    Wire.write((value>>8)&0xff);
    Wire.write(value&0xff);
    Wire.endTransmission(true); // send stop must be true to post write
    }while(err!=0);

  do{
    err=Wire.requestFrom(id,4,true);
    if(err==4){
      uint32_t testValue=Wire.read();
      testValue *= 256;
      testValue += Wire.read();
      testValue *= 256;
      testValue += Wire.read();
      testValue *= 256;
      testValue += Wire.read();
      if(testValue==value) successCount++;
      else failCount++;
      }
    }while(err!=4);
  }

Serial.printf(" Successfully stored %d, failed %d\n",successCount,failCount);

Running this code on two simultanious Master devices will result in a unpredictable number of fails. With my current library, it would produce even more problems, because my code assumes any bus_busy conditions (other master has control of the bus) as a hardware fault, not a valid bus status. My current library will attempt to clear the hardware fault, when actually it would cause a hardware/arbitration fault by manually stimulating the bus while it attempts to clear the 'fault'. This manual stimulation would be intrepreted by the 'owning' master as an Arbitration loss. Then it would exit it's transmisison, retry, detect a bus_busy, LOOP foreEVER.

How do you determine a Valid arbitration loss, bus_busy from a hardware fault bus_Busy?

Chuck.