Strange i2c behavior with esp32 and Blynk

Hello,

I am using a CCS811 VOC and CO2 sensor, a BMP Pressure and Temperature sensor and an Adafruit SSD1306 OLED display with an Adafruit ESP32 Huzzah. All the sensors and display use i2c communications. If I run my code in the “stand alone” mode, i.e. not using Blynk, everything works fine. If I use Blynk, after some minutes up to several hours of operation, I get the following i2c errors:
[esp32-hal-i2c.c:161] i2cWrite():Busy Timeout! Addr:5b.
[esp32-hal-i2c.c:161] i2cWrite():Busy Timeout! Addr:40.
[esp32-hal-i2c.c:161] i2cWrite():Busy Timeout! Addr:5b.

I tried removing the display – same result.
I removed one sensor and removed the display – same result with Blynk.

I have read in other forums that the i2c on the ESP32 has some problems with timing but the fact that it works without Blynk leads me to believe that I must be doing something wrong with Blynk.

My code is below. I cleaned it up a bit by removing some of the functions to make it easier to read and this code works without Blynk and fails with Blynk.

/******************************************************************************


  Read the TVOC and CO2 values from the SparkFun CSS811 breakout board

  Originally derived from Sparkfun ESP32 Thing example
******************************************************************************/
#include <arduino.h>
#include "SparkFunCCS811.h"
#include <SPI.h>
#include <Wire.h>               //Classes for I2C
#include <Adafruit_GFX.h>       //Classes for display
#include <Adafruit_SSD1306.h>  //Classes for OLED display
/*******************************************************************
 *
 * The following lines are for connecting to Blynk
 *
 *******************************************************************/
#include <WiFi.h>             //
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>

// This is my authorization code for Blynk
char auth[] = “xxxxxxxxx”;  

//Put router info here
char ssid[] = “xxxxxxxxx”;
char pass[] = “xxxxxxxxxx”;
BlynkTimer timer;

/**********************************************************************************************/

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define CCS811_ADDR 0x5B //Default I2C Address for the CCS811
//#define CCS811_ADDR 0x5A //Alternate in case I have a conflict with others

CCS811 SensorOBJ(CCS811_ADDR);  //Sensor object of class CCS811

long chipid; //used if I want to display chip identification code
long NewTime = 0;  //upddated millisecond count
int GoofOff = 50; //delay time in milliseconds

void oledDisplay();  //function prototype declaration
void sendSensor();   //function prototype declaration



void setup()
{
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
  Serial.begin(115200);
  CCS811Core::status returnCode = SensorOBJ.begin(); // used for error codes
  Serial.print("begin exited with: ");
  Serial.println();
  display.clearDisplay();
  Blynk.begin(auth, ssid, pass); // start up Blynk

  // this uploads data from sensor to Blynk at 1 second intervals
  timer.setInterval(1000L, sendSensor);
  //timer.setInterval(2307L, oledDisplay);  // skew timer interval to stop i2c issues
}




void loop()
{
  Blynk.run();
  timer.run();
  //call function if Blynk is disabled
  //oledDisplay();
  //delay(1000);

}

void oledDisplay(){
  SensorOBJ.readAlgorithmResults(); //get data from Sensor
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0,0);
    display.print("TVOC: ");
    display.println( SensorOBJ.getTVOC());
    display.print("CO2:  ");
    display.println( SensorOBJ.getCO2());
    display.display();  //Write data to oled
    //display.clearDisplay();
}


void sendSensor(){

   if (SensorOBJ.dataAvailable()){
    Serial.println("Sending Data");
    SensorOBJ.readAlgorithmResults();
    int C = SensorOBJ.getCO2();
    int V = SensorOBJ.getTVOC();
    Blynk.virtualWrite(V0, C);
    Blynk.virtualWrite(V1, V);
    
  }
}

Could someone give me an idea as to what I should do?

Thank you

My experience with using the ESP32 is basically a bleeding edge process and things will go wonky…

The ESP32 is a dual core MCU, with unique timing issues that seem to still be a work in progress… as indicated by lack of analogWrite() commands and such.

Blynk also requires constant timing and communication, so there is bound to be some conflicts over time… but whether the issue is Blynk or espressif is hard to determine… but my bet is on the ESP32 Arduino core and espressif due to the still immature age of the port.

As to suggestions… sorry, the ESP32 is still too new to me to dig into the nitty gritties :stuck_out_tongue: One of mine runs 24/7 and disconnects from Blynk Server without errors or stopping the sketch at random times days, weeks… and this is without using i2C, but it is with using ledcSetup, so probably something with the core timing.

Thanks for the quick reply, Gunner. I sort of suspected this was going to be the answer, but I am an eternal optimist. :star_struck:

The issue with core timing is probably correct – further evidence of that is once the error occurs, the ESP32 continues giving the error message and can’t push data to Blynk until I reset it, although it is still connected to Blynk. I

have used the ESP32 with Blynk for some months now without i2c and have had no serious issues.

Thanks again for your help.

1 Like

A GitHub user going by the name stickbreaker has been doing a lot of work to improve I2C on Arduino ESP32. His work is currently being reviewed and there might be some API changes still but the code can be tested from a development branch created for his work. https://github.com/espressif/arduino-esp32/tree/stickbreaker-i2c

Unfortunately I can’t help with how to install this version instead of the official one but I’ve read several people commenting it has fixed most of their I2C related issues.

1 Like

Thanks, Ristomatti.

I will go give that a try and report back on the success.

