Close
0%
0%

Single SuperCapacitor UPS for Raspberry Pi

A last gasp Uninterruptible Power Supply for any Raspberry Pi computer.

Similar projects worth following
The circuit provides about 30 seconds of backup power (at up to 2.5A) to a Raspberry Pi computer when the power fails -- using a single supercapacitor. This allows the Pi to shutdown gracefully without damage to the SD card. Power is automagically restored when it becomes available again.

I have 3 Raspberry Pi computers running 24/7 in headless mode scattered around my residence. One of them is an old Pi1B that manages my heating system and monitors my water well. I consider it a mission critical piece of hardware. Invariably, when I leave for a trip in the winter the power will fail, so I need a means to automagically and gracefully shutdown all of the headless Pi’s.

I built a working UPS using a stack of two 400F supercapacitors about three years ago: https://www.raspberrypi.org/forums/viewtopic.php?f=37&t=50470&hilit=controlled+shutdown&start=25. It was a relatively simple solution that did not make very efficient use of the supercaps, but now with more power hungry versions of the Raspberry Pi I decided it was time to build a new one with higher load capacity (and re-purpose the supercaps).

The energy that you can get from a capacitor is simply

where V1 is the initial voltage across the capacitor and V2 is the final voltage across the capacitor. The output energy is in Joules (Watt-seconds). It is evident from this equation that you can get much more energy out of the capacitor if you can get a lot of voltage across it and take more voltage from it. The problem is that affordable supercaps don’t exist with voltage ratings above 3V (typically 2.7VDC).

So just stack them like batteries then. What’s the big deal? When you stack two identical capacitors in series you get half the capacitance value. This is actually not as bad as it sounds since your energy capacity goes up with the square of the applied voltage. So if we had a stack of 4 supercaps that we could put 10V across would produce 4X more energy than a single supercap with 2.5V across it. Or conversely, you could use smaller supercaps to get the same energy output. The basic problem with this thinking is that the prices of supercaps don’t scale linearly with size — a 400F is $12 while a 100F is $8-$12, so 4 of them will cost a lot more. Another issue with stacked supercaps is one of balancing. The capacitor voltages need to be kept in balance to avoid exceeding the rated voltage. This requires extra circuitry, cost and complexity in the charging circuitry.

My heating system only needs backup power long enough to shutdown the system — a last gasp.

The current design:

Analog Devices recently (as of 2018-10-1) released the LTC4041, a supercapacitor backup IC. It takes care of the charging of the supercapacitor and the balancing, if there are two of them. It also manages the switchover from powering the load from an AC source to powering the load from the supercapacitor backup. What it doesn't manage is the timers required for the interval when the Raspberry Pi is committed to shutting down and the power-off interval which resets the Raspberry Pi and allows it to reboot when AC power becomes available again. This is the required functionality of the design:

  1. Provide 5V±0.25V power to the RPi @ 500mA to 2A max.
  2. If the power fails, continue to provide 5V from a single (or dual) SuperCap charged to 2.7V (or 5V). And indicate the power failure to the RPi.
  3. Backup power must be provided for a minimum of 35 seconds. The current load will be high until the RPi shuts down into a low current state that only draws about 50-80mA. It takes about 10-20 seconds to enter the shutdown state.
  4. The RPi will assert a SHUTDN input to indicate to the UPS that it has committed to the shutdown sequence. The UPS must provide backup power for 15-20 seconds after the SHUTDN input is asserted. The UPS must also disconnect the power input from the load after this interval to prevent the RPi from hanging in shutdown mode if the input power is reapplied. 
  5. At the end of the shutdown interval the power is disconnected from the load for at least 5-10 seconds to allow the RPi to reboot when power becomes available again. If power has returned during the shutdown interval...
Read more »

LG4-BOM.xls

A crude Bill of Materials in spreadsheet form for the latest LTC4041 version. Some sources are included.

ms-excel - 10.00 kB - 01/06/2019 at 15:39

Download

UPS4041-LG4.zip

A compressed folder containing all of the gerber files to create the PCB for the latest LTC4041 version of the UPS. You can upload this file directly to OSH Park and then order boards.

Zip Archive - 45.39 kB - 01/06/2019 at 15:04

Download

UPS4041LG.X.production.hex

Hex file used to program the PIC10F202 ┬ÁP.

hex - 356.00 bytes - 01/19/2019 at 00:26

Download

powerfail.py

Python code to manage the UPS.

x-python-script - 3.77 kB - 11/13/2018 at 19:36

Download

UPS-LG2.zip

This a compressed folder containing all of the gerber files to create the PCB for the first version of the UPS. You can upload this file directly to OSH Park and then order boards.

Zip Archive - 84.60 kB - 06/26/2017 at 19:39

Download

