esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
15.96k stars 13.34k forks source link

problems starting I2C (reading BMP180 preasure sensor) #2261

Closed AnduriI closed 6 years ago

AnduriI commented 8 years ago

Basic Infos

Hardware

Hardware: ESP-12E Core Version: 2.3.0

Description

Hey there, hope you can help. I have a nodeMCU v1.0 which works fine running several sketches. But when trying to read an I2C sensor I fail. I read to use Wire.begin(9, 10); to start the wire library with selected SDA and SCL. I have my sensor connected to the SD2 and SD3 pin of the nodeMCU which are GPIO 9 and 10. I uploaded the whole sketch below to have a look at, but thats only the BMP test example from adafruit. Even with nothing connected to the nodeMCU it shows the same behaviour (not the error that should be printed). One strange thing is that I can not read anything at the specified 9600 Baud but only on 115200 Baud. I use Arduino IDE to flash my ESP8266.

Settings in IDE

Module: nodeMCU v1.0 Flash Size: ?4MB/1MB? CPU Frequency: 80Mhz Flash Mode: ?qio? Flash Frequency: ?40Mhz? Upload Using: ?OTA / SERIAL? Reset Method: ?ck / nodemcu?

Sketch

#include <Wire.h>
#include <Adafruit_BMP085.h>

