Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Power-saving possibilities using the arduino-pico core#1544

Unanswered
NuclearPhoenixx asked this question inQ&A
Discussion options

Hi,

I know that sleep and dormant modes are not supported in this core and I don't want to talk about that here. There are more than enough threads on that by now.

What I'm interested in is, what possibilities are there to save power using this core as it standsright now? Something like, disabling peripherals, not using the second core, downclocking the Pico as much as possible, etc.

I know there are things like__wfi() andsleep_ms() (which doesn't really enable any low-power modes), but honestly, I don't know of much more. So please enlighten me if you know of anything else :)

Feel free to delete this question if you had enough talking about that lol

You must be logged in to vote

Replies: 6 comments 23 replies

Comment options

Just to be clear, I'm not opposed to adding sleep stuff to the core. I just don't have the equipment to do any testing so wouldn't know if it was doing anything or not. So, if someone wants to submit the deep sleep stuff as a PR, I'd be a happy camper. :)

FWIW the most important thing is not to start things you don't need. For example, once ananalogRead happens the ADC clock will run forever. (Although PIOs will be shut off when not in use.)

There's also lots of interesting goodies in the RP2040 datasheet (not the SDK). You can power down individual SRAM banks, for example.

You must be logged in to vote
5 replies
@NuclearPhoenixx
Comment options

Thanks for your input!

@NuclearPhoenixx
Comment options

Another easy way to reduce consumption, what I found out today, is to reduce the core voltage. I'm using the Pico at 50 MHz and can go as low as 0.90V and it saves me about 2mA compared to stock, which is pretty sweet.

I'm using the Pico SDK'svreg_set_voltage() command which is very easy to use.

@cytown
Comment options

50MHz will cause it freeze when using 2 cores. Not test for 1 core codes.

@LinusHeu
Comment options

Random kinda-off-topic thing I just noticed: I think clk_adc runs even without doing any analogRead().
At the top of void setup():

    Serial.begin();while (!Serial) {};delay(1000);    Serial.println(clock_get_hz(clk_adc));    Serial.print("frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC):");    Serial.println(frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC));clock_stop(clk_adc);    Serial.println(clock_get_hz(clk_adc));    Serial.print("frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC):");    Serial.println(frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC));

output:

48000000frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC): 480000frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC): 0
@NuclearPhoenixx
Comment options

50MHz will cause it freeze when using 2 cores. Not test for 1 core codes.

Works for me, even down to about 20 MHz. Although, at this point the USB connection drops out, but the Pico still works otherwise. With 50 MHz, even the serial USB connections works like normal for me.

Random kinda-off-topic thing I just noticed: I think clk_adc runs even without doing any analogRead().

Interesting! 👍🏻

Comment options

It is not a big deal to isolate few files from Pico-SDK (pico-extra) and build an Arduino library for RP2040 'dormant' mode like I did:
https://github.com/lyusupov/SoftRF/tree/master/software/firmware/source/libraries/RP2040_Sleep

then I can use the library as follows:

  Serial1.end();  Serial2.end();  Serial.end();#if defined(USE_TINYUSB)  // Disable USB  USBDevice.detach();#endif /* USE_TINYUSB */  sleep_run_from_xosc();#if SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN  sleep_goto_dormant_until_pin(SOC_GPIO_PIN_BUTTON, 0, LOW);#else  datetime_t alarm = {0};  sleep_goto_sleep_until(&alarm, NULL); /* TBD */#endif /* SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN */  // back from dormant state  rosc_enable();  clocks_init();  rp2040.restart();

However, the RP2040 does not look like a very power efficient SoC.
At least it is true for genuine Raspberry Pico and Pico W boards:

  1. read section 3.1.3 fromPico datasheet
  2. I've got the similar dormant current value withmy own measurement
You must be logged in to vote
3 replies
@NuclearPhoenixx
Comment options

I see, but does this compile with the current core? Because AFAIK you have to build some extra dependencies into to core to get it to run.

@cytown
Comment options

@lyusupov I use your code and run like this:

            Serial.println("start sleep.");            sleep_run_from_xosc();            datetime_t alarm = { 0 };            Serial.println(" wait alarm.");            sleep_goto_sleep_until(&alarm, NULL); /* TBD */            Serial.println(" awake");            // back from dormant state            rosc_enable();            clocks_init();            rp2040.restart();

Then the output stuck at "start sleep.", and never back from sleep... Any clue?

@cytown
Comment options

Just add a libray.json to it and add symlink to the dir will works in platformio.

Comment options

does this compile...

Does this make sense for you ? -
https://github.com/lyusupov/SoftRF/actions/runs/5341411492/jobs/9682198972

You must be logged in to vote
0 replies
Comment options

FWIW, I have been trying various things in my sleep code to whittle down power consumption. I don't have dormant mode working yet, which ought to be the best possibility. But I did figure out that slowing the system clock before sleep is a huge win for power consumption in my fw. Right before sleep it goes to 18mhz:

