A friend and I designed a UPS for the more power hungry Models. Have a look here :
viewtopic.php?f=29&t=192959
[Edited diagram and text]
Following previous designs for my RPi, in particular the one-button-start-stop method, and several UPS based supplies, I wanted to see if I could combine the two and make it more simple and advanced at the same time.
The one-button-start-stop solution can be found here
viewtopic.php?f=91&t=129357
My latest UPS based supply can be found here :
viewtopic.php?f=37&t=132201&p=882125#p882125
In the previous designs I stayed away from Li-ion type batteries due to the complex charging mechanism and the risk of mishaps when you get that part wrong. However, in order to reduce size these 3.7V cells are the way to go if you can make them work.
The time was right to give that a try. In my earlier designs, I used a diode OR to combine the 5V coming from the wall-wart and “mixing” that with the voltage coming from the battery. This voltage was then fed to a Booster-Buck board which boosted the mixed voltage to about 8V and then reduced (Buck’ed) it to the 5V1 going to the Pi.
I found a couple of Li-ion charger boards and controllers, and ordered a couple of li-ion cells so I thought I was off to a good start. It was really easy to get the charging portion right and learn more about the charging sequence, the over voltage protection and the end-of-charge point.
Unfortunately, I struggled to use the single Li-ion 3.7V cell in my original power supply and switch circuit, because of the voltage drop caused by the Schottky diode mixer. The minimum input voltage that the XL6009S or the LM2577S requires to output the needed 1A current kept giving me problems. It should work reliably, theoretically, but it didn’t. I also tried a few “loss-less” MOSFET circuits as a mixer, but was disappointed in the results by limiting myself to using through-hole parts.
While searching for better DC boost convertors that had a lower input voltage minimum, I stumbled on the Adafruit PowerBoost 1000c board.
https://learn.adafruit.com/adafruit-pow ... t/overview
With this board, I hit the jackpot. It has everything I needed for my RPi supply.
The key features for me where:
Excellent charger capabilities for the Li-ion cell
Simultaneous charging and providing power (loadshare)
A low battery indicator
An integrated voltage boost circuit designed for a Li-ion cell
An integrated power enable pin to cut the output power
This board can charge a cell with a maximum of 1Amp, and can simultaneously power an RPi. The combined current for charging and the output is 1.65Amps, but the RPi gets priority over the charge current. If the main supply cannot provide enough current, the Powerboost will use the cell capacity to boost the output current. This is great for the wildly varying demands an RPi has that can cause a voltage droop which makes the RPi unstable, or even crash.
I tested this supply over a period of about a month now, with two of my Model (1) B's and briefly with my Model 3. I don't have a Model 2 to test for you, but that should work too. If you don't max out all the cores for the Model 3 and don't hang too many power hungry USB devices on it, it should work within the specs, but make sure you check that out.
I designed the following circuit around this board : [UPDATE]
Due to a longer boot period on later kernels and on some RPi models, the period between applying power to the RPi and the activation of the poweroff overlay has changed. To be safe, replace the 100uF capacitor in the diagram with a 220uF version.
If you followed my other one-button-start-stop circuits, this one has a few changes and improvements. First of all, the main difference is that I needed to add a level shifter to drive the output enable (EN) signal for the board.
Compared to the other designs I published, there are some additional changes that made the circuit less dependent on component tolerances. What I felt was needed was a more solid voltage level on the charge capacitor junction to better support the dual use. (start & stop)
After initiating the startup process and the full boot, this level (through the button) is also used to powerdown the RPi and it could get too close to the event trigger point, resulting in false interrupts. They are filtered out in software, but this can be avoided all together. In this newer design, I still use the GPIO pull-up parameter on the shutdown_request pin. By the time the button can be used to powerdown the RPi, the voltage at the junction would have been raised to a higher level by the pull-up as soon as the daemon starts to run. I also swapped a resistor for a diode to limit the pull effect from the gpio-poweroff pin to the junction and also the base of the transistor. Without that pull on that junction, I could use a smaller capacitor. With these changes, I could now also use a normal run-of-the-mill NPN transistor, instead of a logic level MOSFET that needs to operate in a 3.5V environment.
NOTE
I noticed that since the last firmware upgrades, the activation time of the overlay moved from about 3.5 sec into the boot sequence to about 5 sec. Depending on the component tolerances, especially for the electrolyte, you may want to increase the value of the charge resistor or the capacitor if the supply cuts out during the boot process. I now recommend 8 sec. to stay safe from further changes.
The software script is quite simple with just two event interrupts; one for the button request to power down, and one for the low-bat level, also to power down :
Code: Select all
#!/usr/bin/python
#-------------------------------------------------------------------------------
# Name: UPS-li-ion.py
# Purpose: RPi power supply with Li-ion UPS controller
#
# Author: paulv
#
# Created: 22-10-2015, modified 26-04-2016
# Copyright: (c) paulv 2015, 2016
# Licence: <your licence>
#-------------------------------------------------------------------------------
from time import sleep, time
import subprocess
import RPi.GPIO as GPIO
DEBUG = False
TEST = False
# ----- GPIO setup
POWER_OFF = 30 # P5-5 is used by dts gpio-poweroff overlay : reserved!
LOW_BATT_P = 31 # P5-6 critical battery level, active low
STOP_REQ_P = 29 # P5-4 stop/start button input, active low to shutdown RPi
if DEBUG : GPIO.setwarnings(True)
else : GPIO.setwarnings(False)
# Use the Raspberry Pi BCM numbered pins
GPIO.setmode(GPIO.BCM)
# Low Battery level sensing
GPIO.setup(LOW_BATT_P, GPIO.IN)
# Shutdown request (with extra pull when daemon starts to run)
GPIO.setup(STOP_REQ_P, GPIO.IN, pull_up_down=GPIO.PUD_UP)
def low_bat_level(LOW_BATT_P):
'''
Interrupt service routine that gets called when the li-ion battery voltage
is getting to a critical level < 3.5V.
When the low level is detected, the Pi should be
shutdown to prevent a crash and avoid possible damage to the SD card.
To avoid jitter in the recognition, a valid signal is deemed correct when
it is low for a 2 sec period within a 4 sec window.
'''
# if we're here, we have a low bat alarm
# remove event detection to avoid glitch detections
GPIO.remove_event_detect(LOW_BATT_P)
if TEST : print "Batt low detected"
# start to count the logic levels by sampling 8 x roughly
# every 250 mSec = 2S, which is then also the largest false detection
# period we can skip.
edge_start = time()
cnt = 0
while (time() - edge_start) <= 4 : # check within a 4 Sec window
if TEST : print "batt low ; cnt = ", cnt
sleep(0.25) # check every 250 mSec
if GPIO.input(LOW_BATT_P) == 0 : # Looking for valid low batt levels
cnt += 1
else: # when we have captured a glitch, start all over again
cnt = 0
# With 8 consecutive levels, or when the max time is up, leave.
if cnt == 8 :
break
if cnt == 8 :
if TEST : # acknowledge but continue running
print "Low battery level is real"
sleep(2)
# setup the event detection for the low batt level again
GPIO.add_event_detect(LOW_BATT_P, GPIO.FALLING, callback=low_bat_level, bouncetime=20)
return
else:
subprocess.call(['logger "Critical battery level, RPi is shutting down"'], shell=True)
print "Critical battery level, shutting down RPi now!"
subprocess.call(['poweroff --poweroff'], shell=True, \
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sleep(20) # do not return, wait it out here.
else:
if TEST : print "False battery alarm ", cnt
sleep(2)
GPIO.add_event_detect(LOW_BATT_P, GPIO.FALLING, callback=low_bat_level, bouncetime=20)
return
def stop_req(STOP_REQ_P):
'''
Interrupt service routine that gets called when the start/stop button
is pressed while the RPi is running.
When this event is detected the Pi should be shutdown.
To avoid incorrect button presses, the button must be pressed for >4 seconds
otherwise, it is deemed an invalid press.
'''
# remove event detection to avoid false detections
GPIO.remove_event_detect(STOP_REQ_P)
if TEST: print "Stop request detected"
edge_start = time()
cnt = 0
while (time() - edge_start) <= 7 : # check within a 7 Sec window
if DEBUG : print "Stop button ; cnt = ", cnt
sleep(1) # check every second
if GPIO.input(STOP_REQ_P) == 0 : # Looking for valid low batt levels
cnt += 1
else: # when we have captured a glitch, start all over again
cnt = 0
# With 5 consecutive levels, or when the max time is up, leave.
if cnt == 5 :
break
if cnt == 5 :
if TEST : # acknowledge but continue running
print "Shutdown request is valid"
# wait for the cap to charge back to a logic level 1 to avoid false hits
sleep(7)
# setup the event detection again
GPIO.add_event_detect(STOP_REQ_P, GPIO.FALLING, callback=stop_req, bouncetime=20)
return
else:
subprocess.call(['logger "Shutdown requested, RPi is shutting down"'], shell=True)
print "Shutdown requested, shutting down RPi now!"
subprocess.call(['poweroff --poweroff'], shell=True, \
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sleep(20) # do not return, wait it out here.
else:
if TEST : print "Invalid button press"
sleep(2)
GPIO.add_event_detect(STOP_REQ_P, GPIO.FALLING, callback=stop_req, bouncetime=20)
return
def main():
# add an entry to /var/log/syslog
subprocess.call(['logger "RPi supply daemon started"'], shell=True)
# setup the event detection for the low batt level
GPIO.add_event_detect(LOW_BATT_P, GPIO.FALLING, callback=low_bat_level, bouncetime=20)
# setup the event detection for the start-stop button
GPIO.add_event_detect(STOP_REQ_P, GPIO.FALLING, callback=stop_req, bouncetime=20)
try:
while True:
if TEST:
print "low_bat = ", GPIO.input(LOW_BATT_P), "stop_req = ", GPIO.input(STOP_REQ_P)
sleep(5)
except KeyboardInterrupt: # Ctrl-C
if DEBUG : print "Closing GPIO channels"
GPIO.cleanup([LOW_BATT_P, STOP_REQ_P])
if __name__ == '__main__':
main()
Add this to crontab (crontab –e) to get the daemon started :
Code: Select all
@reboot sudo /usr/bin/python /home/pi/UPS-li-ion.py
Code: Select all
# Enable Poweroff
dtoverlay=gpio-poweroff,gpiopin=30
viewtopic.php?f=29&t=133740
In any case, my goal was to provide a power supply with a simple one-button start-stop method, and a power backup to prevent power related crashes and damage to my SD cards. This design works really well. Here are two pictures on how I implemented this. I did not implement the sensing of the main supply because I don’t need it. If you do, it only takes two resistors and a smoothing capacitor.
Note that this will not be a complete solution for embedded systems that need to have a fully automatic start mechanism. To add that, you need a hardware watchdog like the one I used in my automatic power supply.
I hope this helps to provide better power to the RPi.
Enjoy!
I also designed a supply that can be used in "embedded" or in autonomous applications. Look here : viewtopic.php?f=37&t=150358