Unstable system when controlling power to serial peripheral devices and sleeping In the process of trying to make a small system that will last a while on 4 AA batteries, I've reduced my Arduino project to a barebones system that when asleep draws a tiny amount of current from the batteries.

However, to achieve this, I found it would be necessary to cut power to the two attached peripheral devices (connected to an ATMega328P-PU). One of them is an I2C device, and the other is a serial device, and both are attached to the hardware serial/I2C pins as appropriate.

In terms of powering the peripherals, the bases of two transistors are connected to two of the digital pins, and power to them is controlled from code via these transistors. Both devices are 5V, and when the system is running the total current draw is around 200mA.

Basically this setup works, however I'm getting "random" system hanging and essentially an unreliable project. Sometimes when I power it up it will work as normal, but then hang and not sleep. Other times, it will sleep, but then freeze after waking or just get stuck during waking (which I can tell because the serial device powers up first and does nothing, but the I2C device remains off).

My best guess is the root of the cause is either something to do with the serial communication being interrupted by sleeping the MPU (I'm using the maximum power saving sleep, which is woken by an external interrupt on pin 2), or possibly some sort of power problem (sudden current draw from battery?) that occurs when the peripherals are powered on in code (though I don't know how I should test this).

So far, I've tried calling Serial.end() before sleeping the MPU, and Serial.being(9600) on waking, and have scattered delay(1000)s throughout to ensure everything has enough time to get running, but the problem still remains.

Does anyone have any pointers on things I could change/test, or an alternative approach I could take to make the same power savings?

EDIT: Some more details

The transitors used are TIP 120's. The connections are essentially an exact copy of the image here: https://ctheds.files.wordpress.com/2007/10/tip120.jpg, except the resistors used are 560 Ohms (just what I had to hand, no other reason, didn't think it would change anything). 

The I2C peripheral is a 20x4 LCD (which I believe is HD44780 compliant). The serial device is an GT511C3 fingerprint sensor. I don't believe either of them have any automatic power saving features, though I haven't looked for such things in the documentation explicitly.

The exact code I use to call sleep is

set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();


which I'm lead to believe is the lowest power mode, and aside from this problem works well for my system.
Using an NPN transistor to control power to a peripheral may be problematic.

An NPN transitor would presumably be used as a low-side switch interrupting the peripheral's ground line, however, even when turned on this will have a non-trivial voltage drop.

Most logic level definitions are asymmetric, ie, the maximimum legal voltage for a logic "0" is relatively low. If you insert the voltage drop of a bipolar transistor into a peripheral's ground line, then it may be borderline unable to drive a fully legal '0' to the ATmega, which is reference to the lower true ground and would see the peripheral's ground difference added to its output voltage.

A better approach would be to use either a high-side switch (as there is typically more room between the minimum legal '1' and the supply) or else to use an FET switch which would have a much lower voltage drop. 

Also keep in mind that most IC's are not specified to tolerate lasting I/O voltages much outside of the range of their power suppliers, and in fact their protection diodes may mean that application of such voltages effectively powers them through the I/O pin.  So before turning off power to a peripheral, you probably want the ATmega software to assert all shared I/O lines towards the side of the peripheral supply which is not being disconnected, ie, for a low side switch drive everything high and for a high side switch drive everything low.

Finally, the process of power cycling could potentially confuse peripheral interface engines and it is possible that some error flags set in this process might never be cleared.  So you may want to clear the flags of and generally re-initialize your USART, I2C, etc on resume.