set_sys_clock_khz(18 * 1000, false);

And then returns to 133mhz on wakeup:

set_sys_clock_khz(133 * 1000, true);

(It might be possible to go slower than 18mhz, but some lower values caused hangs/crashes so I stopped tuning it there.)

I also pause PWM & DMA usage, and of course power down peripherals and LEDs and such. I haven't tried powering off the flash yet, but that's next. ATM, power consumption during sleep is 8ma .

I also tried dormant mode, but I found that some interrupt kept waking it up prematurely. (If I callnoInterrupts() before entering dormant mode, I have the opposite problem: it never wakes up.) I could not figure out what was the source of the interrupt, though. I tried manually clearing the interrupt table & something still woke it up. I wonder if core1 still sends Events to core0 even when it's idle viarp2040.idleOtherCore() ?

Or maybe it's a USB thing; I hadn't triedUSBDevice.detach() but I'll give it a shot.

You must be logged in to vote
2 replies
@matthias-bs
Comment options

Which header files have to be included for using set_sys_clock_khz()?

@NuclearPhoenixx
Comment options

You only needpico/stdlib.h for that.

Comment options

Yesterday I managed to whittle the sleep consumption even lower, from 8ma down to 3ma.

• I got the most improvement by halting the USB PLL during sleep and restarting it on wakeup. This drives the other main clock besides clock_sys. So far, this seems reliable, and it saved about 4ma.

to sleep:

  Serial.end();  pll_deinit(pll_usb);

to wake:

  pll_init(pll_usb, 1, 1440000000, 6, 5); // return USB pll to 48mhz  // High-level Adafruit TinyUSB init code, does many things to get the USB controller back online  tusb_init();  Serial.begin(115200);

• I'm pretty sure I'm not allowed to drop the sys_clk speed any lower than 18mhz with my 12mhz xtal, but I did turn the RPI's internal voltage regulator from 1.1v down to 0.9v during sleep, which saved maybe another 0.5ma. (This is done after slowing the system clock.)

to sleep:

vreg_set_voltage(VREG_VOLTAGE_0_90 ); // 0_85 crashes for me. YMMV.

to wake:

vreg_set_voltage(VREG_VOLTAGE_1_10);

• Putting my flash chip into power-down mode seems to save a tiny scrap of power; datasheet says 0.1-0.5ma . YMMV. Consult your flash chip datasheet and the sdk doc forflash_do_cmd()

With this, current consumption during sleep is down to 0.003A on my ammeter.

I still haven't tried powering down SRAM. I'm not sure how to power down only the SRAM that I'm not using. Also I'm not sure how to estimate the potential power savings. But I'd love to hear about anybody else's experiments with that!

You must be logged in to vote
6 replies
@myklemykle
Comment options

Sure, here is the relevant code section. It's all the tricks described above. Note that I get to 3ma sleep onmy custom board, the Pocket Integrator, which runs at 1.8v when awake. Other boards have other parts, drains, needs, etc. (Also, my ammeter is something I got cheap off of Amazon. It says 3ma, but I've never actually calibrated it.)

// ... after shutting off LEDs, accelerometer, etc ...// idle core 1rp2040.idleOtherCore();// power down analog referencedigitalWrite(Aref_enable, LOW);// reduce clock speed for mega-savings!// 18mhz seems to be my slowest option set_sys_clock_pll(756000000, 7, 6); #ifdef SLEEP_USB// power down USBSerial.end();pll_deinit(pll_usb);#endif#ifdef LOW_VREG// reduce internal chip voltage?vreg_set_voltage(VREG_VOLTAGE_0_90 ); // 0_85 crashes, but 0_90 works & saves close to a milliamp#endif#ifdef SLEEP_FLASH// power down flash// (saves very little power; 10-40ua according to datasheet)#define FLASHBUFSIZ 4        // FYI these commands are specific to my flash chip; yours may be differentbyte flash_ibuf[FLASHBUFSIZ] = { 0xb9, 0, 0, 0 };  // power-down cmdbyte flash_obuf[FLASHBUFSIZ];flash_do_cmd(flash_ibuf, flash_obuf, FLASHBUFSIZ);#endif//////////////////// try to sleep --// until any button pressed,// or activity on wake or play pin.//playPinRose = false; // the playPin-watching ISR will re-true this if play LED lights during sleep.unsigned int napsTaken=0;bool anyButtonPressed = false;unsigned long totalNapTime_ms = awakeTimer_ms;        // FWIW I haven't figured out which sleep_goto_dormant_until_X() call in the pico sdk         // will wake up on activity from any one of a set of pins. That might save even more power.        // Instead, we just take 100ms naps & then test all the pins, over and over ..do {sleep_ms(SLEEPYTIME);// versus doing it this way -- less power in theory, but something keeps waking it up prematurely ...//absolute_time_t t = make_timeout_time_ms(SLEEPYTIME);//best_effort_wfe_or_timeout(t);napsTaken++;if (tempSettings.napWink) { // Wink the debug led every 4 seconds during sleepif (napsTaken % 40 == 1)leds[4].on();else if (napsTaken % 40 == 2)leds[4].off();}                 // pet the watchdogrp2040.wdt_reset(); readButtonsQuick();anyButtonPressed = btn1pressed || btn2pressed || btn3pressed || btn4pressed;} while ( !(// wake up if the play LED has lit, playPinRose // or if any button was pressed|| anyButtonPressed ));//////////////// wake back up:#ifdef LOW_VREGvreg_set_voltage(VREG_VOLTAGE_1_10);#endif#ifdef SLEEP_USBpll_init(pll_usb, 1, 1440000000, 6, 5); // return USB pll to 48mhztusb_init(); // re-init Adafruit TinyUSB library#endif#ifdef SLEEP_FLASHflash_ibuf[0] = 0xab;  // power-up cmdflash_do_cmd(flash_ibuf, flash_obuf, FLASHBUFSIZ);#endifset_sys_clock_khz(MCU_MHZ * 1000, true); #ifdef SLEEP_USBSerial.begin(115200);#endif// power up analog referencedigitalWrite(Aref_enable, HIGH);// wake core 1rp2040.resumeOtherCore();// then wake up LEDs, accelerometer, etc.
@earlephilhower
Comment options

