Charging Lipo batteries with Pico Lipo

@ Hel

I’ve just got a Badger 2040W (Great - works really well) and the recommended Galleon 400mAh 3.7V battery. I’m trying to charge it up with a Pico Lipo and Hel’s program listed here:

# This example reads the voltage from a LiPo battery connected to Pimoroni Pico LiPo
# and uses this reading to calculate how much charge is left in the battery.
# It then displays the info on the screen of Pico Display (or Pico Display 2.0).
# With Pimoroni Pico LiPo, you can read the battery percentage while it's charging.
# Save this code as main.py on your Pico if you want it to run automatically!

from machine import ADC, Pin
import time
# change to DISPLAY_PICO_DISPLAY_2 for Pico Display 2.0
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY_2

display = PicoGraphics(display=DISPLAY_PICO_DISPLAY_2, rotate=0)

display.set_backlight(0.8)

vsys = ADC(29)                      # reads the system input voltage
charging = Pin(24, Pin.IN)          # reading GP24 tells us whether or not USB power is connected
conversion_factor = 3 * 3.3 / 65535

full_battery = 4.2                  # reference voltages for a full/empty battery, in volts
empty_battery = 2.8                 # the values could vary by battery size/manufacturer so you might need to adjust them

# Create some pen colours for drawing with
BLACK = display.create_pen(0, 0, 0)
GREY = display.create_pen(190, 190, 190)
GREEN = display.create_pen(0, 255, 0)
RED = display.create_pen(255, 0, 0)

while True:
    # convert the raw ADC read into a voltage, and then a percentage
    voltage = vsys.read_u16() * conversion_factor
    percentage = 100 * ((voltage - empty_battery) / (full_battery - empty_battery))
    if percentage > 100:
        percentage = 100

    # draw the battery outline
    display.set_pen(BLACK)
    display.clear()
    display.set_pen(GREY)
    display.rectangle(0, 0, 220, 135)
    display.rectangle(220, 40, 20, 55)
    display.set_pen(BLACK)
    display.rectangle(3, 3, 214, 129)

    # draw a green box for the battery level
    display.set_pen(GREEN)
    display.rectangle(5, 5, int((210 / 100) * percentage), 125)

    # add text
    display.set_pen(RED)
    if charging.value() == 1:         # if it's plugged into USB power...
        display.text("Charging!", 15, 90, 240, 4)

    display.text('{:.2f}'.format(voltage) + "v", 15, 10, 240, 5)
    display.text('{:.0f}%'.format(percentage), 15, 50, 240, 5)

    display.update()
    time.sleep(0.5)

I’ve also got a 500mAh LiPo battery BAT0003

Both batteries drive the new Badger2040 W but the numbers on the displayV2 do not appear to be right.

If there is enough juice to drive the Badger I would expect to see higher values on the screen.

I’ve not used LiPos before. Am I doing things correctly?

Battery voltage reading is different on Pico W as it shares the voltage reference with one of the pins used by the wireless module - will see if I can dig out some code for you!

Oh sorry - you’re using a Pimoroni Pico LiPo to read the battery voltage, not the Badger W? I think you should be able to read the voltage whilst charging with that one, though it’s been a while! Does it read the voltage correctly when it’s not connected to USB power?

I’m thinking, because its a PICO W you still have to use the new code.

# This example shows how to read the voltage from a LiPo battery connected to a Raspberry Pi Pico via our Pico Lipo SHIM
# and uses this reading to calculate how much charge is left in the battery.
# It then displays the info on the screen of Pico Display.
# Remember to save this code as main.py on your Pico if you want it to run automatically!

from machine import ADC, Pin
import time
import network
# change to DISPLAY_PICO_DISPLAY_2 for Pico Display 2.0
from picographics import PicoGraphics, DISPLAY_PICO_DISPLAY


def get_vsys():
    # Pico W voltage read function by darconeous on reddit: 
    # https://www.reddit.com/r/raspberrypipico/comments/xalach/comment/ipigfzu/
    conversion_factor = 3 * 3.3 / 65535
    wlan = network.WLAN(network.STA_IF)
    wlan_active = wlan.active()

    try:
        # Don't use the WLAN chip for a moment.
        wlan.active(False)

        # Make sure pin 25 is high.
        Pin(25, mode=Pin.OUT, pull=Pin.PULL_DOWN).high()
        
        # Reconfigure pin 29 as an input.
        Pin(29, Pin.IN)
        
        vsys = ADC(29)
        return vsys.read_u16() * conversion_factor

    finally:
        # Restore the pin state and possibly reactivate WLAN
        Pin(29, Pin.ALT, pull=Pin.PULL_DOWN, alt=7)
        wlan.active(wlan_active)


