Help! How to setup a multi-master I2C?

human890209
Posts: 54
Joined: Wed Aug 15, 2018 8:56 am

Help! How to setup a multi-master I2C?

Postby human890209 » Thu Sep 06, 2018 2:51 am

Hi,
I tested my I2C code on ESP32, some wired things happen. And I checked the TwoWire library and got confused with the sendStop argument.

I guess the sendStop can only be set to TRUE or the message won't be received or sent.
I noticed ESP32 I2C used a queue system.
I used Arduino boards and ESP8266 Arduino, the sendStop argument is not functioning that way.

sendStop does not affect data sending or receiving. I treat it like a choice of hold or hang the phone after the conversation. If you hang your phone then other masters could make a phone call to a slave device. I2C is a multi-master system, which makes sendStop vital.

I used to do this before write/read the I2C

Code: Select all

beginTransmission((uint8_t)address);
result = endTransmission(false);
If the result is 0, then I can perform the action, and I2C bus is occupied by the current master. if not, I could try again later, cause the line is busy now, some other master is using the bus.
And the master only "hang up the phone" at the last request/transmission.

But I2C for ESP32 Arduino is different. Hope someone could provide some practical instructions about multi-master I2C.

I noticed this
Wire.busy() be added. this bool function returns the hardware status of the bus. This status can be use in multi-master environments for application level interleaving of commands, also in single master environment, it can be used to detect a 'hung' bus. With the functional change to Wire.begin() this allows app level recover of a hung bus.
I guess should check Wire.busy() before the final

Code: Select all

Wire.endTransmission();
Wire.requestFrom(len, true);
which not set the sendStop to false.

But is that 100% safe? Is the queued I2C actions an airtight sequence that other master can't cut in?
----edit-----
https://github.com/stickbreaker/arduino ... e3f28ad174
I read the instructions by Chuck. I guess the queued I2C can't be broken by another I2C master. It's cool.


And is there 100% no chance for other master get in between Wire.busy() and the final request/transmission? (Of cause, ISR should be blocked...)

I read this:

Code: Select all

i2c_err_t i2cWrite(i2c_t * i2c, uint16_t address, uint8_t* buff, uint16_t size, bool sendStop, uint16_t timeOutMillis){
    i2c_err_t last_error = i2cAddQueueWrite(i2c, address, buff, size, sendStop, NULL);

    if(last_error == I2C_ERROR_OK) { //queued
        if(sendStop) { //now actually process the queued commands, including READs
            last_error = i2cProcQueue(i2c, NULL, timeOutMillis);
            if(last_error == I2C_ERROR_BUSY) { // try to clear the bus
                if(i2cInit(i2c->num, i2c->sda, i2c->scl, 0)) {
                    last_error = i2cProcQueue(i2c, NULL, timeOutMillis);
                }
            }
            i2cFlush(i2c);
        } else { // stop not received, so wait for I2C stop,
            last_error = I2C_ERROR_CONTINUE;
        }
    }
    return last_error;
If I call endTransmission(true), and another master is occupying the bus. Than this master will get I2C_ERROR_BUSY, and do i2cInit() and retry once. If another master is still occupying the bus.
This master will do i2cFlush(i2c).
Cause it's a queue system. I should redo every action before the endTransmission(true) to make a second try.
I wish there will be a simple function like i2cRetry() and don't flush the queue automatically, the user could decide to call i2cRetry() to i2cProcQueue() again, or i2cFlush() to abort this i2c task.

Who is online

Users browsing this forum: No registered users and 60 guests