Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple I2C ports #3063

Closed
abouillot opened this issue Mar 20, 2017 · 15 comments
Closed

Multiple I2C ports #3063

abouillot opened this issue Mar 20, 2017 · 15 comments
Labels
waiting for feedback Waiting on additional info. If it's not received, the issue may be closed.

Comments

@abouillot
Copy link

The I2C implementation on ESP8266 is soft based. It can set the pin to use.
However, I had no success in getting two I2C bus running together. The issue I have is that the I2C device I want to use only have one address and I need two instances of it connected to the ESP. I was planing to open two Wire ports and connect each of the peripheral to one.

Is it possible with today's implementation? Is there any guide on how to achieve this?

@vlast3k
Copy link

vlast3k commented Mar 20, 2017 via email

@tablatronix
Copy link
Contributor

tablatronix commented Mar 26, 2017

see #2774 , #2607, #2162

@devyte
Copy link
Collaborator

devyte commented Sep 8, 2017

Does instancing another Wire object, and initing that to different pins work?

@devyte
Copy link
Collaborator

devyte commented Oct 1, 2017

@abouillot did you try any of the comments here?

@devyte devyte added the waiting for feedback Waiting on additional info. If it's not received, the issue may be closed. label Oct 1, 2017
@devyte
Copy link
Collaborator

devyte commented Oct 10, 2017

No feedback in over a month, closing.

@devyte devyte closed this as completed Oct 10, 2017
@kartom
Copy link

kartom commented Jul 8, 2020

This issue should be reopened since i can confirm that creating two instances will not work. The latest call to TwoWire::begin will set the pins used, no matter which object that are used and how they are configured. That since Wire.h is using an underlying twi in a non object oriented way.

void TwoWire::begin(int sda, int scl)
{
    default_sda_pin = sda;
    default_scl_pin = scl;
    twi_init(sda, scl);
    flush();
}

And twi_init uses one global twi object:

void twi_init(unsigned char sda, unsigned char scl)
{
    return twi.init(sda, scl);
}

Every TwoWire object should keep its own twi object, but the twi object is not exposed in the twi.h. Fore some reason the only thing that is exposed is a C wrapper over the object. The twi class itself calls those wrapper functions also, which is kind of strange. (The twi class is a bit of a hack, if you ask me.)

The Wire library looks like it is object oriented, but creating more than one TwoWire objects does not make sense with this implementation. This should be corrected or explained in the documentation.

The best solution imho is to expose the twi class in the twi.h file and redo the implementation of that class so it uses class functions instead of the exposed C-interface. This might however break some compatiblity with the twi.h file (not sure now).

The solution suggested by @vlast3k works but gives rather cluttered code if you like to communicate with devices on both i2c channels since you have to do a Wire.begin before each call to an i2c communication. Most libraries for i2c devices supports initializing their object with a TwoWire object to support multiple i2c channels, wich is necessary if you like to use more devices than there are possible adress configurations for that device. This support is now useless since this implementation prevents multiple TwoWire ojbjects.

@sierramike
Copy link

I agree with kartom, the issue should be reopened.
I tried the solution to call the begin() method again each time before having to communicate with another bus, but it's not working, only the first bus is working.
I suppose it is because I need to send a lot of commands in a small amount of time to adjust PWM outputs on multiple PCA9685 cards (one on each bus).

@daneisinger
Copy link

@devyte I'm running into this as well.

@devyte
Copy link
Collaborator

devyte commented Sep 13, 2020

Please open a new issue, follow the template instructions, explain the problem with the addresses, and reference this issue.
Note: from a quick look at the code, I don't see any practical reason to force a single I2C bus, as long as it is understood that only one bus may work at any given time (sw implementation: timing of one would interfere with timing of the other).

@6leonardo
Copy link

Have you solve? can I help? I need more than one i2c on same board?

@Bighoneypot
Copy link
Contributor

@abouillot In case your sensors have the same I2C address, use a TCA9548A multiplexer. I use it and it works great

@6leonardo
Copy link

Now it works....it's not very beautiful code but seams to work...
I have tested with 4 gy-bme280... 2 for bus
here the patch in cores/esp8266 I
and in the library Wire
you can put the wire library in local library but for the core I must change the original files
mod_i2c_multi-bus.zip
I attach the code for test the 4 gy-bme280
gy-bme280.ino.zip

@6leonardo
Copy link

@abouillot In case your sensors have the same I2C address, use a TCA9548A multiplexer. I use it and it works great

comunque grazie.... mi sa che è la soluzione piu pulita visto che se aggiornano la release perdo tutto....

@6leonardo
Copy link

Now it works....it's not very beautiful code but seams to work...
I have tested with 4 gy-bme280... 2 for bus
here the patch in cores/esp8266 I
and in the library Wire
you can put the wire library in local library but for the core I must change the original files
mod_i2c_multi-bus.zip
I attach the code for test the 4 gy-bme280
gy-bme280.ino.zip

more than not so good code.... the problem was using c++ classes with c timer in rom that want a c callback.... so I do the first thing that I thought that was create 5 function and from there call c++ ... the same thing was happen in twi but there I could use std:bind but with ets_timer and so I was not able to do it.... so I solve in very brutal way.... but works like a charm

@eisnerd
Copy link

eisnerd commented Nov 20, 2021

Now it works....it's not very beautiful code but seams to work... I have tested with 4 gy-bme280... 2 for bus here the patch in cores/esp8266 I and in the library Wire you can put the wire library in local library but for the core I must change the original files mod_i2c_multi-bus.zip I attach the code for test the 4 gy-bme280 gy-bme280.ino.zip

This is really cool. I tried it with two SSD1306 breakout modules that hide the "D/C#" address select pin so have identical I2C addresses. I have been able to use them simultaneously on separate SDA/SCL pins on an ESP8285 dev module. However, I have two other I2C modules (an MCP23016 gpio expander and AT42QT1070 touch sensor module) that do not work properly with this version of Wire/twi, even if there's just one device on one I2C bus and only the one global Wire instance. I can get their addresses with some "i2cdetect" code, but writing to them does not seem to work. I've tried adjusting the clock freq and pullups, but basically they work fine when I reset framework-arduinoespressif8266 and do a clean build, but stop responding when I switch back to your version and do a clean build.

I'll try to investigate further, but any guesses would be helpful. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
waiting for feedback Waiting on additional info. If it's not received, the issue may be closed.
Projects
None yet
Development

No branches or pull requests

10 participants