I2C Multiple Devices

Hello,

What would be the recommended way to have multiple devices reading and writing on the bus? More specifically how would you go about handling errors?

Here is some example code. Registers and parameters are not provided to focus on the use case of the i2c driver.

// Presuming all devices are setup prior to sampling. Additionally that both devices are on the same i2c bus.
function getA() {
    local wErr = i2c.write();
    if (err) {
        server.error(format("error writing to device A: %d", wErr));
        imp.wakeup(0.01, getA);
        return;
    }

    local rData = i2c.read();
    if (!rData) {
        local rErr = i2c.readerror();
        server.error(format("error reading to device A: %d", rErr));
        imp.wakeup(0.01, getA);
        return;
    }

    // do something with rData
    imp.wakeup(0.01, getA);
    return;
}

function getB() {
    local wErr = i2c.write();
    if (err) {
        server.error(format("error writing to device B: %d", wErr));
        imp.wakeup(0.01, getB);
        return;
    }

    local rData = i2c.read();
    if (!rData) {
        local rErr = i2c.readerror();
        server.error(format("error reading to device B: %d", rErr));
        imp.wakeup(0.01, getB);
        return;
    }

    // do something with rData
    imp.wakeup(0.01, getB);
    return;
}

getA();
getB();

I2C uses device addresses, so it’s easy to have multiple devices on the bus. You just target each one by address. The read() and write() calls each take a device address as a parameter, so you know which device any subsequent error relates to.

Each device listens for its own address and should only respond to message when it is being addressed. This is the great thing about I2C. So long as each part has a unique address they can all live in harmony.

The only thing to be aware of is with SMB compliant devices like smart batteries or chargers. The SMB standard has a timeout parameter for a transaction. I2C does not. Sometimes you can have a SMB device misbehave and lock up the bus, if you paused during a read of data from another device, and you wait too long the SMB devices thinks the conversation has timed out . So it waits for a new conversation to start. If the next byte being send it it’s address it can hold down the bus waiting for more data that might never arrive.

So there is no collision possible using the Electric Imp I2C driver where a clock could be held in a busy state, whilst another message is trying to be transmitted to/from another device?

No collision is possible. I2C inherently has just one controlling node (able to drive the clock and start transactions) and all other nodes are controlled, and cannot start their own transactions or drive the clock line. In Electric Imp I2C, the imp itself is always the controlling node. And because the entire provided API is synchronous (the call does not return until the transaction completes), there can never be any bus contention.

Some I2C devices might have a separate interrupt line for informing the imp when they might profitably be polled, but only the imp can ever initiate the actual I2C protocol.

Peter