Arduino: multiple i2c devices?

Created on 2 Jul 2015  Â·  14Comments  Â·  Source: esp8266/Arduino

Is it possible for an esp12 to have multiple i2c devices? I have been able to get an mpu-6050 (accelerometer/gyro) working with gpio4/gpio5 but I'd like to try and add an i2c screen (ssd1306) too.

The docs show that you can change the pins with the Wire.begin(int sda, int scl) would I add a second line with something like:

display.begin(int sda, int scl)

Most helpful comment

You're getting yourself very confused - you need to understand I2C at it's
very basic (connection) level...

Think of a tram-car running on rails. Think of the rails (two lines)
leaving the central terminus (the ESP in this case) - one line is called
SDA, the other is called SCL and they are just above the ground (GND). As
the lines go out, there are tram stops that connect to them, both SDA & SCL
and those tram stops are built on the ground.

Think of the tram as a bus and it's route as I2C.

When you declare the pins (Wire.begin(4,5);) you're telling the tram driver
which two lines to use (SDA on 4, SCL on 5) - these are the pins on the
device (in this instance, with an ESP, GPIO4 & GPIO5).

The tram stops along the route have addresses and no two can have the same
address. These addresses are in hexadecimal, are either fixed or variable
to a limited degree by the manufacturer. The base address for the OLED
display is 0x3C (with some Adafruit boards having an option to use 0x3D, I
think). I believe the base address for the MPU-6050 is 0x68, but I've never
used one). Two different addresses - so far, so good.

I2C is a 'master / slave' setup - someone is always in control of the tram
(the driver), he's paid by the company who own the tram and the terminus is
'head office' and they set the policy.

If you want to deliver something to a stop, you buy a ticket for that stop

  • send data to 0x3C or 0x68. If you want to collect something from a stop,
    you have to buy a return ticket, go there and ask for it - request data
    from 0x3C or 0x68, and because they're polite, if they have it, they'll let
    you bring it back.

Libraries do all sorts of clever things and, assuming that there are
ESP8266-modified libraries for the devices you want to use, they will take
your request, issue the correct ticket, leave the terminus and drive to
your stop - providing you get the address correct and return you to the
terminus if that's what you wanted...

SDA & SCL on the right lines and the right way round, correct address and
it works like magic with good libraries.

On 2 July 2015 at 17:54, Steve Nelson [email protected] wrote:

So then would I have two lines that would use the "Wire" object?
like:
//for accellerometer
Wire.begin(4,5);
//for OLED
Wire.begin(14,16);

And the bus will just deal with it? I was trying to use adafruit ssd1306
library which I've gotten to work on an arduino mega.

The library has cod like this:

define OLED_SDA 14

define OLED_SCL 16

define OLED_DC 2

define OLED_CS 12

define OLED_RESET 3

Adafruit_SSD1306 display(OLED_SDA, OLED_SCL, OLED_DC, OLED_RESET, OLED_CS);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

The library is throwing some errors on me at the moment that I'm trying to
debug, but do you see anything inherently wrong with this approach?

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505#issuecomment-118076152.

All 14 comments

SDA & SCL don't change - they're the lines that the I2C bus uses - all
devices use the same two lines. What changes is the I2C address for the
board you're wanting to address - one set of commands to the MPU6050, the
other set to the OLED...

As long as the two devices don't use the same address you're OK - but watch
out for on-board pullups...

On 2 July 2015 at 15:42, Steve Nelson [email protected] wrote:

Is it possible for an esp12 to have multiple i2c devices? I have been able
to get an mpu-6050 (accelerometer/gyro) working with gpio4/gpio5 but I'd
like to try and add an i2c screen (ssd1306) too.

The docs show that you can change the pins with the Wire.begin(int sda,
int scl) would I add a second line with something like:

display.begin(int sda, int scl)

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505.

So then would I have two lines that would use the "Wire" object?
like:
//for accellerometer
Wire.begin(4,5);
//for OLED
Wire.begin(14,16);

And the bus will just deal with it? I was trying to use adafruit ssd1306 library which I've gotten to work on an arduino mega.

The library has cod like this:

define OLED_SDA 14

define OLED_SCL 16

define OLED_DC 2

define OLED_CS 12

