Updating Espressif 32 to 5.2.0 Breaks Wire.cpp?

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:

ets Jul 29 2019 12:21:46

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
[  1083][E][Wire.cpp:526] write(): NULL TX buffer pointer
[  1083][E][Wire.cpp:526] write(): NULL TX buffer pointer
[  1083][E][Wire.cpp:448] endTransmission(): NULL TX buffer pointer

If I revert back to version 5.1.1 (or 5.1.0) and clean, compile, upload, then everything works as expected.

My relevant platformio.ini is:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_port = COM10
board_build.partitions = default_8MB.csv
;board_build.partitions = no_ota.csv
board_flash_size = 8MB
board_maximum_size = 8388608
board_upload.flash_size = 8MB
;lib_ldf_mode = deep+
lib_deps = 
	links2004/WebSockets@^2.3.7
	yoprogramo/QRcodeDisplay@^2.0.2
	yoprogramo/QRcode_eSPI@^2.0.0
	ttarnowski/uniuno-timer@^1.0.0	
	SPI
	Wire
	adafruit/Adafruit BusIO
	TFT_eSPI
	;bodmer/TFT_eWidget @ ^0.0.5 ; added as library so I could customize it
	adafruit/Adafruit PCT2075
	https://github.com/aselectroworks/Arduino-LTR329
	https://github.com/DustinWatts/FT6236
	https://github.com/me-no-dev/ESPAsyncWebServer
	https://github.com/me-no-dev/AsyncTCP
	ayushsharma82/AsyncElegantOTA @ ^2.2.7
	bblanchon/ArduinoJson @ ^6.19.2
	;ModbusClient=https://github.com/eModbus/eModbus.git
	miq19/eModbus@^1.6.0
	; 070722 ESP Async WebServer ; latest stable version of ESPAsyncWebServer
	; ESP8266WiFi
	; https://github.com/tzapu/WiFiManager.git@^2.0.11-beta
	https://github.com/tzapu/WiFiManager.git
	; tzapu/WiFiManager @ ^2.0.11-beta
	paulstoffregen/OneWire@^2.3.7
	;milesburton/DallasTemperature@^3.9.1

I’m hoping that I’m overlooking something simple and obvious but I haven’t found out what that is yet.

Any ideas on what this could be?

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?

Hi Max,

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)

Maybe something here jumps out at you.

No nullptr errors anymore like the first post shows?

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.

But why? TwoWire(0) is already Wire.

Instantiating two objects for the same I2C bus looks disastrous. Remove I2C_0 from the code, and replace &I2C_0 with just &Wire.

I believe I did that because my I2C was not on the default pins and the PCT2075 library required me to do it this way?

If I make the changes you suggested I get this in the serial monitor on boot up:

ets Jul 29 2019 12:21:46

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!
[  1191][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
Couldn't find PCT2075 chip

The same Master mode warning and now it doesn’t find the PCT2075.

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.

OK, this is bringing back bad memories of when I started this project and tried to get everything up and running.

I have this Wire.begin(I2C_SDA, I2C_SCL); in setup() and then in my PCT2075 initialization I have:

// PCT2075 Temp Sensor
    if (!pct.begin(PCT2075_Addr, &Wire))  // 221103 Changed from &I2C_0
    {
        Serial.println("Couldn't find PCT2075 chip");
        // while (1)
        return;
    }

but in my serial port I’m seeing this on a boot up:

[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
Couldn't find PCT2075 chip

So the only way I got everything to work before was the way I did it but I can’t explain why to be honest.

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.