3

tl;dr can someone tell me if it is possible to set custom pins for an I2C slave (client, peripheral) within the Arduino environment?

Context On an ESP32 (ESP32-WROVER from Freenove) I am trying to communicate with 2 devices that are I2C masters (Adafruit Monster M4sk)

On this particular ESP32-WROVER board the default SDA and SCL pins are used by a camera. So I have to set up I2c on different pins. I'm using pin 2 as SDA and pin 15 as SDL.

I can easily set up I2C as a MASTER on those pins, works just fine using Wire.begin(2,15). I find lots of documentation about setting custom pins, multiple busses using Wire or TwoWire.

What I really want to do is something like this:

#include <Wire.h>

#define SDA1 2
#define SCL1 15

#define SDA2 21
#define SCL2 22

#define SLAVE_ADDRESS_ON_BUS_1 0x52
#define SLAVE_ADDRESS_ON_BUS_2 0x33

setup()
{
  Wire.begin(SDA1,SCL1,SLAVE_ADDRESS_ON_BUS_1); // Join I2C bus 1 using pins 2 and 15
  Wire1.begin(SDA2,SCL2,SLAVE_ADDRESS_ON_BUS_2);// Join I2C bus 2 using pins 21 and 22


  Wire.onReceive(receiveI2CBus1Event); // register event for when master on i2c bus 1  writes
  Wire.onRequest(WriteToI2CBus1Event); // register event for when master1 wants on i2c bus 2 wants to read

  Wire1.onReceive(receiveI2CBus2Event); // register event for when master on i2c bus 2 writes
  Wire1.onRequest(WriteToI2CBus2Event); // register event for when master on i2c bus 2  wants to read
}

As far as I can tell there is no way to use either Wire or TwoWire to create a peripheral on a custom set of pins...

Wire.begin(MY_ADDRESS);

I have tried re-defining SDA and SCL but that does not seem to work Note I am running Expressif's ESP32 libraries v2.0.2 (ESP32 Libraries 1.0.6 and prior did not support ESP32 as a slave) I have tried this (this being redefining SDA and SCL) using both Arduino IDE 1.8.19 and Arduino IDE 2.0.0.rc5

I can't be the first person trying to have an ESP32 act as an i2c slave using something other than the default pins...

Am I gonna have to resort to some sort of I2C bridge/switch/mux? if so, any recommendations? (preferably recommendations with arduino sample code showing how a master can assign an address to another master)

Thank you.

2 Answers2

4

You're very close, you just have the order of the parameters flipped. The address comes first, followed by the pin numbers.

There are optional parameters to Wire.begin() that allow you to specify the pins used for the I2C controller in slave mode:

    bool begin(uint8_t slaveAddr, int sda=-1, int scl=-1, uint32_t frequency=0);

So you could call

Wire.begin(MY_ADDRESS, SDA1, SCL1);

and optionally specify the frequency as a final argument if you need to.

While this form of begin() looks like it's for a master, its code explicitly sets the is_slave flag:

    is_slave = true;

and calls i2cSlaveInit().

I haven't actually used this so I can't promise it works, but this is the way the code is organized.

romkey
  • 6,218
  • 3
  • 16
  • 12
  • 1
    Not only was the parameter order wrong, the first parameter is type sensitive. The following change will compile, and the esp32 will join the bus as a slave, using the pins specified. I can confirm that both the read and write callback functions get called on the ESP32 slave. I can NOT at this time confirm the data written is anything other than garbage, but hey that may just be a hardware problem. But One Step Closer THANK YOU! ``` uint8_t slave_addr = SLAVE_ADDRESS; Wire.begin(slave_addr,SDA1,SCL1); // I2C bus 1 setup SLAVE, i2c fast mode ``` – George Dolbier Mar 31 '22 at 04:52
1

Another way is to invoke Wire.setPins() before invoking Wire.begin(). It's equivalent to passing the pin numbers to the constructor, so there's no reason to prefer one over the other. Just take your pick.

Eric Mintz
  • 61
  • 1
  • 2