/***************************************************
  This is an example for the BMP085 Barometric Pressure & Temp Sensor

  Designed specifically to work with the Adafruit BMP085 Breakout
  ----> https://www.adafruit.com/products/391

  These displays use I2C to communicate, 2 pins are required to
  interface
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// Connect VCC of the BMP085 sensor to 3.3V (NOT 5.0V!)
// Connect GND to Ground
// Connect SCL to i2c clock - on '168/'328 Arduino Nano/Uno/Duemilanove/etc thats Analog 5
// Connect SDA to i2c data - on '168/'328 Arduino Nano/Uno/Duemilanove/etc thats Analog 4
// EOC is not used, it signifies an end of conversion
// XCLR is a reset pin, also not used here

Adafruit_BMP085 bmp;

void setup() {
  Wire.begin(9, 10);
  Serial.begin(9600);
  if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP085 sensor, check wiring!");
    while (1) {}
  }
}

void loop() {
  Serial.print("Temperature = ");
  Serial.print(bmp.readTemperature());
  Serial.println(" *C");

  Serial.print("Pressure = ");
  Serial.print(bmp.readPressure());
  Serial.println(" Pa");

  // Calculate altitude assuming 'standard' barometric
  // pressure of 1013.25 millibar = 101325 Pascal
  Serial.print("Altitude = ");
  Serial.print(bmp.readAltitude());
  Serial.println(" meters");

  // you can get a more precise measurement of altitude
  // if you know the current sea level pressure which will
  // vary with weather and such. If it is 1015 millibars
  // that is equal to 101500 Pascals.
  Serial.print("Real altitude = ");
  Serial.print(bmp.readAltitude(101500));
  Serial.println(" meters");

  Serial.println();
  delay(500);
}

Debug Messages

All I get when using I2C is the following in a loop:

 ets Jan  8 2013,rst cause:4, boot mode:(3,4)

wdt reset
load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v60000318
~ld

 ets Jan  8 2013,rst cause:4, boot mode:(3,4)

wdt reset
load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v60000318
~ld
me-no-dev commented 8 years ago

what happens if you use the default GPIO4 and 5?

AnduriI commented 8 years ago

I will be using this nodeMCU as a mysensors gateway. Unfortunatly the build instructions say that the radio has to be on D2 and I don't know where to change this. But as far as I read this shouldn't be a problem as ESP8266 has I2C only implemented in software. And even with no Pins connected at all I don't get the error message as stated in void setup() but only a wdt reset. I even tried to remove the costume pin selection and started the wire library with standard GPIO4 and 5, with the same result

RudyFiero commented 8 years ago

Normally GPIO9 and 10 are used for the flash memory. When the flash is accessed in 4 bit mode these pins are used. Have a look at this schematic.

http://smarpl.com/sites/default/files/images/ESP8266-ESP-201-GPIO9-GPIO10-schematics.png

Your configuration above shows you are using quad mode so that makes use of 9 and 10.

If you need to use GPIO9 and 10 then read through this thread. http://www.esp8266.com/viewtopic.php?f=13&t=1216&sid=6bae8974defd709c2276dbb5d8ebca83

On the nodeMCU board you do not have access to the pins in order to modify the circuit so you can use GPIO9 and 10.

I would recommend using other available pins. GPIO 0,2,4,5,12,13,14,15 and maybe 16. 16 is a bit different. I have not tried 16 for I2C so I'm not sure that it works.

AnduriI commented 8 years ago

@RudyFiero thanks a lot for your suggestion. I tried again with my radio disconnected and only SCL at D3 and SDA at D4. This setup gives wdt reset:

void setup() {
  Wire.begin(0, 2);
  Serial.begin(9600);
  if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP085 sensor, check wiring!");
    while (1) {}
  }
}
 ets Jan  8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v60000318
~ld

 ets Jan  8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v60000318
~ld

 ets Jan  8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16 
tail 8
chksum 0x2d
csum 0x2d
v60000318
~ld

Any further hints? I'm a litte curious why the mcu also does a reboot if no SDA and SCL are connected only by calling wire.begin(). When using this code on an Arduino I get the correct message "check wiring".

RudyFiero commented 8 years ago

When I use Wire.begin(0, 2);
my connections SDA, SCL and based on the pin layout information for your board it looks like you have the SCL and SDA connections reversed. Without switching your connections, change to Wire.begin(2, 0);

And just to cover the bases I'll ask what pull up resistors you are using. I typically use 2k2 but I occasionally will use up to 4k7. 4K7 allows me to have a couple of 4k7 in parallel, one on the esp module and one on a connected board.

I always have SDA assigned to GPIO0. That way I can ground that line when programming without touching the SCL line. Without transitions on SCL then any I2C devices will ignore any activity on SDA/GPIO0.

AnduriI commented 8 years ago

Hey @RudyFiero, I tested both, Wire.begin(2,0); and Wire.begin(0,2); without success. I have a 4k7 at both lines as kind of standard pull-up. I also added a second set of them in parallel to bring them to 2ksomething, but still only wdt resets. Maybe I will redo it completely and take everything apart and start all over...

RudyFiero commented 8 years ago

It is really odd that you are getting resets. Maybe there is a line that is making an unexpected connection somewhere.

I have found that if the 3.3 volt supply doesn't have an adequate regulator and sufficient bypass caps that the ESP module can get resets due to the power supply dipping too low. But you have a decently made module so I didn't expect that to be an issue.

At this point I would do what you plan to do, and start over. Would you have another module that you can use in place of the one you have been using? Sometimes hardware fails. It usually is one of the last things I suspect but that is because I am a hardware designer and not a programmer. I have worked with a lot of programmers and many of them have a tendency to blame the hardware more than they should.

I hope you solve the problem soon. I know how frustrating it gets.

pasko-zh commented 8 years ago

First, the wdt reset is a result of your while (1) {} loop in your setup when you fail to "connect" to the sensor. (btw: I don't understand why this loop could make any sense there, but anyway....) Note that the software watchdog bites every 3.2 seconds, and the hardware watchdog after ~ 6 seconds (typically 7s or if you are lucky after 8s). btw: If you should ever need to disable the software watchdog and live with the hardware watchdog alone, you can do it like this:

system_soft_wdt_stop(); // disable the software watchdog
system_soft_wdt_feed(); //this feeds the software AND the hardware watchdog
// now, you can place your code here -- it has ~ 6 seconds until the hardware watchdog bites
system_soft_wdt_feed(); // feed again
system_soft_wdt_restart(); // enable software watchdog again

Or, as a simple example, the basic sketch is: (imagine busy_1second() is when your while loop executes for 1 second)

extern "C" {
    #include "user_interface.h"
}

int j = 0;
unsigned long a, b;

void setup() {
    delay(1000);
    Serial.begin(115200);
    Serial.println("Setup...");
}

void ICACHE_RAM_ATTR busy_1second() {
    unsigned int i, iterations;
    if (F_CPU == 160000000) {
        iterations = 13333332;
    }
    else {
        iterations = 6666666;
    }
    for (i = 0; i < iterations; i++) {
        asm(
            "NOP;"
            "NOP;"
            "NOP;"
            "NOP;"
            "NOP;"
            "NOP;"
            "NOP;"
        );
    }
}
void loop {
SEE NEXT ...
}

First, use for the loop:

void loop() {
    Serial.println("Getting busy in 3 seconds...");
    delay(3000);
    Serial.println("now!");
    system_soft_wdt_stop();
    system_soft_wdt_feed();
    system_soft_wdt_restart();
    for (j = 1; j < 20; j++) {
        a = micros();
        busy_1second();
        b = micros();
        Serial.println(b - a);
        if (j % 6 == 0) {
            system_soft_wdt_feed();
            Serial.println("HW Dog fed! Miam miam :-o ");
        }
    }
    // system_soft_wdt_feed();
    // system_soft_wdt_restart();
}

Aua! The Software Watchdog bites every 3 seconds!

Port open
Setup...
Getting busy in 3 seconds...
now!
1000039
1000012
1000000

Soft WDT reset

ctx: cont 
sp: 3ffef830 end: 3ffefa20 offset: 01b0

Now, we want to be bitten by the Hardware Watchdog instead, so:

void loop() {
    Serial.println("Getting busy in 3 seconds...");
    delay(3000);
    Serial.println("now!");
    system_soft_wdt_stop();
    system_soft_wdt_feed();
    // system_soft_wdt_restart();
    for (j = 1; j < 20; j++) {
        a = micros();
        busy_1second();
        b = micros();
        Serial.println(b - a);
        if (j % 9 == 0) {
            system_soft_wdt_feed();
            Serial.println("HW Dog fed! Miam miam :-o ");
        }
    }
    system_soft_wdt_feed();
    system_soft_wdt_restart();
}

Ouuuch!

Getting busy in 3 seconds...
now!
1000039
1000006
1000000
1000000
1000000
1000001
1000001
1000000

 ets Jan  8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1264, room 16 
tail 0
chksum 0x0f

Finally, we put the Software Watchdog asleep and are feeding the Hardware Watchdog every 6 seconds :-)

void loop() {
    Serial.println("Getting busy in 3 seconds...");
    delay(3000);
    Serial.println("now!");
    system_soft_wdt_stop();
    system_soft_wdt_feed();
    // system_soft_wdt_restart();
    for (j = 1; j < 20; j++) {
        a = micros();
        busy_1second();
        b = micros();
        Serial.println(b - a);
        if (j % 6 == 0) {
            system_soft_wdt_feed();
            Serial.println("HW Dog fed! Miam miam :-o ");
        }
    }
    system_soft_wdt_feed();
    system_soft_wdt_restart();
}

And hence now the loop runs forever, without any bites by the watchdogs:

Getting busy in 3 seconds...
now!
1000002
1000007
1000001
1000000
1000000
1000000
HW Dog fed! Miam miam :-o 
1000001
1000007
1000000
1000001
1000001
1000000
HW Dog fed! Miam miam :-o 
1000000
...

Second, if your sensor is not working with the wire library, you may give my own i2c implementation a try, I wrote it in assembly, so timing etc. should be correct, it's called brzo_i2c.. (You will have to adapt the i2c communication, but should not be that much of work ;-)

Third, since you are using adafruit's breakout board with an onboard regulator and those MOSFETs for the level shifting: It might be that this breakout board has the same hardware issures as the HTU21 breakout board, when using it with the esp8266 and 3.3V, see readme with brzo_i2c example.

pieman64 commented 8 years ago

Excellent information @pasko-zh Could I just ask you to describe what a software and hardware watchdog is i.e. the difference between one and the other.

pieman64 commented 8 years ago

@pasko-zh could I also ask about delay() in relation to soft and hardware resets. I thought I had seen a fairly official statement (Espressif ?) that delay should be no longer than 20 milliseconds. How does this tie up with your 3.2s / 6 to 8s?

pasko-zh commented 8 years ago

@pieman64 I will try to explain a bit more:

Software vs. Hardware Watchdog: Well, it is a terminology used in the context of the esp8266 (also, officially by esspressif). I don't know how they exactly implemented it or which circuit they are using. Obviously, there are two of them ;-) From the term "hardware" watchdog I am thinking of something like the MAXIM watchdog chips. So probably it is something in hardware, while the former lays in deep in the SDK (?) To me, it was rather confusing at the beginning, because nowhere it was explained how they both work together...

Watchdogs intervals : I did the above mentioned expirements a rather long time ago. Then, later, I did some googeling and I found this official statement by esspressif. That's why I know that the software watchdog bites after 3.2 s (I had just 1s loops in my tests, so I thought of 3s). Then, for the hardware watchdog resets, the tests gave 7s--8s, whereas esspressif talks about 6s. So, to be on the safe side I would go for 6s for the interval of the hardware watchdog.

Feeding the software watchdog: You can do it in several ways

  1. With Calls to the SDK, like system_soft_wdt_stop(); system_soft_wdt_feed(); system_soft_wdt_restart();
  2. Use delay(.), but note that delayMicroseconds(.) does NOT feed it!
  3. Use yield(), this does a context switch from user to system context, and in the latter amongst other things, the software watchdog is fed
  4. Everytime you iterate over your main loop, i.e. loop { .... } is called
  5. Maybe other options I am not aware of ;-)

Thus, you have to make sure that one of these options is uesd within an interval <3.2s. Now, imagine you have a rather "long" loop and you are doing some time consuming stuff, like for instance a wifi scan, then you should explicitly use something from 1. -- 3. I suspect that also in this issue it is the case, where the wifi_scan already takes around 2.1s, behind the scenes this is a call to one (!) SDK function, wifi_station_scan(.).

Timing: There are a couple of "timings" we should take care of, when programming the esp. You can find these in the SDK docu on page 15. And in there, you will find for instance "please do not occupy CPU more than 15 ms." Not that delay(.) can be as long as you want, it is not a busy waiting. My comment above (if you want to use the cpu longer than 3.2s) was a bit missleading in that sense, I will correct it, thanks for that.

krzychb commented 8 years ago

@pasko-zh, Very interesting and informative description on ESP8266 watchdog. :+1: Please consider adding it to documentation / FAQ, e.g. "Why ESP8266's watchdog is bugging me" :smile: Krzysztof

mkeyno commented 8 years ago

@pasko-zh do you have any idea what would be reason for long time hardware reset , for example my code works about 20 minuets and then reset

pasko-zh commented 8 years ago

@mkeyno, could you point me to your code? Without it, it's hard to tell. Is it an exception, or is it first a Soft WDT reset followed by Hard WDT reset?

pasko-zh commented 8 years ago

@krzychb Of course, I am happy to document it. Just some questions: Where should I place that info:

Thanks, Paško

krzychb commented 8 years ago

@pasko-zh,

cc: @igrr / @me-no-dev to step in if required.

This is great! I was thinking you could expand on your first and second post to create a new FAQ . People are frequently coming here discovering one or both watchdogs and asking why they are resetting ESP. The goal would be to describe why watchdog is in place and how to let it do his task. This is by structuring the code without resorting to ...soft_wdt... functions.

If this is too big task, then what about compressing your both posts into shorter / more formal description that would fit into a new section "Watchdog" under Reference.

Krzysztof

P.S. Love your asm insertions! Would not go too much beyond nop so not to freak out less experienced audience :smile:

pasko-zh commented 7 years ago

@krzychb, cc @igrr , @me-no-dev Finally (was busy with my "other work" ;) I've updated the FAQ section about WDT resets. Please have a look at my changes in the pull request

TS-Tec commented 7 years ago

Hello, I have the same Problem as @AnduriI Tried 3 different NodeMCUs and BME280 and SSD1306 with I2C. I also tried differnt sketches (I2C Scanner for example) and differnt wiring. All with the wire.h configuration. And with the same result: No functionality, sometimes resets...

Any ideas... Thanks!

pasko-zh commented 7 years ago

@TS-Tec :

  1. Are you using the NodeMCU Firmware or the Arduino Core? If it is the former, you may better ask your questions in the NodeMCU

  2. Is i2c not working in general or only with the two sensors BME280 and SSD1306? I.e. do you have at least one i2c device working?

SeppHansen commented 7 years ago

Hello,

had the same Problem like Anduril in the first post. I also tryed to use ESP12-E (NodeMCU 1.0) with BMP180 Pressure Sensor and Arduino IDE and get the same problems of bootloops after setting "Wire.begin();" in the Sketch.

I solved the Problem by updating the "Wire.h" file of the Arduino-IDE manually. My preinstalled Wire.h looked like that you can find in here: https://projects.cs.uaf.edu/redmine/projects/cyberalaska/repository/revisions/master/entry/include/arduino/libraries/Wire/Wire.h

and i replaced it with the Wire.h you can find here: https://github.com/esp8266/Arduino/blob/master/libraries/Wire/Wire.h

So in the Notes of the preinstalled Wire.h you can read that the last modification was made from Todd Krein in 2012!!! In the Wire.h from Guthub the last modification was done by Hrsto Gochkov and Ivan Grokhotkov in 2014 / 2015. The important addition is that the Wire.h has now ESP8266 support. Now everything works fine and without any bootloops.

kind Regards Sepp

devyte commented 6 years ago

Closing as user-error.

haleksandrov commented 6 years ago

To solve this problem I just comment while (1) {} in if (!bmp.begin()) { Serial.println("Could not find a valid BMP085 sensor, check wiring!"); while (1) {} } And now code continues working.

averri commented 6 years ago

I'm facing the same issue with ESP-8266 and the BMP280. I'm using the I2C scanner to test various sensors, and it is capable of finding the address of all of them, except the BMP280. I have checked the file Wire.h, it contains the modifications done by Gochkov in 2015.

assada commented 5 years ago

In my case: if i am connect bmp280 to gpio4+gpio5. Vcc and gnd on esp8266 - sensor not running. But if i am connect vcc and gnd to arduino(5v) and scl, sda to gpio4/5 on esp - its works! Looks like some power issue. But the tester shows me 5V on esp power pins.

spdi commented 5 years ago

My case: I use esp01s so run Wire.begin(2,0) and don't forget to pull-up CSB pin of BMP280 to operate in I2C mode, and decide what I2C address will be used: 0x76 when SDO connected to GND, and 0x77 when SDO connected to VCC.