Friday 2 March 2018

ZeroLiPo: Pi push-button battery power control

The ZeroLiPo is a Lithium-ion Polymer battery power manager for the Raspberry Pi from Pimoroni.

It does not handle battery charging, it simply converts the LiPo 3.7Volts to 5Volts, and provides a low voltage alarm.

Although I've had one of these for ages, I've only just considered using it, possibly for my Bat Call Logger.
The ZeroLiPo is a tiny board which Pimoroni say can be used either by being plugged into the Pi GPIO header, or by being soldered to header pins, allowing an expansion board to be able to be connected to the Pi GPIO pins.

But in the case of the Wolfson sound board used in my Bat Call Logger, neither of these options is going to work, as there is a conflict with the pins required by both boards.

However, the first step is to work out how I'm going to use the ZeroLiPo, and how I can control power on/off. If I'm going to try using my Bat Call Logger in the field, it will need to be headless and powered from a Lithium battery. So ideally I just want a push button to power the system.

Initially I thought it was going to be easy. I expected to be able to use a gpio output to hold the power on via the ZeroLiPo Enable input, and simply set the output low when it was time to turn the power off. However, once the Raspberry Pi had completed the shutdown process, the state of the gpio pins are mostly returned to their initial values.
Note: all gpio pin numbers referenced below relate to wiringPi numbering.
With wiringPi installed on the Pi 2 I was using for experimentation, I issued the terminal command:-

gpio readall

...which revealed the default states of the gpio;

wiringPi gpio readall

I initially tried using gpio22 connected to the ZeroLiPo Enable, as this is high as soon as the Pi is powered up. However, as soon as the shutdown command completed, the pin returned high and the Pi was held in a powered up state.

But there is one gpio pin that goes high when the Pi is powered up, and stays low (when set low) after shutdown: gpio15/TxD. So this is the one to use for the enable input (EN) of the ZeroLiPo.


Here are the main points;

  • use a single switch for both power on & power off
  • graceful shutdown using command: shutdown now -h
  • power off after shutdown
  • shutdown & power off if battery voltage drops below alarm level

This needs 1 Pi gpio output and 2 inputs.

power up/down circuit

Here is the development/test circuit;

ZeroLiPo Raspberry Pi power up/down circuit

From cold, pressing the button connects the battery supply (3.7V nominal) to the EN input via a silicon diode. This turns on the 3.3V & 5V supplies to the Raspberry Pi, and gpio15 goes high, holding the EN input high via a 2k2 resistor and a silicon diode. The 2k2 resistor is just there to limit gpio output current while the capacitor is charging. In practice, the capacitor is pretty much charged anyway by the time gpio15 is high.

The input voltage to gpio23 is limited to a safe value by the 10k resistor. Once my Gambas program is running, further button presses are detected via gpio23, which initiates the Linux command: shutdown now -h

My Pi 2 takes approximately 10 seconds to shutdown. Power is maintained on EN by the CR network (47uF & 470k) for about 18 seconds, and then it powers off.

While the system is running, if the battery voltage drops below 3.4V, the program powers down in a similar manner.

Note that the 2k2 resistor connected to Pi pin8 would actually be connected via pin8 on the ZeroLiPo board, since the 8 pin connector on the board blocks pin 8 on the Pi header. This is OK as pin 8 is not connected to any part of the ZeroLiPo internal circuit.

ZeroLiPo Raspberry Pi
only pins 1, 2, 6 & 7 are connected to the ZeroLiPo

the test software

Nothing remarkable here, just a simple gui using Gambas and wiringPi. The basic idea could be incorporated into whatever the target application is, whether gui or command line, and whether written in Gambas, Python or whatever.

wiringPi declarations:-

' Gambas class file

Library "/usr/local/lib/libwiringPi"

Public Extern wiringPiSetup() As Integer        'Initialises wiringPi & assumes the calling program uses virtual Pin numbers
Public Extern pinMode(pin As Integer, pud As Integer)   'sets Pin mode to either INPUT, OUTPUT, (or if applicable; PWM_OUTPUT or GPIO_CLOCK)
Public Extern digitalRead(pin As Integer) As Integer      'returns the input state (low=0, high=1)
Public Extern digitalWrite(pin As Integer, value As Integer)

Public Const PIN_OUTPUT As Integer = 1
Public Const PIN_INPUT As Integer = 0

Public Const LO_BATT_PIN As Integer = 7     'Lo battery (< 3.4V)
Public Const EN_PIN As Integer = 15         'Enable battery power
Public Const OFF_PIN As Integer = 23        'start or shutdown required (switch closed)

Using a 1s timer to check switch and alarm status:-

Public Sub Timer1_Timer()
  If digitalRead(LO_BATT_PIN) = 0 Then  'battery < 3.4V
    digitalWrite(EN_PIN, 0)
    Exec ["sudo", "shutdown", "now"]
  If digitalRead(OFF_PIN) = 1 Then 
    digitalWrite(EN_PIN, 0)
    Exec ["sudo", "shutdown", "now"]

Note that command "shutdown now" is actually the same as "shutdown now -h" as this is the default action.

the Wolfson sound card problem

The Wolfson sound card is used on my Bat Call Logger, and its a bit of a hack anyway to get it wired and working on a Pi 2 or a Pi 3. As this card sits on the 40pin header of the Pi, it is difficult to see how the Zero LiPo can also be connected to the system to allow battery power to be used.

I thought about cutting the track to pin 7 (which is the only conflicting pin) on the Zero LiPo, so I could use the board as a 'shim' between Pi and Wolfson. It would then be necessary to solder a wire from the Zero LiPo alarm to a suitable free pin on the Pi. This may work, but I still have a mechanical problem with the Wolfson 'pogo pins' which would contact with the Zero LiPo.

The other idea was to use the Zero LiPo mounted free from the Pi/Wolfson combination. This would mean running wires for +5V, +3.3V and 0V between boards, in addition to the low voltage alarm, the EN and BAT+ leads. Very messy!

So for this application I probably need to look for an alternative battery management solution.


  1. Hello Steve,

    I implemented your ingenious schematics (exactly as it is) between ZeroLiPo and Raspberry Zero WH. Regarding scripting, I modify Pimoroni's original cleanshutd bash script.

    Currently, all signs are that it will work as described, just few details I must find out, like default status of RPi Zero's pins at boot.

    Your "gpio readall" output shows enable pin 15 assigned function ALT0 with status 1. On RPi Zero after booting up Enable pin 15 is always INPUT, but sometimes it is in state 1, sometimes 0 - I did not catch the rule yet).

    Here is a question:

    Did you maybe in your gambas script somewhere at the beginning set Enable pin 15 as OUTPUT and drive it HIGH?

    With best regards,

  2. Hi Goran, no I don't think so because pin 15 seems to be in the required mode as the system boots, whereas there is a delay (due to boot time) before the Gambas program can set/reset any i/o.

    It seems a long time since I've played with a Pi so I'm probably not much help. However, I seem to remember that you can set serial port in the /boot/cmdline.txt file, so maybe my config was different to yours (e.g maybe the OS image settings have changed since 2007/8 or something). Maybe take a look at the "console=tty1" stuff on my post about Serial Comms & PHP, and try to work it out from there. Cheers.

  3. Hi Steve,

    just to report the circuit works like a charm now. In the meantime at the beggining of the script I configured pin 15 as output and set it high.
    On RPi Zero WH I have Raspbian Buster Lite (headless) installed. It needs 12 seconds to shutdown, then additional six seconds to power off (actually, as I didn't have 47uF/470k combination at hand, I put 22uF/1M which gives the same RC constant practically).