Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: support deep sleep for the RP2350 #2528

Open
sillycowvalley opened this issue Oct 7, 2024 · 10 comments
Open

Feature Request: support deep sleep for the RP2350 #2528

sillycowvalley opened this issue Oct 7, 2024 · 10 comments
Labels
enhancement New feature or request

Comments

@sillycowvalley
Copy link

sillycowvalley commented Oct 7, 2024

I wouldn't know where to start so I asked the One Who Is Wrong With Confidence (ChatGPT) for an example and got some sample code which probably was not worth sharing (so I've deleted the noise I originally posted).

However, I figure we need an open ticket for this feature since this is one of the improvements of the RP2350 over the RP2040.

Would we want to add some RISC-V specific functionality to the RP2040 class for this?
The two typical use cases for deep sleep are:

  • GPIO pin wakeup
  • RTC wakeup
@earlephilhower
Copy link
Owner

I'm pretty sure the code sample you got isn't close to correct, but there are good examples from the RPI folks directly in the pico-examples and the SDK and datasheet docs.

I still haven't found out where my USB power monitor migrated to so don't really have the equipment to do this myself.

If someone wants to give ti a go, I'd be happy to get it in here. The interesting bit will be getting the system and core back into a consistent state after restart. Things like which clocks are on, what the USB state is, which blocks are enabled (ADC, PWM, timer, etc.). Requiring the user to assume the board is equivalent to power on (but with valid RAM) might be fine, but the core internal state will need to be updated to reflect whatever is chosen...

@earlephilhower earlephilhower added the enhancement New feature or request label Oct 7, 2024
@maxgerhardt
Copy link
Contributor

maxgerhardt commented Oct 9, 2024

For the RP2350 there is at least the powman (power manager) API that can switch off certain things. And the CMSIS headers for the ARM Cortex-M33 and the RISC-V Hazard3 probably also have functions to go into a sleep state (wait for interrupt, etc.).

Also related to adafruit/circuitpython#9491 and raspberrypi/pico-playground#48

@seamusdemora
Copy link

seamusdemora commented Nov 7, 2024

I need x-low power consumption from a uC for an off-grid project I've undertaken. I'd like to use the Pico for this as I've done another project (controlling an INA260) using a Pico 1. However: I have tried the dormant example from the Pico Playground on an Pico 1, and it simply did not work for me. I'm not sure it works at all...

I'm posting to ask about the status of "deep sleep" here: does it appear feasible/do-able, any thoughts on the timeline??

My alternative for the Pico is a TI MSP430 - they have sleep examples that actually work :)

@maxgerhardt
Copy link
Contributor

maxgerhardt commented Nov 10, 2024

I just tested some code found in the RP2040 datasheet and ran it on my Pico (1). The DORMANT sleep with GPIO wakeup worked just fine.

Here's the sketch:

#include <Arduino.h>
#include <hardware/xosc.h>

#define GPIO_EXIT_DORMANT_MODE 3 /* connect GP3 to GND once in DORMANT mode */

void setup() {
  Serial1.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  pinMode(GPIO_EXIT_DORMANT_MODE, INPUT_PULLUP); // pull pin that will get us out of sleep mode
}

void loop() {
  if (Serial1.available() > 0) {
    (void) Serial1.read();
    digitalWrite(LED_BUILTIN, LOW);
    // this interrupt source will get us out of the DORMANT mode agin
    gpio_set_dormant_irq_enabled(GPIO_EXIT_DORMANT_MODE, IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_LOW_BITS, true);
    // disable systick now so that no milisecond interrupts will occur
    systick_hw->csr &= ~1;
    // we will get out of sleep when an interrupt occurs.
    // this will shutdown the crystal oscillator until an interrupt occurs.
    xosc_dormant();
    // this will only be reached after wakeup.
    gpio_acknowledge_irq(GPIO_EXIT_DORMANT_MODE, IO_BANK0_DORMANT_WAKE_INTE0_GPIO0_EDGE_LOW_BITS); // acknowledge GPIO IRQ
    systick_hw->csr |= 1; // enable systick again, hope we survived this
    // we don't actually know the time duration during which we were dormant.
    // so, the absolute value ofmillis() will be messed up.
    digitalWrite(LED_BUILTIN, HIGH);
  }
  Serial1.println("hello, world");
  delay(500);
}

note that this was compiled with the USB stack off, so Serial1 is the hardware UART on GP0, GP1.

The sketch waits on a character to be received via UART, then it will set the crystal oscillator into dormant mode. Before that, GP3 is registered as a wakeup source, expecting a falling edge.

With a Nordic PPK2, I was able to measure the current going into the 5V "VBUS" line. So, this measures the entire current draw of the Pico board at 5V, and not just that of the RP2040 processor.

I can clearly see that, once I send the UART character, the current draw drops dramatically, from an average of 23.54mA to 2.10mA (at 5V).

grafik

@maxgerhardt
Copy link
Contributor

The pico_sleep component was also recently updated: https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_sleep

@maxgerhardt
Copy link
Contributor

Mhm, the Pico datasheet claims 0.8mA @ 5V in DORMANT mode (source).. If I manually copy in the pico_sleep and hardware_rosc component from above (with a few mods to get rid of stdio reinit and enable a GPIO pullup) and do a

    sleep_run_from_dormant_source(DORMANT_SOURCE_XOSC);
    sleep_goto_dormant_until_pin(GPIO_EXIT_DORMANT_MODE, true, false); 

I do get down to 1.88mA. Something is still missing here.. maybe a perpiheral is on, or some other component on the board is drawing power. In any case, enough experiments for today.

grafik

@earlephilhower
Copy link
Owner

Off the cuff, maybe try setting all GPIOs to INPUT_PULLUP to avoid wasting any pad power on floating pins?

Also probably want to Serial1.end() to put the UART0 into reset. It's still a digital device running off of some clock even when idle, with input protection FFs/etc. always doing something...

@seamusdemora
Copy link

seamusdemora commented Nov 12, 2024

I just tested some code found in the RP2040 datasheet and ran it on my Pico (1). The DORMANT sleep with GPIO wakeup worked just fine.

Here's the sketch:

@maxgerhardt :

That's a big help - thank you! Uh... where is the "RP2040 datasheet" where you found this?

The pico_sleep component was also recently updated: https://github.com/raspberrypi/pico-extras/tree/master/src/rp2_common/pico_sleep

I think that is for the Pico 2350 instead of the 2040. It appears they have deleted the code they had posted for the RP2040. ?? At least, I can't find it.

@maxgerhardt
Copy link
Contributor

The pico_sleep component works on both RP2040 and RP2350 chips, it differentiates between them using #if (!)PICO_RP2040 at compile time.

@seamusdemora
Copy link

@maxgerhardt

I just tested some code found in the RP2040 datasheet and ran it on my Pico (1). The DORMANT sleep with GPIO wakeup worked just fine.

Excuse me please, but I still don't understand what you mean by "code found in the RP2040 datasheet". Can you provide some clarification - or a link to that code? I have looked in the Raspberry Pi Pico Datasheet, but I find no code in there.

I'm also confused by the source of the code you posted in your earlier comment... It's not the same as this 'hello_dormant' example in the Pico Playground repo. Where do I find this code?

My apologies for acting as a nincompoop, but I'm not really familiar at all with this arduino-pico repository. Can you provide me with a brief pointer to - or explanation - on how to get started with this??

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants