Problem to reinit i2c bus after sleeping and power off

Hi,

I am trying to make low power with my arduino and have a problem with i2c bus. Here my config :

  • arduino mini pro modified (no regul and led)
  • BH1750 on i2c which is powered by P mosfet (bs250 for the moment)
  • sleep mode powerdown with pin change interrupt (no watchdog)

At starting, it reads well BH1750. Then I power off with mosfet, put A4 and A5 output=0, and go to sleep (my sleep routine is from Nick Gammon : sleep with pin change).

My problem is when I wake up from pin and power on sensor, I am unable to read again BH1750. It returns 0. In other hand, if i press reset button, it reads ok on startup. So I think I need to deal with i2c register config but I was wondering if Wire.begin does it as in BH1750 lib it uses (and arduino doc tells that it config registers). But it doesn't work for me. Maybe I need to restore another interrupt, but which one???

do you have any ideas about this?
Thanks for feedback.

The I2C is the hardest part for power down.

Did you read this: Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors
If you don't need analog inputs, you can turn off the analog section of the chip.
You could also reduce the cpu clock run-time.

I can't find information in the datasheet of the BH1750 what the power usage is. Does it have a sleep mode ?

Turning off I2C Slaves is not good. The pullup resistors keep the SDA and SCL high, and if a I2C sensor chip has no power, there will be current via SDA and SCL into the sensor chip to GND.
You could turn off the pullup resistors (I think that is what you do), but then the I2C bus is no longer valid. You might need a long startup sequence after that.
Could you show your whole sketch between code tags ?

The best option is to keep sensors and pullup resistors active. Try to put the sensor into a sleep mode. The resulting current could be only a few micro-amps.

I'm not sure what I remember about sleep mode for the I2C in the ATmega328P and the Wire library. I would expect a lot of troubles.

Did you also remove the yellow capacitors ? If they are bad quality, they can leak. I think one of them is connected to VCC. Running it on one or two 100nF capacitors is okay.

Do you know that an ATmega328P can read its own VCC ? You can read the battery voltage without external components.

@Peter_N : thank you very much for your reply.

I know BH1750 has sleep mode, and is low power (http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf).
I am trying to make a multi sensor battery powered for my personal use (if you want to see my schem you can see here https://github.com/scalz/MySensors-HW/tree/development/PowerManagementMysensors). It is still in dev. For the moment I don't use boosters, I am directly from battery. I test it step by step.

Yes I have already read this link. very useful! You are right, I am turning off pullups as mosfet is enabling/disabling 3v power rail and BH1750 has pullups. So when I turn off power rail, it turns off BH1750.
I am not using directly Wire. I use BH1750 libs and Mysensors. I could put my sample sketch here if you want to check but you would need libs. I need to make some cleanings before.

I think it is maybe a problem with registers or port pin config before and after sleep mode. I tried putting A4,A5 output=0, input_pullup before sleeping. Nothing better, still 0 reading.
No I didn't remove yellow capa. For the moment, I get sub uA when mosfet turn off (bh1750+nrf24).

The Wire library enables the internal pullup resistors for SDA and SCL.
You can turn them off after Wire.begin()

  Wire.begin();
  digitalWrite( SDA, LOW);
  digitalWrite( SCL, LOW);

Are those switching converters special low-power types ? Many of those converters use a few milli-amps idle current, but some use almost nothing.

Both RF modules are switched with VCC_RF. But where do the chip-selects and interrupts go ? The interrupts are tied together, I think that is not possible. The chip selects are idle high.

Did you read about waking up I2C on that page ? ( Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors ). It seems to be possible.
Perhaps you have to wait for a second after the sensor is powered on. Could you run the i2c_scanner after the sensor has power again, and see if the sensor is detected ? http://playground.arduino.cc/Main/I2cScanner

Peter_N thank you for helping me.

I have two mosfet : one for radio and one for vcc sensors. Interrupts are not tied together. D2 for radio, D3 for wake up. radio is working well.

Thanks for i2c links. I added scanner at startup just before my first reading of sensor. And added it just after power up mosfet. And it is very strange :

  • at startup all is ok, Lux = 140, and scanner reads 23 for adress
  • after woken up and turn on mosfet, delay (2000) : scanner reads 23 adress (ok), but lux = 0 ...
  • I disconnect anything, press reset button, and it gets Lux= 140 .....

I am asking me what happens when arduino resets that makes my sensors reading right...

The i2c_scanner does not use the buffer of the Wire library (no data is used). The address is put on the I2C bus and the ACK is checked. The problem can be the I2C hardware of the ATmega328P or the Wire library or the sensor.

The page from Nick Gammon ( Gammon Forum : Electronics : Microprocessors : Power saving techniques for microprocessors ) shows that the Wire.begin() is called again to re-initialize the Wire library and the hardware.
I don't know if it will always be allowed to repleatedly call Wire.begin(), but at the moment it seems neccassary to make the I2C bus work again.

@Peter_N : I found my answer. You are right there was a problem with i2c hardware config before and after sleep mode. Charles from ulpnode helped me on this.
How I solved my problem, in case people have same problem, before entering sleep :

     // Disable digital input buffers on all ADC0-ADC5 pins
     DIDR0 = 0x3F; 
     // set I2C pin as input no pull up
     // this prevent current draw on I2C pins that
     // completly destroy our low power mode
   
     //Disable I2C interface so we can control the SDA and SCL pins directly
     TWCR &= ~(_BV(TWEN)); 
   
     // disable I2C module this allow us to control
     // SCA/SCL pins and reinitialize the I2C bus at wake up
     TWCR = 0;
     pinMode(SDA, INPUT);
     pinMode(SCL, INPUT);
     digitalWrite(SDA, LOW);
     digitalWrite(SCL, LOW);

And in my Powerup :

power_twi_enable();

Thank you for your help!

Very strange ! But I'm glad you have it working 8)

The power_twi_enable() enables the I2C hardware in the Power Register.
So you don't call Wire.begin() again ? and it works :o

Perhaps you could do a dummy I2C session to be sure.

I know this is an old post but it made my day!
Thanks to scalz and Charles from ulpnode for the I2C reinit code, works like a charm to get my I2C LCD to wake back up after powering it off with a high side switch. :slight_smile: