arduino-esp32 icon indicating copy to clipboard operation
arduino-esp32 copied to clipboard

Bus Invalid State sda=1, scl=0

Open gulbo opened this issue 5 years ago • 11 comments

Hardware:

Board: DOIT Esp32 DevKit v1 Core Installation/update date: last release IDE name: Platform.io Flash Frequency: 40Mhz Upload Speed: 115200

Description:

I'm working on a project to upload on a Google Sheet accelerations read by the MPU6050, connected with wifi. There are 2 taks, one to read accelerations (readData) and one to upload them using HTTP (postRequest). The problem is: everything works, until when this error occurs! At that point the accelerometer doesn't show up anymore even running a simple i2c scanner sketch. Dead. If I change accelerometer (did it 3 times), everything works again... This for 10mins, or 1 day maybe, but sooner or later the error returns. I attach also the hardware layout I am using. Am I burning accelerometers? Is it just a code problem? pls save me MVIMG_20190425_115932

Sketch:

#include <Arduino.h>
#include "I2Cdev.h"
#include "MPU6050.h"
#include "Wire.h"
#include "WiFi.h"
#include "HTTPClient.h"
#include "freertos/FreeRTOS.h"
#include <string.h>

#define CORE_DEBUG_LEVEL (5) //FROM 1 TO 5
#define READ_DELAY 20 	//20 ms means 50hz
#define POST_DELAY 	10000 
#define SEND_POST 1

MPU6050 accel(0x69);

// SSID and Password
static const char* ssid     = "G";
static const char* password = "f1";
static const char* url = "https://hooks.zapier.com/hooks"; 

//data
String x_buf, y_buf, z_buf;
bool read_en;

//rtos
static TaskHandle_t xTaskPost = NULL, xTaskData = NULL;
static SemaphoreHandle_t xMutex;

// Establish a Wi-Fi connection with your router
void initWifi() {
	Serial.print("Connecting to: "); 
	Serial.print(ssid);
	WiFi.begin(ssid, password);  

	int timeout = 10 * 4; // 10 seconds
	while(WiFi.status() != WL_CONNECTED  && (timeout-- > 0)) {
	delay(250);
	Serial.print(".");
	}
	Serial.println("");

	if(WiFi.status() != WL_CONNECTED) {
		Serial.println("Failed to connect to WIFI");
		while(1);
	}

	Serial.print("WiFi connected in: "); 
	Serial.print(millis());
	Serial.print(", IP address: "); 
	Serial.println(WiFi.localIP());
}

void initMPU(){
	Serial.print("Waiting MPU.....");
	while (!accel.testConnection()){
		Serial.print(accel.getDeviceID());
		Serial.print(".");
		delay(300);
	}
	Serial.println(".");
	Serial.println("MPU6050 connection successful");
	accel.initialize();

	delay(1000);
	// set offsets
	accel.calibrate(-5109, -5497, 9133, 38, -152, 29);

	//low pass filter
	Serial.println("Low-pass filter at 42Hz");
	accel.setDLPFMode(MPU6050_DLPF_BW_42);
}

// Make an HTTP request to the web service
void postRequest(void * pvParameters ) {
	String jsonObject;
	while(1){
		while(xSemaphoreTake(xMutex, (TickType_t) 1) != pdTRUE);
		if (read_en && xPortGetFreeHeapSize()>150000){ //if not reading, or not enough space, do not concatenate anymore
			Serial.println(String("Heap size free: ") + xPortGetFreeHeapSize());
			jsonObject.concat(String("{\"value1\":\"") + x_buf);
			x_buf = (char*) NULL; //invalidate
			jsonObject.concat(String("\",\"value2\":\"") + y_buf);
			y_buf = (char*) NULL; //invalidate
			jsonObject.concat(String("\",\"value3\":\"") + z_buf + "\"}\n");
			z_buf = (char*) NULL; //invalidate
		}
		else{
			Serial.println("Not enough space, waiting to POST successfully...");
			Serial.println(String("Heap size: ") + xPortGetFreeHeapSize());
			Serial.println(String("Reading accelerations: ") + (read_en?"enabled":"disabled"));
		}
		xSemaphoreGive(xMutex);
		Serial.println(String("Connecting to ") + url);   
		HTTPClient http;
		http.begin(url);
		//http.addHeader("authorization: Bearer ", auth_token);
		http.addHeader("content-type:", "application/json");
		#if SEND_POST
		int httpResponseCode = http.POST((uint8_t *)jsonObject.c_str(),jsonObject.length());
		#else
		int httpResponseCode = 0;
		Serial.println(jsonObject);
		#endif
		//Serial.println(jsonObject);
		if(httpResponseCode > 0){
			String response = http.getString(); 	//Get the response to the request
			Serial.println(httpResponseCode);   	//Print return code
			Serial.println(response);           	//Print request answer
			jsonObject = (char*) NULL;
			while(xSemaphoreTake(xMutex, (TickType_t) 1) != pdTRUE);
			if (!read_en){ 
				read_en = true;
				Serial.println("Read now enabled again");
			}
			xSemaphoreGive(xMutex);
			Serial.println("json empty!");
			Serial.println(String("Heap size: ") + xPortGetFreeHeapSize());
		}
		else{
			Serial.print("Error on sending POST: ");
			Serial.println(httpResponseCode);
		}
		
		http.end();  //Free resources
		vTaskDelay(POST_DELAY);
	}
}

void readData(void * pvParameters ) {
	for(;;){
		int16_t ax, ay, az;
		accel.getAcceleration(&ax, &ay, &az);
		while (xSemaphoreTake(xMutex, (TickType_t) 1) != pdTRUE);
		if (read_en){
			bool read_x = x_buf.concat(ax + String(" "));
			bool read_y = y_buf.concat(ay + String(" "));
			bool read_z = z_buf.concat(az + String(" "));
			read_en = read_x && read_y && read_z;
			if (!read_en){
				Serial.println("READ NOW DISABLED");
			}
		}
		xSemaphoreGive(xMutex);
		vTaskDelay(READ_DELAY);	
	}

}

void setup() {
	// join I2C bus (I2Cdev library doesn't do this automatically)
	Wire.begin();
	delay(1000);
	// initialize serial communication
	Serial.begin(115200);

	//mpu
	initMPU();
	
	//wifi
	delay(4000);
	initWifi();
	
	read_en = true;
	xMutex = xSemaphoreCreateMutex();
	xTaskCreate(
				postRequest,       /* Function that implements the task. */
				"PostReqTask",          /* Text name for the task. */
				4096,      /* Stack size in words, not bytes. */
				( void * ) 1,    /* Parameter passed into the task. */
				tskIDLE_PRIORITY,/* Priority at which the task is created. */
				&xTaskPost );      /* Used to pass out the created task's handle. */

	xTaskCreate(
				readData,       /* Function that implements the task. */
				"ReadDataTask",          /* Text name for the task. */
				4096,      /* Stack size in words, not bytes. */
				( void * ) 1,    /* Parameter passed into the task. */
				tskIDLE_PRIORITY,/* Priority at which the task is created. */
				&xTaskData );      /* Used to pass out the created task's handle. */

} 

void loop(){}


Debug Messages:

[E][esp32-hal-i2c.c:1426] i2cCheckLineState(): Bus Invalid State, TwoWire() Can't init sda=1, scl=0
Waiting MPU.....0.0.0.0.0.0.

gulbo avatar Apr 25 '19 10:04 gulbo

@gulbo Are you using this branch? It is outdated, I would recommend you use the Official repo at Arduino-ESP32.

Try that version, if you still have problems I'll help.

Chuck.

stickbreaker avatar Apr 25 '19 22:04 stickbreaker

@stickbreaker Hi, actually I tried them both. I ended up in this branch since I read something about the fact that the main repo provides a poor implementation of the wire library. But probably it was an old comment! Anyway, I tried

