Skip to content

Confusing overload of Wire::begin #6616

@Equidamoid

Description

@Equidamoid

Board

Any

Device Description

Not specific to a device.

Hardware Configuration

Any I2C device connected

Version

v2.0.2

IDE Name

CLion + platformio

Operating System

Linux

Flash frequency

N/A

PSRAM enabled

no

Upload speed

N/A

Description

The Wire::begin method has confusing overload:

    bool begin(int sda=-1, int scl=-1, uint32_t frequency=0); // returns true, if successful init of i2c bus
    bool begin(uint8_t slaveAddr, int sda=-1, int scl=-1, uint32_t frequency=0);

The sda and scl arguments are of type int, while the SDA and SCL constants from d32_core.h have type uint8_t. A "naive" user might try to call begin(SDA, SCL) and get mysterious "could not acquire lock" error on first attempt to use the bus.

To make the problem worse, this code worked fine before the "slave" overload was introduced.

As a solution I want to propose renaming the "slave" function to something like begin_slave.

Sketch

int setup(){
    // have to explicitly specify the pins to provide the frequency
    Wire.begin(SDA, SCL, 4000);
    Wire.beginTransmission();
}

Debug Message

[   238][E][Wire.cpp:319] beginTransmission(): could not acquire lock
[   239][E][esp32-hal-i2c.c:142] i2cWrite(): could not acquire lock


### Other Steps to Reproduce

_No response_

### I have checked existing issues, online documentation and the Troubleshooting Guide

- [X] I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Activity

me-no-dev

me-no-dev commented on Apr 24, 2022

@me-no-dev
Member

You can also:

Wire.begin();
Wire.setClock(frequency);
StickStackxD

StickStackxD commented on Apr 24, 2022

@StickStackxD

You can also:

Wire.begin();
Wire.setClock(frequency);

I can confirm that the workaround is working for now.

Equidamoid

Equidamoid commented on Apr 24, 2022

@Equidamoid
Author

@me-no-dev
I came up with this (I know, ugly, but at least straightforward):

Wire.begin(static_cast<int>(SDA), static_cast<int>(SCL), static_cast<uint32_t>(4000));
me-no-dev

me-no-dev commented on Apr 25, 2022

@me-no-dev
Member

casting also works, but I do see this as a kind of issue :) we will have to "fix" this somehow

mymy-dot

mymy-dot commented on May 25, 2022

@mymy-dot

This issue ended up taking me several hours to solve, until by chance I came across this post. Granted, I don't know what I'm doing. But I do know that adding:

Wire.begin(static_cast<int>(SDA), static_cast<int>(SCL), static_cast<uint32_t>(4000));

Made the beginTransmission(): could not acquire lock error go away on my ESP-WROOM-32 and I was able to access my I2C device.

bato3

bato3 commented on Jul 14, 2022

@bato3

This is because SDA and SCL are defined as

static const uint8_t SDA = 21;
static const uint8_t SCL = 22;

and Wire.begin() can be:

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

And some libriares defines it initializations as:

   bool     begin(uint8_t sda = SDA, uint8_t scl = SCL, uint32_t speed = AHTXX_I2C_SPEED_100KHZ, uint32_t stretch = AHTXX_I2C_STRETCH_USEC);

Working solutions

  Wire.begin((int) SDA , (int) SCL);
  Wire.begin(21, 22);
  Wire.begin();

Not working solutions:

Wire.begin(0x38, (int) SDA, (int) SCL);
Wire.begin((uint8_t) -1, (uint8_t) -1); // display error:
//i2cSlaveInit(): invalid pins sda=-1, scl=22

Another affected: esphome/esphome#2978

19 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Status: SolvedThe issue has been resolved and requires no further action.

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions

    Confusing overload of `Wire::begin` · Issue #6616 · espressif/arduino-esp32