Open RayNieport opened 2 years ago
These two issues appear to be somewhat connected. Removing pico_enable_stdio_usb(project 1)
and pico_enable_stdio_uart(project 0)
from CMakeLists.txt
and commenting out all printf
statements in my code alleviates the lockup issue I mentioned.
I have the same issue with the Pico where I can only enter picosleep mode a couple of times before it enters into sleep mode and doesn't IRQ back to running code. Have you gotten any success with it?
@kyrieandre No success yet. I might attempt to write my own sleep functionality since the pico-extras version seems to be having issues.
I've seen reports that disabling stdio might help the issue, but I need stdio for my use case.
@kyrieandre @ghubcoder @ms1963 I tried disabling stdio entirely just to test, but after about 30 minutes the Pico locked up again. Better, but I need this to run 24/7. Right now my test program simply blinks once per second for five seconds, then goes to sleep. If an interrupt occurs it wakes back up and continues blinking for another five seconds.
So every ~350 sleep cycles it freezes and won't wake back up.
I am using this in conjunction with FreeRTOS. I wonder if anyone else experiencing this issue is using FreeRTOS as well? I don't think it's a problem with the OS but it's a possibility.
I'm seeing this issue as well. I'm not using FreeRTOS but I see the lockup consistently after about 6-10 sleep cycles before I see "PANIC: No user IRQs are available".
Not sure exactly what changed, but I'm no longer experiencing lockup after multiple sleep/wake cycles. I think this had to do with swapping to the official RP2040 FreeRTOS port (the guide I initially followed recommended using the generic ARM M0+ port).
However, I still have the issue with USB not working after the Pico wakes up. My goal is to output debug information via stdio_usb
(all UART pins are used for other purposes in my project). I do run stdio_init_all()
after waking up from dormant mode, but this doesn't seem to help.
Just to add a bit of input- if you use https://raspberrypi.github.io/pico-sdk-doxygen/group__pico__stdio__usb.html to re-initialize the USB stdio, you seem to be able to recover USB control over the Pico (at least using VSCode on Windows 10.) I've not checked about the clocks/etc, but this fixed my issue with not being able to re-use the Pico again without forcing bootsel + restarting it manually.
Edit: seems the Pico doesn't fully recover from dormancy though as others have pointed out... when I try to re-run the code set up to put it into dormancy and then wake, no dice unless I restart the Pico manually. Might just be how I've written but yeah... :(
Any movement forward on this issue? It would be nice to have stable sleep/dormant with complete example code (restoring clocks, working USB serial, etc.)
I'm seeing this same issue with SLEEP (not DORMANT) mode. Without the aforementioned recover_from_sleep function, a second SLEEP does not awaken. However, even with clock restoration, I can only awaken 6 times before user IRQs are exhausted. I am not sure what is consuming user IRQs. If I mark them all unclaimed after awakening, I can maybe wake a few more times, but the Pico still crashes. I'm using USB serial comms.
If you look at the stdio_usb_init
function in pico-sdk/src/rp2_common/pico_stdio_usb/stdio_usb.c
, you'll see where it claims an IRQ:
#ifdef PICO_STDIO_USB_LOW_PRIORITY_IRQ
user_irq_claim(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
#else
low_priority_irq_num = (uint8_t) user_irq_claim_unused(true);
#endif
But low_priority_irq_num
is statically defined in that file so I don't think there's a way to find out what it is at runtime. Instead, you can add this to your CMakelists.txt
file:
target_compile_definitions(myprog PRIVATE
PICO_STDIO_USB_LOW_PRIORITY_IRQ=31)
PICO_STDIO_USB_LOW_PRIORITY_IRQ
needs to be between 26
and 31
(inclusively) so that it passes this assertion:
static_assert(PICO_STDIO_USB_LOW_PRIORITY_IRQ >= NUM_IRQS - NUM_USER_IRQS, "");
Now you can unclaim it before calling stdio_init_all()
or stdio_usb_init()
, e.g.:
user_irq_unclaim(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
clocks_init();
stdio_init_all();
This way you only use 1 IRQ and don't exhaust the available pool.
That explains a lot. It would be helpful if this were placed in the documentation somewhere.
I was just unclaiming all the user IRQs (since I'm not myself using any). That didn't work, but I noticed the aforementioned recover_from_sleep function was re-initing stidio before I was doing that and re-initing myself, so I fixed that. I still got a crash after running a while, but then I removed all stdio/printf and it's been successfully running on two boards for 15 mins now (waking every 10s) so seems good. So while I'd still like to get USB stdio working with sleep (and a full example would really benefit the entire community), at least sleep itself seems finally to be working, after much work.
I played around with this some more and consistently reproduced the lockup. However, it turns out that there is no need to re-initialize stdio at all. Also, if you are using the dormant function (as opposed to the sleep function), there's no need to restore scb_hw->scr
et al. because these are not changed when going dormant. The only thing missing from the hello_dormant example in pico-playground is that the clocks are not re-enabled when the system wakes up.
If using sleep_run_from_xosc()
as is used in the example, the XOSC is automatically restarted upon wake-up but the ROSC needs to be re-enabled explicitly before calling clocks_init
otherwise it will hang. I haven't tried to track down exactly where it's hanging or why but according to the Awaking the Raspberry Pico from deep sleep article, it might be when the system clock is being reconfigured.
If using sleep_run_from_rosc()
, then the ROSC is automatically restarted on wake-up so calling just clocks_init
works. The XOSC will then be restarted in clocks_init
.
void rosc_enable(void)
{
uint32_t tmp = rosc_hw->ctrl;
tmp &= (~ROSC_CTRL_ENABLE_BITS);
tmp |= (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB);
rosc_write(&rosc_hw->ctrl, tmp);
// Wait for stable
while ((rosc_hw->status & ROSC_STATUS_STABLE_BITS) != ROSC_STATUS_STABLE_BITS);
}
int main()
{
.
.
.
sleep_run_from_xosc();
.
.
.
// Go to sleep until we see a high edge on GPIO 10
sleep_goto_dormant_until_edge_high(10);
// back from dormant state
rosc_enable(); // No need if using sleep_run_from_rosc
clocks_init();
uint i = 0;
while (1) {
printf("XOSC awake %d\n", i++);
}
.
.
.
}
While avoiding stdio_init_all
will prevent the lockup issue, it unfortunately doesn't solve the USB connection from dropping 😞. It's pretty much a crap shoot as to whether you'll have USB output or not. I believe this is related to the USB clock being stopped but not really sure. For debugging purposes, you may be able to recover enough times when using USB but for the longer term, a UART solution may be more suitable.
I've not played around with the sleep functionality yet but based on the hello_sleep example, I see why the RTC clock was not stopped in sleep_run_from_dormant_source
. However, it is not needed for dormant mode and seems like clocks are left running in dormant mode if not explicitly stopped.
2.16.5 In DORMANT mode (see Section 2.11.3) all of the on-chip clocks can be paused to save power. This is particularly useful in battery-powered applications.
However, even if left running, I don't think it can be used by the RTC anyway, if that's your chosen wake-up method.
If the RTC is being used to trigger wake-up then it must be clocked from an external source.
So it seems like it should be shut down with the rest of them, unless there's another reason to keep it running. Can the RP-2040 keep time while in dormant mode? 🤔 If so, that might be a reason.
Not sure why the peripheral clock is left running either 🤷♂️
My Pico-based board with built-in LCD has been running for just about 24 hrs now on a 220 mAh battery, where before it only got just over 8 hrs, so it seems to be working. This is low power sleeping for 9s with LCD off, then waking and having LCD on for 1s (with just a regular sleep_ms), forever. I agree, I lost USB console not immediately but very quickly (in a minute or two).
I got half a week life on battery, so low power sleep is working. I still haven't made it work with USB IO, it crashes/hangs pretty quickly. I will probably poke at it again, as it's one of my goals for this project, but for now I have to move on to other coding. It would be really helpful if the official examples were updated with all this information, and worked nicely out of the box.
I tried again today (to use USB stdio while also sleeping, by unclaiming user IRQs and reinitializing stdio) and it wakes more than 6 times, but still crashes within about a minute. Not sure why.
One thing I can think of, is I am lazily unclaiming all the user IRQs upon waking (since I don't myself use any), but maybe something ELSE in the SDK doesn't like that.
Another thing I can think to try, is hooking up actual serial and looking for messages printed (panics etc.) to see what the real problem is, but I would have to go looking for a USB to serial cable and get that set up.
I found a solution to the problem leaving the USB and USB PLL clocks always running. In the sleep function sleep_run_from_xosc():
//CLK USB = 0MHz
#if !LIB_PICO_STDIO_USB
clock_stop(clk_usb);
#endif
#if !LIB_PICO_STDIO_USB
pll_deinit(pll_usb);
#endif
In the RTC sleep function sleep_goto_sleep_until():
// Turn off all clocks when in sleep mode except for RTC
#if LIB_PICO_STDIO_USB
clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS|CLOCKS_SLEEP_EN0_CLK_SYS_PLL_USB_BITS;
clocks_hw->sleep_en1 = CLOCKS_SLEEP_EN1_CLK_USB_USBCTRL_BITS|CLOCKS_SLEEP_EN1_CLK_SYS_USBCTRL_BITS;
#else
clocks_hw->sleep_en0 = CLOCKS_SLEEP_EN0_CLK_RTC_RTC_BITS;
clocks_hw->sleep_en1 = 0x0;
#endif
The function to reinit the clocks in the SDK shoud not reinit the USB and USB PLL clocks, make a new function identical to clocks_init() and comment the next section:
pll_init(pll_usb, 1, 1200 * MHZ, 5, 5);
and:
// CLK USB = PLL USB (48MHz) / 1 = 48MHz
clock_configure(clk_usb,
0, // No GLMUX
CLOCKS_CLK_USB_CTRL_AUXSRC_VALUE_CLKSRC_PLL_USB,
48 * MHZ,
48 * MHZ);
The function stdio_init_all(); should not be call every time the PICO wakes up. Replace the call to clocks_init() function with the new function.
Hello from 2023. I faced the same issue of Pico not waking up from neither Sleep nor Dormant. I digged tons of google & github, and all pages stated the same things as in ghubcoder's post. I tried literally everything I found related to sleep modes, tried to study registers and manual clocking settings, nothing worked. Desperate, I started to change random things.
In void sleep_run_from_dormant_source()
, I commented out the last line:
//setup_default_uart();
After this, my Pico wakes up from Dormant by pin. In Dormant, it draws 10 mA, vs 37 mA in active mode. Still too much, keep digging...
UPD: I am using an ST7789 display and it was parasite leakage thru its pins. I deinit'ed SPI and all involved GPIOs, and 10mA were gone. Also, before going to sleep, I am depowering the LCD with a MOSFET.
Hi, thanks for providing this library.
I want to use dormant mode to reduce power consumption when not actively processing something. However this has several issues.
When the Pico wakes back up from IRQ it does not restart the clocks that were disabled by
sleep_run_from_dormant_source()
I've attempted to re-enable all clocks using the following code, which is based on the
recover_from_sleep()
function found here. This article is also useful.While this does get all the clocks back up and running, there are still two issues that I'm aware of:
I've looked around a bit to verify that I'm not the only one experiencing this issue.