Badger power states

Hi, I’m still working on a battery-powered Badger2040 thing and am looking for some more details on minimising power consumption. My project is designed to do nothing until a button is pushed (could be hours, days, weeks), at which point the code runs once, updates the display with the current time (from an RTC breakout board), and shuts itself down again.

I understand the RP2040 has a couple of different power-saving modes but I can’t tell what’s available to use on the Badger?

  • I’ve mostly come to terms with the Badger needing one of the buttons pushed to power-up, before one of the other buttons can actually trigger something to happen when running on batter power (Badger2040 does not wake up after deep-sleep). This is baffling given the focus on having it around your neck instead of plugged-in to a power brick, but I guess realistically there’s nothing I can do besides jamming one button down/shorting it out on the board? I really don’t want to have to put together an external power management PCB.

  • The examples end with a .halt() command; does this actually do anything to the power state of the RP2040, or does it just stop the processor?

This project is intended to be a memory aid for an elderly person so I’m just giving them one button to push when they do something, and the epaper screen will tell them when they last did it. I’m hoping there’s a way I can use the proper low-power states to save batteries, because if it needs a fresh set every month or two then it’s a non-starter unfortunately.

For your use-case, the badger is perfect and you cannot do much better: you have two options for optimizing power: use the RP2040 possibilities, or do it from outside. And that is what the badger-electronics does. You push a button, this turns on the RP2040, your program runs and then finishes. Then the badger-electronics turns of power. The builtin electronics does not need much battery, so this is a perfect setup, much better than the RP2040 can do.

If you need the badger to start automatically, then you have a problem, because the badger is not made for that. But that is not your use-case.

I’m very new to Python so I’m basing things closely off the Pin Interrupt example here (pimoroni-pico/ at main · pimoroni/pimoroni-pico · GitHub ) but unless I’m missing something not covered in that example, when on battery power there has to be one button held down at all times for any other button to trigger an interrupt- this is the case with the default BadgerOS that the Badgers ship with too. The onboard LED flashes for about a second when any button is first pressed, and then any other button press triggers an interrupt.

I’ve seen it mentioned on the forums that this is operating as intended, pressing any button (or connecting USB) enables the 3.3V supply to the rest of the board. Looking at the Badger schematic again though, I now see there’s a 3V3_EN output signal connected to GPIO10/Pin 13 on the RP2040 chip, so I guess my next step is going to be to see what happens if I set that high when my program initialises. I think there may still be an issue as the pin that was pressed probably won’t trigger an interrupt when it’s let go, and there’s a good chance it will be released before the Badger has had a chance to enable power for itself (assuming it can at all).

Your use case is much easier. You don’t need to worry about interrupts. When you press any button, your program starts, updates the display and stops. If you need different functions on the five available buttons, you have to think about interrupts. But you have written about “one button” - I hope I did not get that wrong. But even then I would not keep the RP2040 running, I would rather poll the keys after the program starts.

Well there’s one button for the end-user to deal with, but the other buttons were going to be used for a menu to change the time, 12/24hr mode etc.

I’ve now tried setting pin 10 to high as the first thing the program does after initialising the Badger, but this does not enable the 3.3v regulator on the board, unless I’m doing something wrong? This is what I added immediately after instantiating the Badger -

pin_power_on = machine.Pin(badger2040.PIN_ENABLE_3V3, machine.Pin.OUT)

but running on battery power it’s still the same. I also tried with a 10 instead of PIN_ENABLE_3V3 with the same result.

I have to push and hold any button, then the white LED comes on and goes off after a second, and then any subsequent button push (while still holding the first button) actually gets through to the code and starts an update. Just pushing a single button once momentarily does not power the board for long enough to even light the LED, never mind for the time it takes to update the epaper screen.

So let’s summarize your options:

  • train your users to long press a button, maybe aided with a small buzzer that starts to sound once the pico has started. Once up and running, you can use interrupts or whatever to process other buttons as long as the pico is running (use an endless loop at the end of the program). But note that you need some logic in this case to stop the pico again (e.g. no button pressed for x minutes). For this scenario, battery usage will be minimal

  • prevent shutdown of the badger to keep the buttons reactive to short presses. The problem here is that this drains the battery quite fast, since the pico draws about 25mA if it is running constantly. Note that MicroPython does not yet support (deep) sleep-modes for the pico.

  • same as the second option, but switch to CircuitPython. This dialect supports deep-sleep, so you could keep the buttons reactive and still save a lot of battery capacity (CP deep-sleep with pin-alarm is about 1.5mA). Even in this mode, the actual wakeup button-press cannot be captured by the program, this is due to the nature of how this is implemented. And again, you need the program to run in an endless loop to detect button-events and some logic to decide when to enter deep-sleep again.

I hope this helps to decide which way to go. Every options has some pros and cons, and there is no best solution.

Thanks for your advice; do you have any idea why setting the Enable 3v3 pin to “on” didn’t have any effect on the 3.3V regulator? From the regulator datasheet, anything over 1.5V should switch it on so I can only think that I’m either driving the wrong pin, I’m driving the pin wrong, or it doesn’t work.

I guess going down the CircuitPython route is probably the next best option if I can figure that out, although there’s effectively only one example sketch to work from in that case and my python is decidedly ropey.

I would have to see your program to answer your first question. I could imagine this reason: If the program does not have an endless loop at the end, the program finishes and the pico shuts down, therefore all pins driven high would return to their default state.

Don’t be afraid of CircuitPython. I actually use it most of the time, since it is far easier to work with and the available code-base is huge. There are a few drawbacks, but I never hit any limits I could not work around. If you need help, just ask.

And I have a Badger2040-clock program already, which you could use as a starting point: GitHub - bablokb/circuitpython-clock: A Clock for E-Ink Displays like the Badger2040 or Magtag. It is still work in progress, e.g. the installation instructions are missing, but you can have a look at src/ and see how the screen is created and how the deep-sleep logic works. Don’t be offset by some of the advanced python-trickery, the basic logic should be clear (at least I hope so).

And if you really want to try it, just put some pressure on me and I will write up the install instructions :-)

1 Like

Ah ha, you were right about the endless loop! I had a .halt() at the end of the program instead of at the end of the button handler (thanks Python relying on non-printing characters for code structure, grumble grumble). Without that the board does now power-up and stay powered-up from a momentary push of any of the front buttons. But not the rear User button, because of course that’s the one that I was planning to use, and it’s not connected to the enable line because it’s active-low.

Curiously the board remains powered-up even if I don’t set the PIN_ENABLE_3V3 output in code, so that must be getting set by the board firmware?

So my next steps are going to be changing the code so it triggers itself on power-up, and changing the hardware design to push one of the front buttons instead of the one on the back. I think I’ll probably just call my button handler before the final ‘while True’ loop, that way if I plug it in on USB the debug screens will still work as normal.

I guess the answers to my original questions are -

  • The RP2040 sleep states don’t currently work on the Badger2040. However the firmware means the board will usually remain powered-up after you push one of the front buttons, until it hits the end of the program (or you call .halt() ).

  • The .halt() command stops the Badger2040 from running, which includes killing the enable signal to the 3.3V regulator, effectively ending power draw until one of the front buttons is pressed again.

Thanks again for your help in figuring this out!

Exactly, it is defined here: pimoroni-pico/wakeup.S at main · pimoroni/pimoroni-pico · GitHub