define OLED_RESET 3

Adafruit_SSD1306 display(OLED_SDA, OLED_SCL, OLED_DC, OLED_RESET, OLED_CS);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

The library is throwing some errors on me at the moment that I'm trying to debug, but do you see anything inherently wrong with this approach?

You're getting yourself very confused - you need to understand I2C at it's
very basic (connection) level...

Think of a tram-car running on rails. Think of the rails (two lines)
leaving the central terminus (the ESP in this case) - one line is called
SDA, the other is called SCL and they are just above the ground (GND). As
the lines go out, there are tram stops that connect to them, both SDA & SCL
and those tram stops are built on the ground.

Think of the tram as a bus and it's route as I2C.

When you declare the pins (Wire.begin(4,5);) you're telling the tram driver
which two lines to use (SDA on 4, SCL on 5) - these are the pins on the
device (in this instance, with an ESP, GPIO4 & GPIO5).

The tram stops along the route have addresses and no two can have the same
address. These addresses are in hexadecimal, are either fixed or variable
to a limited degree by the manufacturer. The base address for the OLED
display is 0x3C (with some Adafruit boards having an option to use 0x3D, I
think). I believe the base address for the MPU-6050 is 0x68, but I've never
used one). Two different addresses - so far, so good.

I2C is a 'master / slave' setup - someone is always in control of the tram
(the driver), he's paid by the company who own the tram and the terminus is
'head office' and they set the policy.

If you want to deliver something to a stop, you buy a ticket for that stop

  • send data to 0x3C or 0x68. If you want to collect something from a stop,
    you have to buy a return ticket, go there and ask for it - request data
    from 0x3C or 0x68, and because they're polite, if they have it, they'll let
    you bring it back.

Libraries do all sorts of clever things and, assuming that there are
ESP8266-modified libraries for the devices you want to use, they will take
your request, issue the correct ticket, leave the terminus and drive to
your stop - providing you get the address correct and return you to the
terminus if that's what you wanted...

SDA & SCL on the right lines and the right way round, correct address and
it works like magic with good libraries.

On 2 July 2015 at 17:54, Steve Nelson [email protected] wrote:

So then would I have two lines that would use the "Wire" object?
like:
//for accellerometer
Wire.begin(4,5);
//for OLED
Wire.begin(14,16);

And the bus will just deal with it? I was trying to use adafruit ssd1306
library which I've gotten to work on an arduino mega.

The library has cod like this:

define OLED_SDA 14

define OLED_SCL 16

define OLED_DC 2

define OLED_CS 12

define OLED_RESET 3

Adafruit_SSD1306 display(OLED_SDA, OLED_SCL, OLED_DC, OLED_RESET, OLED_CS);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

The library is throwing some errors on me at the moment that I'm trying to
debug, but do you see anything inherently wrong with this approach?

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505#issuecomment-118076152.

See this - #253

ha! Duncan, that was awesome.

Yep - so in Steve's case,

Wire.pins(0,2); // SDA, SCL
Wire.begin();

becomes

Wire.pins(4,5); // SDA, SCL
Wire.begin();

or whatever pins he wants to use.

_Steve:_
The (0,2) would give SDA on GPIO0 and SCL on GPIO2 and would make the I2C
bus usable on an ESP-01...

On 2 July 2015 at 19:20, Lstt2005 [email protected] wrote:

See this - #253 https://github.com/esp8266/Arduino/issues/253

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505#issuecomment-118097998.

I have my moments...............

On 2 July 2015 at 19:28, Steve Nelson [email protected] wrote:

ha! Duncan, that was awesome.

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505#issuecomment-118099723.

So Duncan, if I want a second device, do I do this:

Wire.pins(4,5); // SDA, SCL
Wire.begin();

Wire.pins(14,16); // SDA, SCL
Wire.begin();

What's confusing me is that I don't know where to set the device address. I'm working under the assumption that these commands above are simply defining what the pins do and the device's library will handle the device's address. Am I getting closer?

Both device will use the same pins either 4 and 5 OR 14 and 16, not both.

On Thu, Jul 2, 2015, 2:11 PM Steve Nelson [email protected] wrote:

So Duncan, if I want a second device, do I do this:

