I have a project that has been working well but today I noticed that the ESP32 Platform had an upgrade to version 5.2.0. I upgraded, cleaned, and recompiled without any issues. However when my code runs it breaks with an error in Wire.cpp:
These checks were added fairly recently, 3 months ago, and are present starting at Arduino-ESP32 2.0.5. Previously there were no such nullptr checks and the internal logic was slightly different.
These buffers are allocated when Wire.begin() is called (source). So, if that error occurs, either your code or one of the library you use do not call into Wire.begin(..); before trying to do a I2C transaction. The code changes in Wire.cpp probably only made a bug in your code or a library’s code visible that was there all along.
To counteract this, you can try do
Wire.begin(SDA, SCL);
as the first call in setup() (given SDA and SCL are your I²C pins).
Alternatively you can use a debugger and set a breakpoint at where it throws the error message in Wire.cpp. When the breakpoint is hit, it will show you the call traceback, i.e., which exact piece of code did try to do a I2C transaction before Wire.begin() was called. That is then the culprit.
Looking at these libraries, they seem to be the only ones doing something with I²C, and they all have proper .begin() methods that do a Wire.begin(). Does your code properly call .begin() on the objects created from this library? Do you have C++ classes which in their constructor code try to do a I²C transaction?
It’s been months since I did the initial code so my memory is a little fuzzy. Unfortunately this project has a LCD so I don’t have access to JTAG in order to run a debugger.
I have noticed perhaps a clue on the serial output when I start the board:
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:2
load:0x3fff0030,len:1184
load:0x40078000,len:13132
load:0x40080400,len:3036
entry 0x400805e4
[INFO]: Touch Panel started!
[ 1192][E][Wire.cpp:159] begin(): Bus already started in Master Mode.
.[LTR329] begin.
[LTR329] MANUFAC ID: 0x05
[LTR329] PART NUMBER: 0x0a
[LTR329] STATUS REG: 0b0
[LTR329] CTRL REG: 0b1101
[LTR329] MEAS REG: 0b11
[LTR329] Lux: 2.91
Found PCT2075 chip
High temperature threshold: 32.50
Temperature hysteresis: 30.50
Alert mode set to: Comparitor
Fault count set to: 4
PCT2075 Reports the Temperature: 28.37 C
mounted file system
reading config file
opened config file
That line about the bus already started led to me commenting out these 2 begin statements many months ago:
#define I2C_Freq 100000
#define I2C_SDA 33
#define I2C_SCL 27
...
FT6236 ft6236 = FT6236();
TouchScreen ts = TouchScreen(&tft, &ft6236);
...
TwoWire I2C_0 = TwoWire(0);
...
LTR329ALS01 ltr329(I2C_SDA, I2C_SCL);
Adafruit_PCT2075 pct;
...
Serial.begin(115200);
// Wire.begin(I2C_SDA, I2C_SCL); // Needed for CTP and LTR329
// I2C_0.begin(I2C_SDA, I2C_SCL, I2C_Freq); // Needed for PCT2075 library
I2C_0.begin(I2C_SDA, I2C_SCL); // Needed for PCT2075 library
...
// Connect to Touch
if (!ts.begin(TOUCH_THRESHOLD, I2C_SDA, I2C_SCL))
{
Serial.println("[INFO]: Touch Panel FAILED to start");
}
else {
Serial.println("[INFO]: Touch Panel started!");
}
initLTR329(); --> which has ltr329.begin();
initPCT2075(); --> which has pct.begin(PCT2075_Addr, &I2C_0)
Sorry, I switched back to the 5.1.1 platform so I could continue working. If I switch to 5.2.0 then the nullptr errors happen. I confirmed that twice yesterday.
I don’t think you can get rid of this message by just adapating your sketch code because, as soon as two or more libraries do a Wire.begin() on the same Wire object, it will throw that “error”. But it’s not critical.
So you have two I2C buses on which different devices are connected? If yes, restore I2C_0 again but use the second I2C peripheral (1) in the argument.
If not, then still remove I2C_0 but do a Wire.begin(I2C_SDA, I2C_SCL); again.
No, only 1 I2C bus but it’s not on the default pins. Yes, you’re probably right about the Master Mode warning so I’ll ignore that as a potential issue.
I’ll try adding in the new Wire.begin(I2C_SDA, I2C_SCL); statement and see what happens.
I got this to work by following Max’s suggestion of removing the I2C_0 define and just using a Wire.begin(I2C_SDA, I2C_SCL); in setup()
Not sure why this didn’t work on the first try but I got the code to work with Espressif 32 Platform 5.1.1 and then I was also able to upgrade to 5.2.0 and all is well.