Help! How to setup a multi-master I2C?
Posted: 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
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
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:
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.
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);
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
I guess should check Wire.busy() before the finalWire.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.
Code: Select all
Wire.endTransmission();
Wire.requestFrom(len, true);
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;
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.