Wire.pins(4,5); // SDA, SCL
Wire.begin();

Wire.pins(14,16); // SDA, SCL
Wire.begin();

What's confusing me is that I don't know where to set the device address.
I'm working under the assumption that these commands above are simply
defining what the pins do and the device's library will handle the device's
address. Am I getting closer?

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505#issuecomment-118113533.

No....

Which pins do you want to use for I2C? Let's say GPIO0 and GPIO2, as
they're common to all... They then become the lines your bus runs on -
you're telling the tram driver how to exit the terminus.

All you then need, to complete that part of the process is:

Wire.pins(0,2); // SDA, SCL
Wire.begin();

The addresses for the stops (the slave modules)are pre-defined by the
breakout board manufacturer (and untimately the manufacturer of the chip on
that board) - other than picking an alternative if it's available (so you
could run 2x similar devices for example) there's nothing you can do - just
like you can't move tram stops.

Think of the tram stops being built by different contractors, the terminus
by another and the tracks laid by a third - as long as they're working to
the same specification, the system will work, even if they each have their
own method.

Assuming your OLED matches Adafruit's version then their page says the base
address is 0x3C or 0x3D, depending on type. Look at the example files that
ship with the library and, for the 128x64, you'll see the line:

display.begin(SSD1306_SWITCHCAPVCC, _0x3D_); // initialize with the I2C
addr 0x3D (for the 128x64)

That _0x3D_ is the address for the OLED and. as it occurs in setup, you've
bought your ticket to that stop in advance - yea!!!

The process will be similar for the other devices connected, by their
respective pins, to the SDA & SCL lines and the addresses will be
different...

I suggest that you get the OLED example running on its own first, then get
the mpu-6050 running on its own. When you're happy (understanding) that SDA
and SCL on GPIO0 and GPIO2 works happily with either address, then try and
combine the relevant parts of the software...

The two stops are on the same track, so it's wired SDA(ESP) to SDA(OLED) to
SDA(MPU) - same for SCL (but the order doesn't matter, unlike the tram
stops).

There should also be one pair of pullups for the whole bus, just like there
is one power feed to the tram lines - not one at each stop (and breakout
board manufacturers rarely offer an option to disconnect those that they've
fitted).