Hello Ristomatti. I went to stickbreaker’s GitHub, and after reading through his explanations, I am now using his code. As of now, I have the ESP32, CCS811 and the OLED display working with Blynk with no failures for two days now! Before, the longest was about 2 hours. Thank you very much for your suggestions.

2 Likes

Hello Flyindon.

You could explain how you have incorporated the stickbreaker code in your program.

Hi BlackTiger,

Get the files you need from github at:

get wire folder and copy to Arduino/arduino-esp32

copy esp32 to Arduino/arduino-esp32/cores

To be safe, I would recommend renaming the old cores and old Wire folders just in case something blows up. Stickbreaker says this is a Beta version, so things may change and blow your stuff up.
Also, I am running into a bit of a problem in that I get a random failure every day or so. I think I may have a noise issue on the i2C bus, so I am going to clean up the board and keep monitoring this.

Here are some links to the background information that I found useful:

Good luck.

Don


background info


covers bus busy issues

@flyindon Great to hear that it helped! I haven’t actually ended needing it but your post just reminded me about this. It’s useful to occasionally check the arduino-esp32 GitHub issue threads to see how things are progressing.

thanks for your help flyindon.

Greetings BlackTiger

A post was split to a new topic: Compiling errors with ESP32

Hi flyindon,
I’m suffering a similar problem to that you describe. I have an ESP32 monitoring analog (light, wind-speed and temperature) and digital (temperature, humidity, barometric pressure) sensors for environmental monitoring. The program runs fine without Blynk (i.e. reporting to the serial port). When I implement Blynk, it disconnects from the wifi randomly, and the serial output shows that it hangs on one of the digital sensors (suggesting an I2C issue). If I comment out the digital sensors, and just monitor the analog sensors, Blynk runs with no problems. Your solution sounds like the right thing, but I’m not sure how to implement it. I can’t see how to download files from the Github links that you indicate above. What am I missing? I’m a newbie at this, so thanks for steering me in the right direction.

Michael,

I am out of town for a few days and away from my computer. I understand that Stickbreaker’s fixes hace been incorporated into espressif, so get the update from espressif. If you still have problems, I can try to help later this week.

Don

Don,
Thanks so much. I do have a very recent espressif implementation, so I guess that the Stickbreaker’s fixes are already in. In the meantime I believe that I have found a fix, or at least a work-around. My initial sketch called ‘readSensors’ as a function that read each sensor and wrote its value to a Blynk virtual pin sequentially. I wondered if the BlynkWrite function at the end of each sensor ‘module’ interfered with the I2C timing, so I placed all the BlynkWrite commands after reading all the sensors. So far no disconnect, so that’s good. Whether my reasoning is sound, I’m not sure, but the net result is what I hoped for. Thanks for your offer to help.

Michael

I have a very similar issue at the moment.

I’m using an OLED with relevant Adafruit Libraries to display my Can Bus Data onto the OLED and send it to Blynk for remote monitoring.

I went to a friend’s house to demo the software and was met with an OLED that displays absolute garbage - obviously my ESP32 didn’t connect to his network.

I started my software back at my place and double checked that everything is working, which it was until I switched off my wifi router.

I’m making use of Blynk v2.0.

I’m a bit confused as to how the blink library can cause timing issues on the I2C.

My Can Bus as well as my FreeRTOS tasks are running as should when the wifi is disconnected, any advice on what to try?

Are you using the Edgent example?

Pete.

Correct.

You should read this…

especially the “Defining your physical switch and LED” section, then check that you don’t have a GPIO conflict.

Pete.

1 Like

Thanks.

1 Like

I went through the article, and made two adjustments in the Settings.h file:

#else

// Custom board configuration
#define BOARD_BUTTON_PIN            0                     // Pin where user button is attached
#define BOARD_BUTTON_ACTIVE_LOW     true                  // true if button is "active-low"

#define BOARD_LED_PIN               27                    // Set LED pin - if you have a single-color LED     attached
//#define BOARD_LED_PIN_R           27                    // Set R,G,B pins - if your LED is PWM RGB 
//#define BOARD_LED_PIN_G           26
//#define BOARD_LED_PIN_B           25
//#define BOARD_LED_PIN_WS2812      33                    // Set if your LED is WS2812 RGB
#define BOARD_LED_INVERSE           false                 // true if LED is common anode, false if common cathode
#define BOARD_LED_BRIGHTNESS        64                    // 0..255 brightness control

#endif

I’m making use of the ESP32 DevKit v4.

My code reacts in exactly the same manner as explained above:
When the Wifi connection drops, the OLED immediately displays garbage.

I have noticed the following in ConfigMode.h:

void enterError() 
{
  BlynkState::set(MODE_ERROR);
  
  unsigned long timeoutMs = millis() + 10000;
  while (timeoutMs > millis() || g_buttonPressed)
  {
    delay(10);
    app_loop();
    if (!BlynkState::is(MODE_ERROR)) {
      return;
    }
  }
  DEBUG_PRINT("Restarting after error.");
  delay(10);

  restartMCU();
}

When the wifi connection is restored, and only after the MCU restarts, the MCU reconnects to the blynk server and my OLED displays the information correctly.

I have tested this theory by commenting the //restartMCU(); function - the MCU does not restart, the OLED displays garbage and it does not reconnect to the blynk server.

My Can Bus and other RTOS related tasks run without errors.

What will cause the processor to enter the error state and cause my I2C to be affected?

Thanks,
Shawn