What's the proper way to deal with multiple devices sharing an i2c bus?

bitbang3r
Posts: 3
Joined: Sat May 26, 2018 12:17 am

What's the proper way to deal with multiple devices sharing an i2c bus?

Postby bitbang3r » Tue Jun 05, 2018 6:26 pm

I built an example project to use u8g2 via esp-idf on a lolin32 board that has an onboard SSD1306 OLED display hardwired via i2c using pins 4 and 5. As part of the setup, it uses Neil Kolban's u8g2_esp32_hal example code to initialize u8g2.

The project can be seen at https://github.com/jskubick/u8g2-exampl ... -sda5-scl4

Now, I want to add code to use additional devices sharing the same i2c bus as the display, and I'm not really sure how to proceed...
  1. rewrite u8g2_esp32_hal.c to turn it into a more general-purpose class for encapsulating an i2c_cmd_handle_t object, treat it like a Singleton, and use it to communicate with EVERYTHING that's on the pin 4/5 i2c bus?
  2. slightly refactor u8g2_esp32_hal.c to turn it into a more general-purpose class for encapsulating an i2c_cmd_handle_t object, but instantiate a separate object for every device on the bus. And maybe come up with some locking mechanism to ensure that only a single thread at a time can touch the i2c bus, and ensure that communication sequences don't get interrupted (say, if a thread that reads a SHT21 temperature/humidity sensor decides to run at the exact same instant another thread is updating the SSD1306 display).
  3. Some other strategy?
I have a hunch that I'm over-thinking the problem (I have 20 years of experience with Java to make me neurotic about design patterns and threading), but I'm not sure just how big of an issue it's likely to be. So far, I haven't found an esp-idf-specific example of sharing an i2c bus among multiple devices.

User avatar
kolban
Posts: 1683
Joined: Mon Nov 16, 2015 4:43 pm
Location: Texas, USA

Re: What's the proper way to deal with multiple devices sharing an i2c bus?

Postby kolban » Wed Jun 06, 2018 5:27 am

Howdy,
The nature of the I2C bus is that each of the slave devices attached to the bus has an address. The I2C protocol always starts by sending an addressing command with is 7 bits of address and 1 bit of whether this is a read or write request. The rules state that only the device with the matching address will respond to the request and all the other devices will ignore.

From this notion, you can have as many devices as you like attached to the CLK and SDA lines and only the device with the matching request address will honor and the others ignore.

If it were me and I was unfamiliar with the concept just described, I'd spend a little time googling I2C theory to read more about the high level principles of I2C. These will serve you well as you work with I2C in general.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32

genedyne
Posts: 18
Joined: Wed Jun 06, 2018 12:47 pm

Re: What's the proper way to deal with multiple devices sharing an i2c bus?

Postby genedyne » Wed Jun 06, 2018 2:03 pm

In your case, I'd suggest you DON'T.

I am also using u8g2 with a display on a ESP32 (started with Neils excelent example, too!). I think you'll find the display updates over I2C are pretty slow. You can optimize this by limiting updates to only portions of the screen that need it, but it's still pretty lethargic. I verified that the SSD1306 also supports SPI (which is what I use with my (similar) ST7565 display).

If you don't care about smooth updates, or your display doesn't change often, OR you're targetting I2C for hardware simplicity, then I'd suggest queuing I2C bus transactions would be best. Some locking scheme might seem simpler to ensure task A finished with the 'resource' before tack B took ownership, but my preference would be to have a single task 'own' the bus, and manage a queue of transactions to be performed, with results posted back to transaction initiators.

Best of luck!

User avatar
fly135
Posts: 606
Joined: Wed Jan 03, 2018 8:33 pm
Location: Orlando, FL

Re: What's the proper way to deal with multiple devices sharing an i2c bus?

Postby fly135 » Wed Jun 06, 2018 3:38 pm

Create a mutex and have the modules that use I2C go through a common I2C interface that controls access through that mutex.

edit: now that you mentioned this I took a look at the code in components/driver/i2c.c and it looks like there are mutexes created for each I2C bus. Presumably that's used to mutually exclude access.

John A

Who is online

Users browsing this forum: Google [Bot] and 403 guests