gulbo avatar Apr 25 '19 23:04 gulbo

@gulbo I think you are running into a timeout issue, the ESP32 with CPU clock speed above 80mhz only allows a 13.1ms I2C timeout, if the slave device stretches SCL (during sample conversion) longer than this period, the I2C hardware fails and aborts the communication sequence. You are going to have to review the datasheet for your sensor and use the polling method for sample acquisition instead of SCL stretching. I recommend you use the main branch of Arduino-Esp32 version v1.0.2.

Chuck.

stickbreaker avatar Apr 26 '19 12:04 stickbreaker

@stickbreaker thank you, but now even if I run a simple i2c scanner, the result are 20 lines of _Bus Invalid State, can't init sda=1, scl=0 _ can I recover this accelerometer? It seems I can't communicate with it at all! Moreover, is it possible that this happened because I enabled in the accelerometer the low-pass filter at 43hz? In any case now I cannot disable it, since I can't even find it with a scanner!

gulbo avatar Apr 26 '19 15:04 gulbo

Do you have pullups on SCL and SDA?

3.3k is what i recommend.

Looks like the sensor needs a power cycle.

stickbreaker avatar Apr 26 '19 17:04 stickbreaker

@stickbreaker no I don't! Now I put 3k, is it ok? Should I disable the internal ones of esp32? The sensor has internal pullups of 2.2k also. In any case, even power cycling doesn't solve the probelm! If I keep the sensor off for some minutes, then the scanner finds it again, but after 15 seconds, it disappears! This sensor has a sampling rate of 1khz. With the digital low-pass filter I enabled, the datasheet says there is a delay of 4.9ms in the sampling rate. Could this be the problem you were saying? However I disabled it (in the 15 seconds window I have to communicate with the sensor), and the sensor doesn't seem to recover thank you very much for helping me Chuck

gulbo avatar Apr 27 '19 10:04 gulbo

I believe the sensor is getting locked up when the command sequences are aborted during an error. You could test the sensor using an UNO or Mega2560.

I would say step back and write a simple test sketch that just configures it and reads it. Verify the sensor works, that you are not fighting a hardware error.

Chuck.

stickbreaker avatar Apr 27 '19 12:04 stickbreaker

Ok I'll take an UNO. It will take a day or two. What about the pull-ups I told you? And the low-pass filter? Since I changed 3 sensors, and I ran always the same code, I belive it is something more software related! But who knows....

Thank you again!!

gulbo avatar Apr 27 '19 12:04 gulbo

Tried with UNO. Ran this basic sketch https://playground.arduino.cc/Main/I2cScanner After the first loop, it blocks.
immagine I have in total 5 accelerometers, 3 of them are in this state. I can take the fourth and try to work with that, but I have a strong sensation that it will go sooner or later in the same state, if I don't find the cause..

gulbo avatar Apr 28 '19 08:04 gulbo

you are using a voltage level convert with the Uno? The sensor is 3.3v only.

I would use 3.3k pullups to 3.3v on each of the i2c pins (SCL,SDA).

For Uno's I use AdaFruits 4-channel I2c. I put two more resistors on each channel, one on the 3.3v side 10k to 3.3v, and another 10k to 5v on the 5v side. This gives and effective resists of about 3k

Chuck.

stickbreaker avatar Apr 28 '19 14:04 stickbreaker

No, without voltage converter! But actually I have always used this sensor with Arduino at 5V, and it has always worked! Also I tried with the two remaining sensors I have, and it works perfectly, with or without pullups. Ofc I just tried for few seconds, because I don't want them to go in the same state as the others... I have no idea at all... UPDATE: tried for a while the "working accelerometer" with Arduino, just reading accelerations, and it worked without problems! Using ESP32 and running my code, it would have been already broken probably. So it seems that something in my code, or in the libraries, is "burning" the accelerometers. Can it be possible?

gulbo avatar Apr 28 '19 15:04 gulbo