display = PicoGraphics(display=DISPLAY_PICO_DISPLAY, rotate=0)

display.set_backlight(0.8)

charging = Pin('WL_GPIO2', Pin.IN)  # reading this pin tells us whether or not USB power is connected

full_battery = 4.2                  # these are our reference voltages for a full/empty battery, in volts
empty_battery = 2.8                 # the values could vary by battery size/manufacturer so you might need to adjust them

# Create some pen colours for drawing with
BLACK = display.create_pen(0, 0, 0)
GREY = display.create_pen(190, 190, 190)
GREEN = display.create_pen(0, 255, 0)
RED = display.create_pen(255, 0, 0)

while True:
    # convert the raw ADC read into a voltage, and then a percentage
    percentage = 100 * ((get_vsys() - empty_battery) / (full_battery - empty_battery))
    if percentage > 100:
        percentage = 100.00
    
    # draw the battery outline
    display.set_pen(BLACK)
    display.clear()
    display.set_pen(GREY)
    display.rectangle(0, 0, 220, 135)
    display.rectangle(220, 40, 20, 55)
    display.set_pen(GREEN)
    display.rectangle(3, 3, 214, 129)

    # draw a green box for the battery level
    display.set_pen(GREEN)
    display.rectangle(5, 5, round(210 / 100 * percentage), 125)

    # add text
    display.set_pen(RED)
    if charging.value() == True:         # if it's plugged into USB power...
        display.text("Charging!", 15, 55, 240, 4)
    else:                             # if not, display the battery stats
        display.text('{:.2f}'.format(get_vsys()) + "v", 15, 10, 240, 5)
        display.text('{:.0f}%'.format(percentage), 15, 50, 240, 5)
    
    display.update()
    time.sleep(0.5)

Unfortunately, no.

Using a voltmeter directly on the batteries:
Galleon: 3.91 volts
BAT0003: 4.07 volts
(Both nominally 3.7v - is this normal?)

I have no idea about what is going on or how to charge my lipos. Help!

1 Like

The Pico Lipo is NOT a W so the old method should work.

ops, saw the Badger 2040W and put the blinders on I think? Pain meds possibly also messing with my brain. Sorry about that Tony.

Went and had a look at the code I was using on my last Pico Lipo setup. Looks to be what you posted above Tony. I just displayed the values without the extra graphics.

vsys = ADC(29)              
charging = Pin(24, Pin.IN)
conversion_factor = 3 * 3.3 / 65535
full_battery = 4.2
empty_battery = 2.8

while True:
    voltage = vsys.read_u16() * conversion_factor
    percentage = 100 * ((voltage - empty_battery) / (full_battery - empty_battery))
    if percentage > 100:
        percentage = 100.00
    
    display.set_pen(green)
    display.text('battery  {:.0f}%'.format(percentage), 15, 300, 240, 3)

Ordered an Lipo Amigo Pro. Hope that sorts things out!

I still do not understand the battery percentage readings shown on the Badgers or why the battery cross out icon is shown while running just on battery. ???

So far I’m only running the old (not a Pico W) code on my Tufty and its Pico Lipo Clone setup.
The Tufty is using standard non rechargeable batteries. It usually only ever runs on battery if we have a power failure. The clone gets put in my pocket and run on battery several times a day. I had a Pico Lipo so that was what I used.
I have an Amigo Pro I plan on using with a Pico W. Might be a while before I wire it up and test it though. I have to go find my round 2it. ;)

Hmmm? On my Tufty I’m doing it this way?

# set up the ADCs for measuring battery voltage
vbat_adc = ADC(29)
vref_adc = ADC(28)
vref_en = Pin(27)
vref_en.init(Pin.OUT)
vref_en.value(0)
usb_power = Pin(24, Pin.IN)

full_battery = 4.5
empty_battery = 2.5