There's a heck of a lot of tutorials doing fantastic things with Arduino so
look at those and understand the concepts as a starting point (
https://www.youtube.com/watch?v=VEZGn0zYHiE as an example for the OLED*)
and then drill downwards...

Look at the transport map for where you want to go, locate the correct
terminus, bor uy the ticket from the correct operating company, board the
tram and enjoy the ride............................................

  • The video shows an I2C only display, the Adafruit displays also have an
    SPI option, which you'll be ignoring - 2 rails and ground - SDA, SCL and
    GND.

On 2 July 2015 at 20:11, Steve Nelson [email protected] wrote:

So Duncan, if I want a second device, do I do this:

Wire.pins(4,5); // SDA, SCL
Wire.begin();

Wire.pins(14,16); // SDA, SCL
Wire.begin();

What's confusing me is that I don't know where to set the device address.
I'm working under the assumption that these commands above are simply
defining what the pins do and the device's library will handle the device's
address. Am I getting closer?

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505#issuecomment-118113533.

ohhhh. That's surprising! I'll give it a try.

Does SPI work the same way? i.e. multiple devices plug into the same pins?

It's a bus - lots of things connected to common signals...

The answer to SPI is 'yes and no' - MISO, MOSI, SCLK are all shared with
all devices but there needs to be a separate SS line to each of them...

You're new to all this I'm guessing?

Read a few general things on Arduino Playground, get a couple of good books
(I can reccomend "Programming Arduino: Getting Started With Sketches" and
"Programming Arduino Next Steps: Going Further with Sketches", both by
Simon Monk, as being very easy to read and understand), watch YouTube
videos and begin from the bottom up - it _will_ all click into place...

On 2 July 2015 at 22:37, Steve Nelson [email protected] wrote:

ohhhh. That's surprising! I'll give it a try.

Does SPI work the same way? i.e. multiple devices plug into the same pins?

—
Reply to this email directly or view it on GitHub
https://github.com/esp8266/Arduino/issues/505#issuecomment-118160707.

First of all, damnnn duncan. that's a fine explanation.

However this post is not updated since Jul,15 so I an in dilemma of whether I should make a new post or use this one to clarify my doubts. Anyway here it goes.

I got the point that we should have a common SDA, SLC that is connected to each I2C device we wanna use. And we must use the begin(SDA,SLC) command only once in the master code to set up 1 SDA and 1 SLC line. I also got that as of now ESP8266 only allows master mode, so anything else connected to it has to be a slave. Also on the same bus each slave device will be identified through it's own unique address. This unique address can be set by the begin(Hex/Int device address) in the code you are writing for the slave device. both device codes must import wire.h.

Once done with this write a request event on your slave device.(I used an arduino as a slave so I was able to write a onRequest event, not sure if other I2C sensors provides that by default -- actually that's a question i'd wanna ask the guru's over here.. plz respond and let us know.) and then from your master device(ESP8266) call the receive request to the slave device through Wire.requestFrom(Hex/Int device address , The max length of the msg you are expecting); .

This will work, and if you are still not clear you should go to your Arduino installation folder and search for the wire library.It comes with some example. The path in windows typically is "C:Program Files (x86)ArduinohardwarearduinoavrlibrariesWireexamples". out of these example upload the master reader to the esp, slave writer to your arduino(again I was testing with that.. if you have a sensor instead, I guess it should be sending the data as a slave by default). Make sure you have connected your SDA,SLC wires to the default GPIO4/5 else you need to add the wire.pins(SDA,SLC) i.e. wire.pins(0,2); incese you are using GPIO0/2 as SDA/SLC line on top of your master(ESP) code's begin(); .

Well, now my question is I read through the ESP8266 data sheet in and out but was not able to find the right I2C address .. + when I used the I2C scanner it also gave me nothing.

Can anyone take any real data sheet for example and highlight the location which I should be looking at for the I2C address? that will help a lot. Just one example .. any example. Thanks.

Help Needed!!!
I am using MFRC and ssd 1306 with node mcu but very confused because I have used the sda pin for both mfrc and ssd 1306 and it is not working together if comment ssd1306 code then it works fine.
so can anyone guide me how can I use sda pin for both of them
the code is given below ;
//SDA and SCL pins are defined below;

define SS_PIN 4 //D2

define RST_PIN 0 //D3

include

include

include

include

include

include

define OLED_RESET -1

Adafruit_SSD1306 display(128, 64, &Wire, OLED_RESET);

MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
int statuss = 0;
int out = 0;
void setup()
{
Serial.begin(115200); // Initiate a serial communication
SPI.begin();
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
delay(2000);
display.clearDisplay();
display.setTextColor(WHITE);
//SPI.begin(); // Initiate SPI bus
mfrc522.PCD_Init(); // Initiate MFRC522
}
void loop()
{
//welcome();
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent())
{
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial())
{
return;
}

//Show UID on serial monitor
Serial.println();
Serial.print(" UID tag :");
String content= "";
byte letter;
for (byte i = 0; i < mfrc522.uid.size; i++)
{
Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
Serial.print(mfrc522.uid.uidByte[i], HEX);
content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
content.concat(String(mfrc522.uid.uidByte[i], HEX));
}
content.toUpperCase();
Serial.println();
if (content.substring(1) == "42 13 44 1E") //change UID of the card that you want to give access
{
Serial.println(" Access Granted ");
Serial.println(" Welcome ");
//ssd1306 code
display.clearDisplay();
display.setTextSize(1); // Normal 1:1 pixel scale
display.setTextColor(WHITE); // Draw white text
display.setCursor(14,25); // Start at top-left corner
display.println("Verified");
display.display();
delay(1000);
Serial.println(" Have FUN ");
Serial.println();
statuss = 1;
}

else {
Serial.println(" Access Denied ");
delay(3000);
}
}

PLEASE GUIDE ME I WILL BE VERY THANKFUL

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mark-hahn picture mark-hahn  Â·  3Comments

Geend picture Geend  Â·  3Comments

mechanic98 picture mechanic98  Â·  3Comments

rudydevolder picture rudydevolder  Â·  3Comments

dariopb picture dariopb  Â·  3Comments