stickbreaker / arduino-esp32

Arduino core for the ESP32

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bus Invalid State sda=1, scl=0

gulbo opened this issue · 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 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 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 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 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!

Do you have pullups on SCL and SDA?

3.3k is what i recommend.

Looks like the sensor needs a power cycle.

@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

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.

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!!

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..

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.

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?