robert-hh / BME280

Micropython driver for the BME280 sensor, target platform Pycom devices
Other
104 stars 27 forks source link

Investigating forced mode for maximum power saving #2

Open amotl opened 4 years ago

amotl commented 4 years ago

Dear Robert,

first things first: Thanks for conceiving and maintaining this MicroPython library for the BME280. We have been using it successfully within the Terkin-Datalogger.

Introduction

Within BME280 optimaler mit MicroPython ansteuern, we have been investigating whether the BME280 sensors will actually be put into sleep mode after taking a measurement.

Best practice for low-rate applications aiming at maximum power saving is the designated forced mode this sensor can operate in. When this mode is enabled, the sensor will immediately go to sleep mode without further ado after being "forced" to run a single measurement.

This detail has been brought to our attention by @weef within Strom sparen beim Einsatz der MicroPython-Firmware im Batteriebetrieb, where @MKO1640 and @ClemensGruber measured the power consumption of different subsystems of our appliance.

While setting this mode by manipulating the control register is invoked before taking a measurement through

https://github.com/robert-hh/BME280/blob/a7074fd2d5a140a14957dbb7c6f247f975a6dcfa/bme280_float.py#L120-L122

we have been confident that this is implemented correctly.

image

Saying this, it was not obvious when looking at the code first hand, we might want to use a respective MODE_FORCED constant here on one of the next iterations.

Investigation

However, after coming back to this, we see that the sensor is put into normal mode after starting up --

https://github.com/robert-hh/BME280/blob/a7074fd2d5a140a14957dbb7c6f247f975a6dcfa/bme280_float.py#L98-L99

-- further, we recognize other libraries are doing it differently because people have been telling each other that writes to the config register may be ignored while in Normal mode.

We published the outcome of our investigation to https://community.hiveeyes.org/t/bme280-optimaler-mit-micropython-ansteuern/2397/27.

What do you think about this? Thanks already for taking the time to look into that.

With kind regards, Andreas.

robert-hh commented 4 years ago

At the moment I have no opinion about that topic. As you can see in the comments at the top of the source, this driver has quite a history. And my contribution until now was to port it to MicroPython and to check and remove small calculation errors in the compensation formula. And yes, I wrote a short documentation. But I can look into that topic and compare it which what the data sheet tells. The code you pointed at is indeed setting forced mode. Did you try to set forced mode at startup?

P.S.: It's no big deal to use constants for FORCED_MODE and NORMAL_MODE.

robert-hh commented 4 years ago

Looking into the code, there is just one method for reading. So it is no problem to set-up the sensor in sleep mode. The code change is minor, I just have to test it.

robert-hh commented 4 years ago

I made a comparison of starting up the sensor in sleep mode vs. normal mode. I cannot tell a difference. According to the data sheet the difference is 0.1 µA (0.1 in sleep mode vs. 0.2 µA in the sleep phase of normal mode). The standby current I see is 6.9µA. This is probably caused by the regulator on the breakout board I use for testing. During measurements, the average current increases to 300 or 500 µA, depending on the oversample number. Nevertheless, I prepared and version using symbolic names for the power modes.

amotl commented 4 years ago

Thanks a bunch for looking into this! Maybe @thiasB, @poesel, @ClemensGruber or @wetterfrosch will share their observations with us regarding power consumption.

wetterfrosch commented 4 years ago

Not taking the power-aspects into account I want to make a remark from the meteorological point of view: The BME280 creates some noteworthy self-heating of around ~ 1°C in MODE_NORMAL, so the suggestion is to put it in MODE_FORCED and do just a measurement every minute or so.

To my understandig: The data comes in both modes from the same register, using Adafruit_BME280.h one has to call bme.takeForcedMeasurement(); in order to trigger a new measurement and get those results stored there.

robert-hh commented 4 years ago

So I removed the regulator and repeated the test with my python script. When initialized in NORMAL mode, the standby current is about 600µA. When set to SLEEP mode, the standby current is ~0.15 µA. The driver now sets the devices to SLEEP mode. Taking a new measurement is using forced mode and resets the driver to sleep.

wetterfrosch commented 4 years ago

I just stumbled upon a view showing what happens "if you're doin' it wrong!": In this sketch (done in C) I set to FORCED-mode /after/ connecting to WLAN. Then I interrupted the uplink (ESP goes into a WLAN-try-to-reconnect-loop) and during that time (<4minutes) the sensor was the whole time in NORMAL-mode (ok, to be fair: close the then not deep-sleeping ESP8266, but the ESP was for reasons of thermal convection at least above the BME280 located):

image

robert-hh commented 4 years ago

I noticed that the sensors are pretty sensitive to placement. When doing my tests, I placed them, if possible, in a certain distance to the CPU module and below that level. Even on my desk, shifting them around by 20-30 cm could change the temperature by up to 1 °C. But 3 °C is a lot. I wonder if that can be cause by the power used in forced mode. Forced mode consumes, as far as I recall my test, about 500µA. At 3.6V this is about 2 mW. The thermal characteristic of the package is not specified. But for 3°C that would be 1500°/W. That's quite a lot.

wetterfrosch commented 4 years ago

No wonder, if you sat at the same time that desk, too ;) Jep, I think the during-that-period-always-on-CPU-temperature played it role there, too. When I find a moment I'll try to make some "isolated" tests (with the CPU far, far away).

Here a picture of this forbidden engineering; to avoid influence of the CPU-temperature the ESP goes into deep-sleep and wakes up every minute (and get only a max. time of 10 seconds for connecting to WLAN -- if this doesn't succeed it goes deep-sleeping for 50s).

image

amotl commented 4 years ago

Coming back from the meteorological details to the power consumption aspects, I just found 732b21fd by @olivluca. It looks like he was on to something here.

However, this has been some time ago already and might have been mitigated by 3bc048f9 already.

robert-hh commented 4 years ago

This setting was changed in the actual state of the repository. The device is initialized to sleep mode. The lines below are use in both variants of the driver.

        self._l1_barray[0] = self._mode << 5 | self._mode << 2 | MODE_SLEEP
        self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
                             self._l1_barray)
robert-hh commented 4 years ago

@wetterfrosch: The way you have soldered the BME280 to the ESP32 board will cause the BME280 to get heated by the ESP32. The ESP32 board gets a warm, and that will propagate to the BME280 board.