View all 6 files

  • Testing With Raspberry Pi as Load

    Bud Bennett01/10/2019 at 22:55 0 comments

    It took longer than expected to get results from using Raspberry Pi 2 and ZeroW. I first pugged in the RPi2, let the supercap charge and then pulled the wall wart. The red power light on the RPi2 began to flash hysterically and the dreaded lightning bolt appeared on the display. Something was wrong with the voltage delivered to the Pi. I measured 4.81V between the OUT+ and OUT- terminals on the UPS, but the PI was getting around 4.7V. It was that damn pink micro-USB cable that I got from the dollar store (for a dollar!). The power leads on that cable were pretty small -- 30 or 32 AWG. I did not want to cut into any of my other micro-USB cables, so I ordered a set of six micro-USB cables, 12 inches long, for $7 from Amazon. They arrived today.

    I cut the USB type-A connector off the end of the cable and trimmed off the shielding and the unnecessary data wires. The power wires did look beefier. Substituting the new black power cable for the cheap(er) pink cable fixed the problem. I got a flash from the RPi2's red power LED when the AC adapter was disconnected, but the LED stayed on after that, and no lightning bolt appeared on the screen. I the ran the RPi2 with all 4 cores at 100% without issue. The 100F supercap voltage, after  going through 15 seconds of waiting and then 20 seconds of shutting down, was 2.3V -- very acceptable. 

    I also tested the UPS with the Raspberry Pi ZeroW. The current drain is quite a bit lower -- the UPS can supply power to the ZeroW for 35 seconds (using a 100F supercap) before having to enter the shutdown sequence. I tried all of my various AC adapters to see if the dreaded relaxation oscillation would return, but the UPS reliably applied power and dutifully shutdown without incident, independent of the AC adapter.

    I'm very close to the end of this project. The only task remaining is to swap the current UPS for this new UPS in my heating system controller. Since it is the middle of winter, and I'm a bit risk averse, that task will have to wait until warmer weather. 

    OLD vs. NEW:

    Just for grins and giggles I took a photo of the first version of the UPS next to the latest version.

    Some items of note:

    • The first version did provide 2.5A from a single supercap charged to 2.7V. The latest version can't do that -- it requires a stack of 2 supercaps to output 2.5A (per spec).
    • There is no trim pot on the new version -- a savings of around $1 (and board space).
    • The new version can charge the supercap much faster without heating the PCB too much since it uses a switched-mode charger. The old version used a linear charger with foldback current limit.
    • Input power jack. Old -- barrel jack. New -- micro USB.
    • The new version is less susceptible to noise between the Raspberry Pi and UPS. The PIC SHUTDN input noise rejection seems to be working.
    • The new version uses a synchronous switcher for both charging and booster -- lower power dissipation in both cases.
    • The old version required nearly 4 hours to populate the PCB. I can populate the new board in less than 1 hour.

  • PIC Code

    Bud Bennett01/06/2019 at 14:59 0 comments

      The assembler code for the PIC10F202 is below. I will also place the hex file for programming it in the files section of this project. The main body is only 21 lines of code. The comments should clearly document what is going on, but here's an overview:

      1. Setup I/O and watchdog timer.
      2. Sample SHUTDN pin every 10ms.
      3. SHUTDN must be high for 5 consecutive samples to be considered "HIGH". This is a noise filter.
      4. If SHUTDN is high, then delay for 20 seconds and set the GP1 high for 750µs, which disables the LTC4041.
      5. Loop forever until power is cut by the LTC4041.
      ; WARNING!!! Don't erase this part before programming. It will erase the
      ; calibration value stored in 0x01ff.
      
      ; PIC10F202 Configuration Bit Settings
      
      ; Assembly source line config statements
      
      #include "p10f202.inc"
      
      ; CONFIG
      ; __config 0xFFFB
       __CONFIG _WDTE_ON & _CP_OFF & _MCLRE_OFF
      
       ; General Notes:
       ; Internal oscillator is 4MHz (1MHz system clock). No external
       ; oscillator needed. 
       ; Watchdog timer is set for 18ms x 16 = 288ms.
       ; Only 2 stack registers. Can't call more than 1 nested subroutine.
       
       ; Pin Assignments:
       ;  1 - GP0: SHUTDN input
       ;  2 - VSS
       ;  3 - GP1: Shutdown output to the base of Q1
       ;  4 - GP2: unused. Set as output.
       ;  5 - VDD
       ;  6 - MCLR_, GP3: unused. tied to VDD in circuit.
      
      
      ;***** Define addresses of the General Purpose Registers ****
      ; 24 general purpose registers available starting at 0x08
      COUNT1    equ 0x08    ;First counter for delay loops
      COUNT2    equ 0x09    ;Second counter for delay loops
      COUNT3    equ 0x0a    ;Third counter for delay loops
      SCRATCH    equ 0x0b    ;Scratchpad variable for everthing else.
          
          org    0x0000          ; processor reset vector
      
          movwf    OSCCAL        ; load the calibration value into the OSCCAL reg.
          
      ;**** Disable unused peripherals ****
          movlw    b'11001100' ; disable Wake on Change, disable Weak pullups, 
          OPTION                ; internal clk -> Timer0, Timer0 source edge don't care,
                      ; Prescaler Assignment -> WDT, Prescaler = 16
                      
      ;**** Setup GPIO inputs/outputs ****
          movlw    b'00000000' ; load GPIO register before TRIS assignment
          movwf    GPIO
          movlw    b'00001001' ; set GP1 & GP2 as output, all others are inputs
          TRIS    GPIO
      
      Start
          clrwdt            ; reset watchdog
          call    Delay10ms   
          btfss    GPIO, 0        ; sample SHUTDN input every 10ms
          goto    Start        ; back to START if SHUTDN = 0
          movlw    d'5'        ; number of samples to deglitch SHUTDN input.
          movwf    COUNT3
      Sample    call    Delay10ms
          btfss    GPIO, 0
          goto    Start        ; back to START if SHUTDN = 0
          decfsz    COUNT3, 1   ; SHUTDN must be high 5x in a row
          goto    Sample
          clrwdt            ; clear the watchdog
          call    Delay20        ; commit to shutdown at this point. Wait 20 sec.
          bsf    GPIO, 1        ; set the shutdown output high
      Stuck    clrwdt            ; reset watchdog    
          goto Stuck        ; infinite loop until power is cut
          
          
      
      ;**** subroutines begin here ****    
      Delay1                ; total count = 1Meg = 1 second
          movlw    d'8'        ; put 8 into COUNT3
          movwf    COUNT3        ; COUNT3 x (COUNT1 x 3 + 3)(COUNT2 + 5) = 1001472
          movlw    d'255'        ; put 255 
          movwf    COUNT1        ; into COUNT1
      Loop2    movlw    d'158'        ; put 158
          movwf    COUNT2        ; into COUNT2        
          
      Loop1    decfsz    COUNT1,1    ; counts down from 255
              goto    Loop1       ;
              decfsz    COUNT2,1    ; counts down from 158
          goto    Loop1        ;
          clrwdt            ; clear the watchdog timer every 125ms
          decfsz    COUNT3,1    ; counts down from 8
          goto    Loop2        ; 
          RETLW    0
      
      Delay10ms            ; delay = 1us x (255x3+3) x (8 + 5) = 9.98ms
          movlw    d'255'
          movwf    COUNT1
          movlw    d'8'
          movwf    COUNT2        
      Loop10
          decfsz    COUNT1,1    
              goto    Loop10       
              decfsz    COUNT2,1    
          goto    Loop10        
          RETLW    0    
          
      Delay20
          movlw    d'20'        ; 20 x 1 = 20 seconds
          movwf    SCRATCH        ; into SCRATCH reg.
      Loop20    
          call    Delay1        ; 1 sec delay
          decfsz    SCRATCH,1   ;
              goto    Loop20       ;
          RETLW    0
          
          END

      Edit 2019-01-18: I change the shutdown output from a 750µs pulse to just a high value after the 20 second delay. Apparently, the pulse was too short to accomplish the task and it works fine with the step output. I updated the hex code in the files section to match.

  • 4041 Version 4th Pass Results

    Bud Bennett01/05/2019 at 06:22 0 comments

    I received the LG4 PCBs last week. There was no point in assembling them since I did not have the PIC10F202 micro controllers, which arrived yesterday. I was able to program the PICs (with my new PICKit4 programmer) and populated the PCBs today. So far so good. On the bench, the circuit performs as expected; and initial testing with a Raspberry Pi2B and ZeroW are ongoing.

    Yes, there is a solder bridge from SCAP- to C8, but it does no harm so I let it remain.

    The relaxation oscillation problem from previous passes doesn't show up on this pass. I tried a couple different AC adapters without any issues. Reducing C2 to 22nF appears to have fixed it. 

    The PIC is performing its function as designed. I triggered the SHUTDN pin and timed out the oneshot and the off timer -- both were close to nominal design targets. There were no issues with the reapplication of power.

    After verifying basic functionality, I attached a 4Ω load and a 100F supercap. I let the supercap charge to full (2.67V) and pulled the AC adapter out of the wall. Here's the resulting waveforms at the output and the supercap:

    As expected, the 100F cap could not hold up the 1.2A load for very long -- not long enough to allow the older/slower Raspberry Pi variants to shutdown safely (but they also don't draw anywhere near this kind of current drain).

    I swapped out the 100F with a 400F and repeated the test:

    The 400F supercap provided 1.2A @ 4.81V for 80 seconds.

    This is what the SW node looks like when charging:

    and boosting to a 4Ω load:

    There was no bandwidth limiting on my 100MHz scope. The switching waveforms don't have too much ringing.

    Raspberry Pi Testing:

    The Pi2B with the 400F supercap in the UPS is running without issues. I haven't seen any unexpected operation, but testing has been limited. I'm going to let the Pi2B/UPS combination run for a couple of days to make sure there are no spurious shutdowns or Pi hangups.

    After that the ZeroW will get tested with the 100F supercap.

    Almost finished...

  • A Better Way

    Bud Bennett12/13/2018 at 04:13 0 comments

    While I was waiting for the band-aid PCBs to arrive I got to thinking about a better approach for the timing circuits. The LTC6993-1 is cute, but at $3.50/each it doesn't seem like very good value. Plus the PCB space that the one-shot, DFF, and LDO consume doesn't justify the function. I set about to see if Microchip had any simple micro-controllers in a SOT23-6 package -- yes they do!

    The PIC10F202 is a pretty bare bones µP -- just a watchdog timer, a clock/timer, and four I/O pins. A big plus is the 1% accurate 4MHz internal clock. It has a supply range of 2V-5.5V and uses TTL logic levels. Best of all, it's only $0.36 in low quantities -- and eliminates more than $4 of discrete components. I can also trade 3 SOT23 packages and a smattering of SMD components for a single SOT23-6 and two SMD passives. I'm sold.

    Here's the new improved schematic:

    The small PIC simply replaces the one-shot, DFF and LDO. There is no noise filter on the SHUTDN input -- the PIC can provide noise filtering in the code.

    The layout is a lot smaller (1.05 inch x 1.275 inch):

    The input output pads are arranged to accommodate 3.5mm terminal blocks so that all of the connections don't require soldering. The terminal blocks are mounted on the back side.

    The balance leads are beefier (on the back side) and should support the 2.5A output load if you're going to employ 2 supercaps -- that was missing from earlier versions.

    The option to use the larger 12x12 inductor is gone. This layout should work with most 6x6 or 7x7 inductors with adequate current/heat ratings. The inductor I'm using costs ~$0.09/each.

    PCBs will be ordered soon.

  • UPS-4041-LG3 Results

    Bud Bennett12/13/2018 at 03:12 0 comments

    I received PCBs yesterday and this afternoon I had a partially working board. I decided not to populate the LTC6993-1, the DFF and the 3.3 LDO. I was only interested in determining which band-aid fixed the problem in the simplest manner, and for that all I needed was a functional LTC4041. Refer to the schematic in the previous log for component references. A Raspberry Pi Zero W was used as a load in all of the testing.

    R18, R19, and C12 were populated since I knew the impact of not having them in place from previous tests. R21 was a short and I left C13 unpopulated to see if it was needed or not. The value of C2 is 22nF, which decreased the TMIN-BACKUP time that the LTC4041 spends ignoring the power-fail comparator after it has tripped.

    It turns out that this was all that was needed to fix the problem. I suspected that the relaxation oscillation was caused by the 500ms TMIN-BACKUP time being too long, which allowed the output voltage of the UPS to decay to zero during that interval. Decreasing TMIN-BACKUP to less than 50ms doesn't allow the output voltage to decay so far and can reach a point where it is above the UVLO threshold of the LTC4041 after one or two cycles. Here's a trace of input(CH2) and output(CH1) voltage during power-up.

    You can see that the output voltage jumps a couple of volts before the PFI comparator switches off and forces the LTC4041 into backup mode -- but the voltage on the supercap is not high enough and the output voltage is not high enough either to allow the boost converter to run. So the output voltage falls back a bit until the TMIN-BACKUP time ends and the input switch is closed again -- this time the output voltage has climbed high enough to keep the booster enabled (or the PFI comparator doesn't trip because the input-output differential is not enough to drag the input voltage down below the PFI threshold.) In either case the output voltage is sustained and the UPS settles into normal mode with the input switch closed and the boost converter off.

    I then populated C13 with a 220µF/6.3V tantalum, but it did not appear to make any difference in operation. I did not investigate the options with C14 and R21 -- I will remove those going forward. I've got enough confidence now to finalize the UPS design.

  • 3rd Pass for the LTC4041 Version

    Bud Bennett11/26/2018 at 17:11 0 comments

    After an exchange of ideas with Analog Devices I have decided to apply a bunch of band-aids to try to fix the observed problems with the earlier versions. This design includes the RC filtering on the SHUTDN input, the RC filtering on the PFI pin, resistor loads at the input and output, and three modifications that deserve a bit more explanation.

    Analog devices suggested the addition of an RC filter on the gate of M1, to reduce the inrush current when the input switch is turned on. The gate capacitance of M1 is already 2.5nF, so making R21 4MegΩ would slow down the switching time by about 4x. Increasing C14 to 7.5nF and setting R21 = 1MegΩ would have the same effect. I'm a bit leery of unintended consequences that may show up due to the slower turn-off time of M1, so this approach would probably be my last resort. 

    I added C13 at the input to help hold the input up when the input switch is closed. This may cause problems with the power fail comparator glitching after the input power is removed, but C13 can be removed if it worsens that issue. C13 is a tantalum, which should minimize voltage transients due to hot plugging the adapter. 

    Lastly, I reduced C2 from 220nF to 22nF. This reduces the minimum backup time from 500ms to 50ms. The reasoning behind this is to prevent prolonged relaxation oscillation by shortening the time between the input switch connections. If the output cap voltage is not allowed to fall completely back to zero then maybe after a few input cycles the oscillation will be broken. The success of this approach depends on the speed of recovery of the power fail comparator. 

    One more thing. I ordered a smaller inductor -- Hotland MCW-0630-1R5-N2. This new 1.5µH inductor is roughly 6.6x7x3 mm vs. 12x12x6 mm of the 1.2µH Coilcraft. The new induction is rated at 9A, which should be good enough for any intended load. The layout will accommodate either inductor.

    New PCBs are on order.

  • More Problems with the LTC4041 version

    Bud Bennett11/19/2018 at 14:58 0 comments

    I installed the modified UPS board, and 100F supercap, into my heating system. It did not go well. The UPS would power the Pi and peripherals the first time that it was plugged in, but it would not apply power after a disconnection. I found two major issues that had to be fixed.

    Oscillation

    After unpacking the oscilloscope and looking at a few waveforms, I determined that the LTC4041 was put into an oscillation caused by its power fail comparator and the input switch. When the AC adapter is first powered up its output voltage ramps toward the final steady state voltage and it is forcing full current into the output. When the input voltage of the UPS reaches 4.75V the power fail comparator allows the input switch to connect the input to the output and there is a surge current which tends to glitch the input voltage downward. Since the AC adapter is still driving the input voltage upward it seems to overcome this glitch and the UPS powers the output just fine.

    Things fall apart when the AC adapter is disconnected and then reconnected during the one-shot interval or the following power down interval. During the shutdown interval there is no current load on the AC adapter and its switch mode converter idles. When the LTC4041 comes out of the shutdown mode, the first thing it does is connect the input switch. The corresponding load spike that comes from connecting the 170µF load capacitance to the input creates a large downward glitch. (Sorry, I don't have pictures of any of this.) The glitch causes the power fail comparator to fire and try to switch to backup mode. The problem with this is that the voltage at SCAP is below 2.5V (by design) and the voltage at SYS is also below 2.5V so the backup converter is inhibited by the UVLO of the LTC4041. So nothing happens until the 500ms minimum backup time period ends and the entire cycle repeats, This is called a relaxation oscillation.

    The end result is that the UPS is stuck in a loop that prevents it from connecting the input power to the output.

    All AC Adapters Are Not The Same

    My first attempt to get the UPS working used the AC adapter that was already working with the heating system. When I installed the UPS and plugged the AC adapter into the wall socket the UPS did not power the Pi. Apparently, that adapter could not respond adequately to the inrush current when the input switch closed so the UPS when into oscillation. Swapping out the adapter with a more responsive adapter solved that problem.

    Solutions:

    After grokking what was happening, my first thought was to place a huge capacitor at the input of the UPS. But that might cause the previous problem with the power fail comparator glitch to return.

    My second solution was to examine the effect of filtering the power fail comparator input so that it would not respond to the short glitch when the input switch was connected. I reviewed my scope traces of a power failure event with a 4Ω load. The slope of the declining output voltage was fairly slow -- and the heating system current load was about half of the 4Ω load. I stacked an 0805 100pF ceramic cap on top of R8  -- creating a 10µs RC filter. Bench testing with the new filter showed improvement, but still occasional  oscillation, so I increased the capacitance across R8 to 1nF. This stopped the oscillation, at least on the bench.

    It also fixed the problem with the heating system. Now the UPS functions as designed, but I have a nagging feeling that this design needs to be tweaked for every application and so is not yet a robust, general purpose solution.

    I'm thinking now that in addition to the power fail comparator filtering I should shorten the minimum backup time period, but haven't as yet worked through what effect that would have.

    Updated Schematic:

    This is the updated schematic with the RC filter at the PFI input.

    I'm not going to replace the schematic in the project details section until...

    Read more »

  • New Python Code Running Under systemd

    Bud Bennett11/13/2018 at 19:35 0 comments

    I'm no code bunny. Here's the current working code: powerfail.py

    #!/usr/bin/env python
    '''
    This program monitors the status of the PWRGOOD signal from the UPS circuit.
    PWRGOOD is normally high. If it goes low then the input power has failed.
    This program senses when PWRGOOD falls and then samples it once/second. An
    accumulator counts up by 1 if power is bad and counts down by 3 if power is good.
    This accounts for the difference in supercap charge current vs. Zero-W load current.
    If the accumulator exceeds 20 then it signals the UPS to disconnect the
    power by asserting SHUTDOWN. This will still cause a shutdown condition even when
    the power is cycling on and off. After it commits the hardware to shutdown it also
    sends a shutdown command to the Linux system. The UPS will hold power up for 20 seconds
    after it receives the SHUTDOWN signal, which allows the Pi to enter a shutdown state
    prior to power removal.
    '''
    import RPi.GPIO as GPIO
    import os, time, sys
    import logging
    import logging.handlers
    #import traceback
    
    # global variables
    COUNT_UP = 1
    COUNT_DOWN = 3 # this relates to the ratio of charger current divided by load current
    COUNT_MAX = 20 * COUNT_UP # how many seconds of power loss before the Pi shuts down
    # set the GPIO pin assignments
    PWRGOOD = 23
    SHUTDOWN = 24
    
    #--logger definitions
    logger = logging.getLogger(__name__) 
    logger.setLevel(logging.INFO)  # Could be e.g. "TRACE", "ERROR", "" or "WARNING"
    handler = logging.handlers.RotatingFileHandler("/var/log/bud_logs/ups_mon.log", maxBytes=1000, backupCount=4) # save 4 logs
    formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    
    class MyLogger():
        '''
        A class that can be used to capture stdout and sterr to put it in the log
    
        '''
        def __init__(self, level, logger):
                '''Needs a logger and a logger level.'''
                self.logger = logger
                self.level = level
    
        def write(self, message):
            # Only log if there is a message (not just a new line)
            if message.rstrip() != "":
                    self.logger.log(self.level, message.rstrip())
    
        def flush(self):
            pass  # do nothing -- just to handle the attribute for now
    
    
    
    # configure the GPIO ports:
    GPIO.setmode(GPIO.BCM)
    # PWRGOOD is an input with weak pullup
    GPIO.setup(PWRGOOD, GPIO.IN, pull_up_down = GPIO.PUD_UP)
    
    def powerfail_detect(count_max, count_up, count_down):
        # if the count exceeds 20 the system will shutdown.
        count = 0
        pwr_flip = False
        while (count < count_max):
            time.sleep(1)
            if (GPIO.input(PWRGOOD)):
                if (pwr_flip):
                    logger.info("Power is good")
                count -= count_down
                pwr_flip = False
                if (count <= 0):
                    logger.info("Returning to normal status")
                    return
            else:
                if (not pwr_flip):
                    logger.info("Power has failed")
                count += count_up
                pwr_flip = True
        logger.info("powerfail iminent...shutting down the Pi!\n")
    
        GPIO.setup(SHUTDOWN,GPIO.OUT)
        GPIO.output(SHUTDOWN,0)
        time.sleep(0.1)
        GPIO.output(SHUTDOWN,1)
        time.sleep(0.1)
        
        os.system("sudo shutdown -h now")
        GPIO.cleanup()
        return
    
    # If this script is installed as a Daemon, set this flag to True:
    DAEMON = True # when run as daemon, pipe all console information to the log file
    # --Replace stdout and stderr with logging to file so we can run it as a daemon
    # and still see what is going on
    if DAEMON :
        sys.stdout = MyLogger(logging.INFO, logger)
        sys.stderr = MyLogger(logging.ERROR, logger)
    
    try:
        logger.info("Enabled")
        while True:
            time.sleep(1)
            if (not GPIO.input(PWRGOOD)):
                powerfail_detect(count_max=COUNT_MAX, count_up=COUNT_UP, count_down=COUNT_DOWN)
                
    except:
        GPIO.cleanup()  # clean up GPIO on CTRL+C exit
    
    

     Note that the log file is located in /var/log/bud_logs/ups_mon.log. It will rotate the log after 1000bytes and keep the latest four logs. You can change all of that by altering the handler params. 

    The above script is located in /home/pi/programs/ and runs as a service using systemd on either the Jessie or Stretch version of Raspbian. You can locate it anywhere as long as the service knows the path. The powerfail.service...

    Read more »

  • UPS4041-LG2 Results

    Bud Bennett11/12/2018 at 01:13 0 comments

    I received the second pass PCBs on 11/7/2018. I was busy, so I did not populate one of the boards until 11/9. I had second (third?) thoughts about a couple of items so I increased C9 from 10µF to 22µF to reduce the impedance at the output and hopefully reduce the ripple voltage at the output; and I increased C2 to 220nF to increase the minimum backup time to 500ms, having some concerns about how the power-fail comparator was going to function with the AC adapter. Here's the newly populated board:

    My initial testing was limited to a power supply input and a resistive load -- I found out quickly that bench testing doesn't equate to the real thing. But on the bench the UPS appeared to be fully functional.

    Measured Bench Parameters:

    (All of these parameters measured with single 400F supercap. )

    Full Charge VSCAP voltage = 2.67V (design target = 2.68V)

    Charge Current = 1.075A (measured assuming 400F ±10% supercap: time to charge from 2.5V to 2.6V = 37.2 sec.) Design target = 1A.

    Backup Voltage = 4.77V with 4Ω load resistor (design target = 4.8V)

    Input Power Fail threshold = 4.75V (same as design target).

    Power Off time out period, after 20 second one-shot interval = 8.3 second (design target = 5-10 sec.)

    Anecdotal Data:

    With a 2Ω load the output voltage during backup did not reach 4.8V. The output voltage dropped from 4.95V to 4.64V immediately after the input power was cut and descended below 4.5V within a few seconds. Clearly this circuit was not going to provide a 2.5A load during backup with a single supercap. The LTC4041 data sheet confirms it with this plot:

    I wanted to determine if the circuit could manage two sequential power failure events. With a 4Ω load resistor the circuit maintained 4.77V at the output after 2 sequential power failures (30 second duration with a 4Ω load). The final voltage at SCAP was 2.19V.

    Bench Testing Waveforms:

    Here's a trace of the output voltage and PWRGOOD signal when the power was cut to the adapter (RL = 4Ω):

    The initial voltage was 5.15V -- so the output voltage dropped to about 4.6V before the boost converter took action. A short glitch below the specified operating voltage of the Raspberry Pi doesn't appear to be a problem (in my experience). 

    In the above waveform there doesn't appear to be any indication of a power failure on the PWRGOOD signal (channel #2). If we expand the timeline it becomes clearer:

    The PWRGOOD signal drops for only a few µs because the backup system takes over and removes the load from the input. Once the power-fail comparator has tripped the LTC4041 keeps the system in backup mode for a time period set by the capacitor on the CPF pin, C2. With C2 = 220nF this period is approximately 500ms. This is to allow the input voltage to relax to a low level and avoid potential oscillations. After this initial short glitch the PWRGOOD signal doesn't fall again until much later:

    As it turns out 500ms wasn't long enough. When the AC power fails the AC adapter stops operating with the effect that the input just becomes a high impedance with a large capacitor. Without any load the input capacitor takes a long time to discharge  and so the power-fail comparator can be fooled into thinking that there is still a power source at the input. The fix is to place a resistor at the input to discharge the input capacitance to a level below the power-fail comparator trip point before the 500ms minimum backup period expires. A 1kΩ resistor does the trick. I should have known to do this since the first discrete version of this UPS included this resistor...

    Read more »

  • Changes to the LTC4041 approach

    Bud Bennett10/23/2018 at 21:06 0 comments

    As usually happens, I was thinking about some aspect of this design when I had a blinding glimpse of the obvious. It is going to cause me to toss the first version of the LTC4041 design without even populating the PCBs.

    Simplifying the input switches:

    The first version of the design had two pairs of FET switches to disconnect the input source. I got to thinking that I did not need to actually disconnect it since it just presents a high resistance load when the AC power fails. I could use a single FET switch if I connected the drain to the input and the source to the VIN pin of the LTC4041. This reverses the body diode of the FET so that the input won't hold up the output voltage to the load if the input power returns. But in this configuration the body diode of the input FET won't let the input voltage fall more than a diode drop below the output voltage. In this application this is not a problem -- as long as the input voltage is less than the 4.75V power fail comparator threshold of the LTC4041. 

    Here's the version 2 schematic:

    M1 is a 30V, 4mΩ RDSon, logic level FET that I used on one of the magnetic switch projects. The package is a 3.3x3.3mm DFL powerPak, which has become pretty standard for these types of devices. I also upgraded C4 to a 150µF low-ESR tantalum (Vishay 594D157X9010D2T -- 10V, D-case, 80mΩ ESR). There are a few of these in my inventory and I haven't been able to use it because of its size, but in this case it fit.

    The Layout is Smaller:

    1.05"x1.613" Almost 15% smaller than the first version. I don't particularly like the way that the output and input traces spiral around each other, but that was forced by the pinout of the LTC4041. 

    So now I will order another set of PCBs. Three of these boards should cost about $8.50 from OSH Park. It will take 3-4 weeks to get them.

View all 12 project logs

Enjoy this project?

Share

Discussions

Silviu EU wrote 05/01/2019 at 14:30 point

Hey Bud, 

I have all the components and PCB's printed , but I'm having problems in programming the PIC 10f202 either with MPLAB IDE or IPE I have tried different connections and ways to program but no success and lost e few good days and hours ,Can you help me with some wiring from PicKit 3 to the Pic in order to program it , maybe some advises, this is the error message that I get when trying to program:

*****************************************************

Connecting to MPLAB PICkit 3...

Currently loaded firmware on PICkit 3
Firmware Suite Version.....01.55.01
Firmware type..............Baseline

Programmer to target power is enabled - VDD = 5.000000 volts.
Target has invalid calibration data (0x00).

Programming...

The following memory area(s) will be programmed:
program memory: start address = 0x0, end address = 0x35
configuration memory
program memory
Address: 0 Expected Value: 25 Received Value: 0
Failed to program device

  Are you sure? yes | no

Melgar wrote 11/06/2018 at 14:02 point

Hello,

I was inspired by your project here to make my own UPS for the RPi based on this chip. Thank you for explaining everything in this project. I wanted to ask you some questions.

1. Why did you add the slightly complicated timer circuit, I want to do something similar but wouldn’t it be much easier to connect a pin from the raspberry to the shutdown pins of the LTC4041? With “gpio-poweroff” a pin can be set high at the end of the Linux shutdown (more info: http://www.embeddedpi.com/documentation/gpio/mypi-industrial-raspberry-pi-psu-shutdown-gpio-line).

2. You said: “If 2 supercaps are used, then make sure that the voltage on the SCAP pin has discharged below 2.5V when the one-shot timer expires or else the booster could be re-enabled and reboot the Raspberry Pi even if there is no input power applied.” I think the datasheet is very vague on this point, do you have a source for this information or did you test it?

3. If the Vscap > 2.5V restarts the chip, then what would be a suitable solution? Lowering the voltage of the SCAP(‘s) is an option, but I expect it to have less performance (more current, closer to minimum Vscap).

Kind regards and good luck with your project,
Melgar

  Are you sure? yes | no

Bud Bennett wrote 11/09/2018 at 06:34 point

1. I was not aware of that feature, but I don't trust external code to not change over time. There used to be a Pi hardware watchdog, but that no longer works. I've been burned before. 

2. You're right about the data sheet being vague. The datasheet discusses this point in the paragraph titled "Max (Vsys, Vscap) Undervoltage Lockout." I got assurance from the designer of the LTC4041 that it works as described. I'll be testing it in the next few days.

3. Smartass answer: Don't use 2 supercaps. Otherwise make sure that the SCAP voltage is below 2.5V before you shutdown the Raspberry Pi. You could also disconnect the SCAP pin from the supercap stack and force it below 2.5V at the end of the timer period somehow. (The SCAP pin is not high current. -- hoping that the data sheet is right about that...) 

I didn't think very hard about how to handle the 2 supercap case. If I implement that option I believe that I will just program the Pi to adjust the period between PWRGOOD going low and when it asserts SHUTDN to guarantee the SCAP drops below 2.5V.

Good luck to you as well. These UPS projects are more complicated than most people realize.

Bud.

  Are you sure? yes | no

Melgar wrote 11/09/2018 at 06:48 point

Thanks for answering

  Are you sure? yes | no

Paul wrote 04/29/2018 at 13:58 point

Cool! I need something like this. If I send this to OSH Park, will they make the board with components or just an empty board? I'm more of a software guy and I'm just starting to learn electronics.

  Are you sure? yes | no

Bud Bennett wrote 04/29/2018 at 21:54 point

They will make three empty boards. You get to stuff 'em. All surface mount...the MSOP part is ridiculously difficult to do without shorts. Discretion is the better part of valor.

  Are you sure? yes | no

Michael wrote 01/16/2019 at 05:44 point

Hey Bud, I like your project very much. I think it would be a huge progress for all raspberrys as you can damage the SD card with one single power loss. But like Paul, I'm just a software guy.
Is it possible to get this board already assembled? 

  Are you sure? yes | no

Bud Bennett wrote 01/16/2019 at 23:57 point

Michael: The only possible way to get an assembled board is for me to build it for you. I can assure you that you can't afford me. I don't consider it much fun to populate/solder PCBs. I wish there was some way of transferring manufacturing rights to a third party -- but this is open hardware so anyone can make the board if they choose. I'm getting ready to make 2 more PCBs just to use some parts I have on hand -- PM me and you might get one.

  Are you sure? yes | no

slado wrote 03/12/2018 at 11:25 point

The 400F capacity seems to me an overkill for 30 seconds backup power. The Raspberry Pi draws only about 300mA average current. Too much capacity prolongs the charging time. From the circuit diagram I could see that the charger is a linear circuit and not a step-down DC/DC converter hence charge current is limited and/or heat production could be an issue. I just compare your circuit with another supercapacitor UPS: www.juice4halt.com

  Are you sure? yes | no

Bud Bennett wrote 04/25/2018 at 13:33 point

I've been traveling quite a bit the last couple of months and did not see this comment until recently. I will address each issue that you raised:

1. I stated that I repurposed the 400F supercaps from a previous project. It is overkill for this, but there was no good reason to spend more money for a smaller supercap when I had these on hand.

2. The Pi by itself is low current drain, but any peripherals will add to it. Your 300mA number is for older, single core Rasperry Pi units. I believe that the Raspberry Pi designers specify a 2.5A wall wart to accommodate the total range of load current. I was attempting to design the circuit that would meet that high end. The juice4halt design uses two 22F supercaps in series. If you assume that their circuit charges the caps to 5.4V and discharges to 2V (highly unlikely) then you get a grand total of 127 W-sec of energy. That will provide less than 10  seconds of power to a 5V load drawing 2.5A. The Raspberry Pi 3 will draw 750mA with 4 cores at 100% -- the juice4halt will only last 33 seconds -- not much margin -- even less with peripherals.

3. You are correct about the initial charge time -- it will be long. But after the supercap is charged, the time to replace the charge is pretty short because the discharge time is limited to 30 seconds or so. The recharge time will be around 1 minute no matter what size supercap is employed.

4. The linear charger is simple and the power dissipation is accounted for in the design. Even a switch-mode converter has limited charge current given the limitations of the wall wart. The total current draw from the Pi and peripherals, plus the charger, can't exceed the wall wart rating.

The juice4halt looks like a nice alternative, but doesn't meet my stated requirements. Your comment appears to be an advertisement for it. 

This was my first foray into switch-mode boost converter design. If I did another one, would it look like this -- most definitely not. But it does the job and I'm pretty satisfied with its performance.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates