Reconnecting to I2C device after powering off

Hi

I have an arduino with a couple of I2C sensors which I am connecting to my Arduino. I am using this library and this library to interface with the sensors.

I have tested these devices and they work fine during typical usage. However, in my particular use case the sensors will only be used intermittently and so, in order to save power, I am powering off the sensors when they are not used (the power line of the sensor is connected to an arduino pin so I just write to that pin to turn on/off).

I was wondering what the correct procedure is to interface with the sensors?

  1. Have a global sensor object (Adafruit_VEML_6075 and Adafruit_BME_280).
  2. Call begin() on these objects during setup()
  3. Each time I want to read the sensor, power up the sensor (by writing to the arduino pin) and then read the values.

Will this work even if in (3) begin() has not been called after powering up the sensor? i.e. do you have to call begin() each time after powering up the sensor or can you just call once in setup()?

I have noticed that in Adafruit_VEML_6075 there appears to be a memory leak because each time I call begin() it uses new memory which is not released. This was causing my program to crash. This is how the begin() function starts in Adafruit_VEML_6075:

boolean Adafruit_VEML6075::begin(veml6075_integrationtime_t itime,
                                 bool highDynamic, bool forcedReads,
                                 TwoWire *theWire) {
  i2c_dev = new Adafruit_I2CDevice(VEML6075_ADDR, theWire); // dynamic allocation but not clear where released

Alternatively, should I place the sensor object in the scope of the sensor read function and then call begin()?

Any thoughts appreciated.

Thanks

There is no correct procedure, because you should not do that :see_no_evil:

The idea is that the constructor sets a few main things, and the .begin() function actually starts to communicate with the device. But not every library is like that, and I did not check all the libraries that you use: Unified Sensor, Adafruit_I2CDevice, Adafruit_I2CRegister.

The Wire library itself has a .begin() and a .end(). You can call Wire.end() to stop the I2C and Wire.begin() to start the I2C bus as many times as you want.
Sadly, those sensor libraries don't have that.

Let's go back a little. What is the goal ? Which Arduino board do you use ? How much current do you want to reduce ?
Some sensors have a sleep-mode. Suppose your project needs 50% more time and effort to reduce the power by 0.000001%. That would be wrong.

Things you could do:

  • Measure the current after putting the sensor in sleep-mode. Don't think about saving current until you actually know the current.
  • Use other libraries or write your own code that can easily initialize the sensor.
  • Ask Adafruit to add a .end() function to the sensor classes. They probably will start laughing when you want to safe 100 nA.

VEML6075: shutdown current is 800 nA.
BME280: sleep current is 100 nA.

It is less than 1 µA that you can reduce. You are probably wasting a magnitude of that current elsewhere in your circuit.

What do the docs say about power usage and sleep modes? What do they draw just staying ready?

Power-up is going to take time, I2C devices have controllers just like SD cards.

bme280 used on the board

There is a sleep mode.

Actually 1 µA is pretty significant as I have managed to get the board down to 70nA without the sensors. I am aiming for ultra low power.

So I've carried out some tests where I leave all the sensors running rather than shutting them down when not used:

  • sensors turned off: 0.07mA (i.e microcontroller in sleep mode)
  • with BME280 and VEML6075: 0.026mA
  • with VEML6075: 0.12mA
  • with BME280: 0.21mA

For the BME280, I have put this in FORCED_MODE. For the VEML6075, I have included shutdown(true).

The difference between leaving the sensors on (0.26mA) and turning them off when not used (0.07mA) may seem small but it is almost 4x.

Thanks

1 Like

I'm investigating whether this consumption is caused by the onboard voltage regulator.

You turned sensors ON/OFF by software command and not changing wiring, right?
Then put the MCU to sleep?

Only happens when you power the board through the power jack, and may be a 7805 or Buck converter depending on the board. USB power does not get regulated by the Arduino. You can feed regulated 5V directly to the board through 5V and GND, but take care to not source or sink more than about 200mA total through the pins or sustain source or sink 25mA though just one pin.

Perhaps say why such low power is an objective ?

At 1uA, a set of humble AAA batteries would have a theoretical life of 114 years or so, but will likely self discharge in 5 years or so. So for AAAs once the sleep current is below around 5uA, there is no significant impact on actual battery life.

Basically correct.

(1) Send a software command to ask the sensor to go to sleep. For BME280 this is effectively by putting the sensor in "forced mode" (i.e. take a reading when asked and then go to sleep). For VEML6075, I call the shutdown method.

(2) Put the MCU to sleep

I wasn't clear - I meant the voltage regulator on the sensor. I think most sensors have voltage regulators to allow a range of inputs. I have bought a 3.3v only sensor with no voltage regulator so I will see if this makes a difference.

Either you have one with a VR or you don't but linear regulators have to drop a volt or two to run properly -- Arduino Uno power plug needs to be at least 7V to get 5.

ATmega328P can read 2.8V to 5V signals without a regulator.