while True:
    vref_en.value(1)
    
    vdd = 1.24 * (65535 / vref_adc.read_u16())
    vbat = (
        (vbat_adc.read_u16() / 65535) * 3 * vdd
    )

    vref_en.value(0)

    # convert the raw ADC read into a voltage, and then a percentage
    percentage = 100 * ((vbat - empty_battery) / (full_battery - empty_battery))
    if percentage > 100:
        percentage = 100
    if percentage < 0:
        percentage = 0

            display.set_pen(green)
            display.text("Battery", 0, 0, scale=3)
            display.text("{:0.2f}v".format(vbat), 150, 0, scale=3)
            display.text("{:0.0f}%".format(percentage), 255, 0, scale=3)
        

Ok, for my Tufty I used this example.
pimoroni-pico/battery.py at main · pimoroni/pimoroni-pico (github.com)
And on my Pico Lipo I used this code.
pimoroni-pico/battery_pico.py at main · pimoroni/pimoroni-pico (github.com)
And for my Pico W I used the new code I posted above.

The first two are, as far as I can tell, working as advertised.
The Pico W code I haven’t fully tested yet.

The Tufty code works on my Tufty and I get 3.98v on one battery and 4.07v on the other. Thanks, I can now see how much juice in each but plugging and unplugging is rather a fiddle!

On my Pico Lipo only the power LED ever comes on. I think there is a fault as the charging LED should light up if the display says it is charging and the voltages are low.

Thanks

The charging LED on my Pico Lipo comes on RED when I plug power in via the USB C jack. Then turns off when the battery is fully charged.
charging = Pin(24, Pin.IN)

    if charging.value() == 1:         # if it's plugged into USB power...
        display.text("Charging!", 15, 55, 240, 4)

If you check the status of the charging pin, what does it show?

charging.value() ==1 because the message appears. Unfortunately, the charging LED does not come on as well. I suspect a hardware fault in the Pico Lipo charging circuit.

Yeah, I think your right. There is a jumper on the back side to disable the onboard battery protection circuit. It would be safe to bypass it " if " the attached battery has its own protection. I’d have a good look on the back for maybe a missing component or a short where there shouldn’t be one.

Wired up my Amigo Pro to a Pico W setup.
With just the GND, and VDEV wired to VSYS, battery state of charge is displayed. Not sure its correct though? It’s seems to be stuck at 50%. And no way of knowing if its being charged, other than the indicator on the Amigo Pro. There is no detection of power being applied to the Amigo Pro via the python code. Battery will only charge if power is being feed to the Amigo Pro USB C jack. The On Off button on the Amiga Pro works. Need to do more testing in this mode to see if the code needs to be changed?

If I also wire up the +5V from the Amigo Pro to VBUS, the charging indication function works. And my battery state of charge now shows 90% when running only on battery. Which is about right, as it was fully charged when I put that battery in storage. Battery will also be charged if you power the Pico W via its Micro USB Jack. The ON Off button only works when “only” on Battery Power though.

EDIT: Charging LED turned off while I was typing this post

EDIT: 2
After running about 4 hours battery state went down to ~60%. That’s about right I think. It’s running a PICO W, two 320x240 LCD’s, and a couple of i2c breakouts. It’s one 2200 mAh battery, and I haven’t run this setup from battery before. Not for any length of time anyway. Just to test my code.

Thanks for your input. I’ve given up on charging with the Pico Lipo for the moment and will wait for the Amigo to arrive - probably Tuesday.

Eventually managed to find myself a Pico LiPo that I hadn’t built into something :)

The battery example is working as expected for me both when charging and when not, so I agree that it looks like there may be something awry with your Pico LiPo.


In response to your other questions…

  • A nominal voltage 3.7V LiPo battery can give out up to around 4.2V when it’s fully charged. This is why it’s important not to plug them into things that only expect alkaline voltages (like micro:bit).

  • Since the addition of the most recent power saving code which turns off the RP2040 voltage the Badger launcher doesn’t stay awake long enough to get a stable voltage reading. We’ll probably remove the icon from the launcher when we update the Badger examples to match the new Badger W/PicoGraphics version - there is a standalone battery reading example though.

Thanks @Hel I’ll use the Amigo Pro to charge and a volt meter to check the charge. I think the charging circuit on my Pico Lipo has had it. All other functions appear to be OK.

That’s more like it!

2 Likes