I like working with the Pi Zero W and Pi 4 as they are very compact, very powerful and very cheap for the capability they offer. I want to use them on small projects, stand-alone, and can't always guarantee power. As we know most Pi's don't like suddenly being turned off. Microcontrollers are much more able to handle this environment.
I didn't want a UPS, I just needed to buy enough time for the Pi Zero to shut down in an orderly manner, then importantly when power is restored to start up again and keep running.
I could not find a product in a reasonable price range to do this, especially if I wanted to automatically restart once power is restored. I also needed a challenge to help me learn about the Pico.
Along comes this new micro controller, the Pi Pico, very cheap, very powerful and importantly very easy to get up and running and has many features to boot. More importantly it has lots of resources, many of which are still available once this project has been implemented.
To give access to the unused resources on the Pi Pico I created a simple ASCII based serial interface.
This project is to safely control power to an external device. It will give a warning when the main supply has failed, and if the battery voltage drops below a safe threshold. It will maintain the supply to an external device for a preset period, during which time the external device has sufficient time to perform an orderly shutdown. Power is then removed completely. Once power is restored to the Pico it will in turn be switched back to the external device as long as the thresholds are all met.
The code in this project for the Pi Pico is written in Micropython.
The main components are:
- Raspberry Pi Pico,
- LiPo 3.7V battery
- boost/charger module
- Power P-Channel MOSFET to drive the external 5V device
- FTDI Comms interface for serial communication [Optional]
- Pi Zero W running the blink application and an LED mounted on one of the GPIO outputs
Note to prospective builders: While this device is functional and versatile there is still plenty of opportunity, if you are up for it, to modify the application and functions and create new ones.
The basic supply and battery warning signals will work straight out of the box using the default settings. The serial interface can be used to tune the way the Pi Pico operates.
There are still quite a few debug messages embedded in the code, when you have it working the way you like, feel free to remove them to clean up the output.
Future development suggestions if you are up for it:
- Time Clock/Scheduler to remotely power cycle the external Pi on a Time Of Day plan
- Additional Serial commands to suit your own purpose, including to manage to Time Clock
- Implement beacon mode where it regularly broadcasts the status to the serial interface
- Implement a watchdog functionality, i.e. it requires a periodic input from the external Pi to reset a timer, if the timer expires it performs a restart of the external Pi
- <Insert your own idea here>
Bill of Materials
- 3 x Resistor 10K 1/4 W 2%
- 3 x Resistor 6K8 1/4 W 2%
- 1 x Resistor 300R For Green LED connecting to 5 V
- 1 x Resistor 68R For Red LED connecting to 3V3
- 2 x Capacitor 0.1uF Ceramic Decoupling
- 1 x Capacitor 1uF 16V Reset timing
- 3 x Capacitor 10uF 16V Power Smoothing
- 1 x Proto Board SB400 "3.00 x 1.90 in (76.2 x 48.3mm), 1/16"" thick (1.6mm) 540 holes, 0.042"" holes are drilled on 0.1"" (2.54mm) centers."
- 1 x Raspberry Pi Pico with soldered headers Can purchase without pins and solder on yourself
- 1 x Charger/Booster Capable of supplying 1A 5V
- 1 x LiPo 3.7V Battery 1200mA Battery capacity to suit your requirements
- 1 x USB Comms interface 3V3 Mainly needed for development
- 1 x LED Red Optional Indicator only - External supply lost
- 1 x LED Green Optional Indicator only – safePower On
- 1 x LED Blue Optional Indicator only – LiPo battery voltage low
- 1 x PushButton N/O Reset pushbutton
- 2 x Female Header 20 x 1 To mount the Pico on the proto board
- 1 x Female Header 3 x 1 For connecting the Charger/Booster
- 1 x Female Header 2 x 1 For connecting the Charger/Booster
- 1 x Male header strip 5 x 1 For connecting the FTDI comms module
- 1 x Power MOSFET P-Channel 35A IRF9540 Power switch
- 1 x Transistor BC546 MOSFET driver
Additional for external device test Led
- 1 x Resistor 68R For Green LED connecting to 3V3
- 1 x LED Green Optional Indicator External Device
- 1 x (2 x 20) Pin connector Female to suit Pi 40 pin connector
Additional consumables that you probably have lying around
The heart of the project is a Raspberry Pi Pico. Its key functions in this project are to:
- Monitor the supply and battery voltages
- Control the power MOSFET’s switching of the safe 5V power supply
- Manage the serial comms interface
- Remembers any config changes made and reapplies on a restart.
- And any other functions of your own inclusion.
This is a 3.7 volt LiPo Battery. It does not need to have a very high power rating, but just make sure your Boost/Charge module supports the battery you are using.
As a minimum, the battery needs to be large enough to support the target external Pi, but not necessarily the complete project. It only needs to support the external Pi for the time it takes for it to perform an orderly shutdown. This is usually around 15 seconds but does depend on your application. I used a default of a 30-second shutdown timer and I used a convenient 1200 mAh battery which is more than up to the task. I will try a 400mAh battery shortly on the simple Pi Zero W test external device detailed in this project.
There are many Boost/Charge modules on the market. For the purpose of this project these modules allow you to charge a LiPo battery from the incoming supply while providing a 5V DC output to run an external device. If the incoming supply is removed, then the 5V DC output is derived from a boost circuit running from the battery.
This module is a key part of the project and you need to check a few specific points when selecting one.
- Access to 5V from incoming mains supply
- Access to V+ from the battery
- Access to 0V, typically the 0V on the supply is directly connected to the V- from the battery and the 0V on the charger output. i.e. they have a common 0V.
- It is handy to know if the module will provide a 5V output if the supply is connected but the battery is not. The Sparkfun module I used, PRT-14411, would not supply an output voltage if the battery was removed but will still operate as the battery voltage drops. This is not a showstopper as long as the battery threshold is high enough, but something to be aware of.
- I also considered a DFRobot Charge/Boost module [DFR0446] and it does not give ready access to the incoming 5V supply. I considered a pair of USB connectors that can make a very short extension cable and allows to break out the incoming 5V supply. At the time of writing this document I have not attempted to build this cable, but it is still on my ToDo list.
This P-Channel MOSFET is the main power controller for switching 5 V DC to the external device. More importantly, it also removes power from the external device, this enables the external device to restart normally and cleanly when power is restored.
This power MOSFET is capable of switching up to 23 A at 100V and comes in a convenient TO-220 package. It is far more powerful than is needed for most projects, but it is cheap and easy enough to source.
In order for the MOSFET to switch on, the MOSFET requires at least -5.0 V from Gate to Source. As this is a P-Channel device Vgs is expressed as a -ve voltage since the source pin is at a higher voltage than the gate pin.
Vgs for this device can be significantly higher than 5V and it works quite happily but I would not go much lower than 5 V as it may not fully turn on and then would not deliver sufficient power to the external device. Please consult the datasheets for more details, there are many freely available on the internet.
Note: as the source is at 5 V it is not safe to drive it directly from a Pi and the even if it could it is not likely is can fully switch off the FET. I get around this by using a simple BC546 NPN transistor as a switch to drive the FET. You can use whatever NPN small signal transistor you have lying around just make sure the resistor values are suitable for your choice.
FTDI Comms Interface
This is used as a simple interface to convert from a USB port to the 3.3-volt serial comms interface on the Pi Pico. I use RealTerm on a Windows PC to send commands to the Pi Pico and receive responses. It is intended that the external device could monitor and manage the Pi Pico, but it is really up to you.
Note the baud rate in the picture, 115200, I also use 8bit, no parity, no handshake.
External Test Device
This is only used as a test ‘external device’ to demonstrate the project’s operation, I choose a “Pi Zero W” as I had a couple lying around, but any external device utilizing a 5V DC supply within the capability of your Charge/Boost module is suitable.
I loaded a simple blink.py application to flash a LED mounted on the 40 pin connector. This is to give a visual indication that the Pi is running.
Note: The 5V output of the SparkFun LiPo Booster/Charger can supply around 1 Amp, more than enough to run the Pico and an external Pi 4 or Pi Zero. I am assuming any significant load controlled by the external device is external to this project, this is just to give the external target time to shut down cleanly.
[Depending on the load that the Pi 4 is under load can exceed 1 Amp of current draw, the power requirements for each Pi are available here.]
Interface to the Protected External Device
In addition to the 5V supply to the Pi Zero W, there will be 2 hardware signals, one to indicate supply has been lost and a second to indicate the battery voltage is dropping low.
These outputs are Active Low from the Pico and will stay low as long as the trigger condition is active.
Theoretically, either or both of these signals can be used to trigger an interrupt on the external device so it knows when to shut down. Use the falling edge to trigger an interrupt.
The LiPo battery does not need to be large and expensive, the system is flexible as it can initiate the shutdown procedure as soon as the main supply is lost, or wait until the battery level drops significantly and thus ride out short term power outages.
This demo code version will trigger from loss of the incoming 5V supply voltage.
I have provided a basic serial interface to monitor the Pi Pico’s status and give access to the unused I/O resources. It just uses ASCII text for the commands and responses, but there is a binary header and a count byte that precedes each command and response message.
There is a separate document to detail this interface’s functionality. You do not need to implement the serial interface in order to use this project, it just opens up additional capability and resourcing.
How it works
The basic operation of the code on the Pi Pico is reasonably straightforward
From power-up, the Pico will set the Trigger outputs to be inactive [High] and disable the 5 V safePower output.
As it enters the main loop the monitored supply and battery voltages are sampled and evaluated and if all is good, the safeVoltage will be enabled thus powering up the external Pi. The main loop continuously evaluates the incoming voltages and processes them accordingly as well as looking for serial commands to execute.
The main loop is a forever loop.
When the Pico shuts down the safePower to the external device, it does not shut itself down but will keep running as long as the battery is able to keep up the 5V supply. In this shut down mode, the Pico is cycling through ‘power up, sample the voltages, if below configured thresholds, it will execute the shutdown timer again, then reset itself’ and repeat. This will continue until the battery runs out or the external supply is restored.
The test setup including the Pi Zero W running the blink application, typically this setup draws 160 – 180 mA, the majority will go to the Pi Zero W.
When the external supply is restored the initial current draw will be higher as it charges the battery.
I used the same voltage divider for both external monitors [External Supply and LiPo battery voltage], so there is one less calculation needed.
The voltage divider consists of a 6K8 and a 10K0 resistor. The divide ratio is 10K / 16K8 = 0.595. So 5.2V -> 3.094 V. In the code the voltage read in is scaled up by the reciprocal of 0.595 which is 1/0.595 =1.68, i.e. 3.08 * 1.68 = 5.2 [pretty close to 5.2 but slightly lower with some rounding error] I tweaked the conversion slightly to 1.782 so it would line up with my Digital Multi Meter, this is due to tolerances in the components, the accuracy of the Digital Multi Meter, etc …
A Problem Encountered
One issue did plague me for a while, after a variable period from 5 minutes up to 8 hours the Pico would suddenly hang or freeze. After many print statements I tracked it down to the time.sleep_ms(333) statement. I reran the code multiple times as it always hung on this statement. I changed from the time module to the utime module but it made no difference. After a few google searches I tried disabling the timer function used to trigger a callback to reset the comms interface. Once I disabled the time function the Pico just kept running with no more freezes. Rather than delve too deep into the code behind the Timer function, I just re-coded the trigger for the comms interface reset. It is not as nice as using the Timer callback, but it works and is reliable. Problem averted by a workaround.
This could be an upgrade to the original project so as not to put too much into the first part.
I kept thinking of all the capability on the Pico that is unused, all of those GPIO ports, there's still one ADC channel free, an internal temperature sensor, and lots of processing power.
I have developed a simple ASCII-based comms protocol to expose and utilise the free resources, such as GPIO pins ADC channel, Internal Temperature, to adjust the Power supply and Battery low thresholds. I was also thinking of building in a hardware watchdog timer so the external Pi Zero W could be reset if it hangs, the watchdog could be reset by toggling one of the GPIO inputs through a specific comms message. The Watchdog timeout is also configurable.
Possibly this should be two or more projects, one with and one without the serial functionality.
Building the Pi PICO controller
These are pictures of the constructed proto board containing the Pi Pico and most of the other discrete components, note there is sufficient space to place components and wiring under the Pi Pico.
This is the Sparkfun Charger Booster module, note the additional blue wire on the underside to give access to the battery +ve rail.
- Build the hardware according to the schematic attached and view the photos for potential layout options, make sure you verify the connections before you apply power. Always important to do this while the big components are not connected [big components are usually the expensive or sensitive components].
- I usually check there are no short circuits across the power rails.
- Key supply rails are where they need to be
- Check that all of the connections are where they need to be and check any adjacent pins to make sure they are not connected
- When you are satisfied, connect the power with the big components still removed, and make sure you have the right voltages where they should be.
- When you are satisfied the hardware is correct, power down, plug in the big components and power up. If all is well, no smoke will escape
- It is intended that this project would be incorporated into a bigger project of your own design so I will not detail any enclosures or physical construction, it will really depend on your intended application of this project into your own projects.
Programming the Pico
You will Need
- The Thonny IDE. If you are not familiar with Thonny IDE, there are many tutorials available to help you download and get started.
- Text editor of choice, or you can use the Thonny IDE.
- Supplied files:
What to Do
- I use the Thonny IDE to test and load the code onto the Pico
- There are two python applications that need to be copied across to the Pico, they are main.py and safePower.py
- main.py is always executed automatically when the Pico powers up, it is just used to call the main application in the safePower.py file.
- After you have first run the safePower application you will notice there is a third file present on the Pico, it is called ‘config_safePower.json’ and contains the config settings. [note: It is a text file, so it is human readable]. If the config file does not exist, it will be automatically created and every time you edit the config settings using the serial interface, the config file will be automatically updated. This file, if it exists, will be automatically uploaded at each restart.
- I have included a fair amount of commenting in the code, hopefully it is sufficient to understand how the code works.
Setting up the Raspberry Pi Zero W
- Copy the two files, blink.py and shutdown.py, to the /home/pi directory on your Pi Zero W. blink.py is only required for testing, once you’re happy all is working you can remove blink.py and delete references to it in the rc.local file, but leave the shutdown.py
- blink.py is a simple test program to blink an LED, it gives a visual indication that the pi zero is up and running. Run it manually and the LED should start blinking. Use ^C to exit.
- shutdown.py is a basic python script that will shut down the pi cleanly using the system command shut down.
- Run chmod +x *.py as the pi user in the pi home directory, /home/pi. It should look similar to the screenshot below
- Edit the /etc/rc.local file to include the two python scripts provided, it should look similar to the screenshot below
- Next, you will need to restart the Pi Zero, issue the command sudo init 6, it should break the connection to the terminal straight away, the restart will take a couple of minutes and the LED on the Pi Zero should start blinking automatically
- Verify that both scripts are running in the background using the command ps -ef | grep <script name>
safePower by Tim Drew is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
Based on a work at https://drive.google.com/drive/folders/1yu9icKCF2r0xxRuEQV18DIimthvGBxx9?usp=sharing.