@myklemykle that's some nice work. Do you think it would make sense to include it in the core somehow?

Also, just in general, if you're disabling the flash clocks then you're also going to need to move the code into RAM (i.e.__not_in_flash_func()), no?

@myklemykle
Comment options

I'd be happy to contribute this to core in some format. However the way I'm doing the actual sleeping in the middle of this function -- sleeping until one of N pins is active -- might not be what most people need. So I'm not sure what options to put there instead.

As for the flash thing ... I agree that makes sense, but OTOH I never did move the sleep function into RAM and it still works. Perhaps the entire function is loaded into the XIP cache before it runs?

@myklemykle
Comment options

Also I have to admit that the sleep/wake of USB does not seem to me to be 100% solid. In my testing, if I sleep/wake USB more than 4 or 5 times in quick succession (like within a minute), the host OS (MacOS 11.7 in this case) seems to get grumpy and reject the device until it's unplugged/replugged. I'm not sure if this is an actual fault on the Pico side of if it's something caused by whatever Serial.end() and tusb_init() say to the host if you call them over and over. I'm not even sure that calling tusb_init() multiple times is supported by TinyUSB. So the USB sleep might want to be controlled by an option flag.

@earlephilhower
Comment options

As for the flash thing ... I agree that makes sense, but OTOH I never did move the sleep function into RAM and it still works. Perhaps the entire function is loaded into the XIP cache before it runs?

The XIP cache wouldn't know what a function looks like, but it might have a large enough cache line/prefetch to keep things running in most cases with this code. I wouldn't like to count on that, though...a slightly different placement of the function might end up not making it into XIP before turning off the flash. Real pain in the butt to diagnose in the field after an OTA!

Comment options

Hi,

I have added a few things to achieve a functionality similar to the ESP32's deep sleep mode:
https://github.com/matthias-bs/arduino-pico-sleep

The example also addresses time-keeping using the integrated RTC.

Cheers,
Matthias

You must be logged in to vote
7 replies
@matthias-bs
Comment options

@dlee99 Did it work?

@dlee99
Comment options

Yes, it did. Although I'm only getting down to 12mA, which could be from the previous power issues discussed before in this post and other posts or because I am using the Adafruit Feather rp2040 which may have other peripherals that are using power even when the RP2040 sleeps.

sleep_goto_dormant_until_pin(SELECT, 0, LOW); // wake up on active low.

Also, I ended up not use your library you made. But it is a great reference to see how it's implemented on the arduino-pico core.

@matthias-bs
Comment options

Did you try any of the options suggested in#1544 (comment)?

@dlee99
Comment options

Yes, I tried and only got 1mA difference. From 13mA to 12mA on my multimeter.

This is what I have in place before I put the controller to sleep.

set_sys_clock_khz(18 * 1000, false);
Serial.end();
vreg_set_voltage(VREG_VOLTAGE_0_90); // 0.85v 0_85 indeed does crash and cause the rp2040 to restart.
pll_deinit(pll_usb);

Interesting, nevertheless.

@myklemykle
Comment options

@dlee99 I guess the MCP73931/2 LiPoly charger and the NeoPixel could be the extra current consumers on that board. But the NP is supposed to be only about 1ma at idle, and the charger is supposed to be less than that.
Just curious: are you sleeping the second core?

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Category
Q&A
Labels
None yet
9 participants
@NuclearPhoenixx@earlephilhower@cytown@myklemykle@lyusupov@TDuxis@dlee99@matthias-bs@LinusHeu

[8]ページ先頭

©2009-2025 Movatter.jp