-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Sleep and wake up #696
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
Comments
This is definitely on my radar. I think one of our major releases should focus on battery-operated datalogging. Saving battery life isn't simple because of peripheral and clock management too. I'd also like to tackle flash wear leveling to coincide with that. I'm happy to advise anyone trying to do this earlier but its not a focus for us yet. |
my God, and I thought that it would be only one instruction. It is really complicated thing. |
I am interested in implementing some version of low power sleep for the nrf52840. From looking through the code it bit, it seems like there are timers and loops that need to be run continuously for CircuitPython to function as expected which complicate the issue. My first goal would be to implement a new module to sleep on command. A secondary goal would be to merge the low power code in with the time.sleep function. Could someone give me some pointers on where to start, what things to keep in mind, and what traps you'd foresee? |
We currently use the SysTick timer in all our ports for general timekeeping (msec ticks and smaller): see So This is a substantial change in the timekeeping logic. it's possible, and makes sense, but it requires some thought. |
@crowecawcaw I'd recommend starting without usb and just loading code over a debugger. USB is timing critical and will be unhappy if the background task isn't called. Once you get it going off of usb then I'd start by just disabling sleep when on usb. Later, if needed, we can make it work with usb. |
This may be a silly question but is there a good way to develop and debug the CircuitPython source? Does anyone have suggestions for a free IDE that could make things easier? Right now, I'm editing code, compiling, and refreshing every change but it's difficult to tell what's going on without breakpoints or the like. |
@crowecawcaw, when I was dev'ing primarily on Win10, I used Atmel Studio 7. Breakpoints and I/O registers were a bit of breeze. The [major] downside though was being forced to compile in a VM. It may be possible to overcome that, but I never figured out a way. I did try to get Segger Embedded Studio working as an IDE on Linux and Win10, but never got anywhere with it. On Linux, using GDB became just as fast as AS7 in most cases. Especially after I started using a breakpoints file. That reduced some iteration time by only requiring |
After spending some time looking through the code base, my plan is to make a module that has a function low_power_sleep() that will put the processor in a low power state until the time elapses. From what I can tell, there are 3 types of timers in play:
My thought is to use a general purpose timer for tracking time while sleeping because there are unused timers that can be configured and run without interacting with any other code. The side effects will be that the usb background task will not run and that time.monotonic() and SysTick will not increment while sleeping. Does all of this seem correct? Does my approach seem reasonable? |
I wonder if we should have separate issues for tracking this on different ports? Personally, I would be more interested in being able to wake up on a gpio change than on a timer, so that we can get rid of those power switches from our hardware designs. |
The nRF and SAMD RTCs both tick with 30.5us precision, so it could be used for time.sleep() and time.monotonic() pretty successfully, I think. |
I thought that if an interrupt was firing quickly, it would prevent the processor for staying in the low power state for very long causing the power consumption to remain high. In this instance, the RTC would be triggering interrupts every 30.5us to increment the ticks. By configuring a timer to interrupt less frequently (100ms or so), the processor would be mostly sleeping and its power consumption would remain very low. The power consumption then would not depend much on the type of timer or its clock speed but on how often it interrupts. Am I thinking correctly? |
@crowecawcaw My debug process is documented here: https://learn.adafruit.com/debugging-the-samd21-with-gdb I use it on SAMD51 and nRF too. |
There's a prescaler for the RTC's, so you can divide down the 30.5us ticks to a slower interval. |
Thank you @tannewt and @dhalbert both for the tips! I have a new My code is below: #include <string.h>
#include "py/obj.h"
#include "py/objnamedtuple.h"
#include "py/runtime.h"
#include "supervisor/shared/translate.h"
#include "nrf/timers.h"
static nrfx_timer_t *timer = NULL;
volatile uint8_t timeout = 0;
static void lowpower_timer_interrupt(nrf_timer_event_t event_type, void *p_context) {
if (event_type == NRF_TIMER_EVENT_COMPARE0) {
timeout = 1;
}
}
STATIC mp_obj_t lowpower_sleep(mp_obj_t seconds_o) {
#if MICROPY_PY_BUILTINS_FLOAT
float seconds = mp_obj_get_float(seconds_o);
#else
int seconds = mp_obj_get_int(seconds_o);
#endif
uint32_t ticks = seconds * 31250;
if (seconds < 0) {
mp_raise_ValueError(translate("sleep length must be non-negative"));
}
timer = nrf_peripherals_allocate_timer();
if (timer == NULL) {
mp_raise_RuntimeError(translate("All timers in use"));
}
nrfx_timer_config_t timer_config = {
// PulseOut durations are in microseconds, so this is convenient.
.frequency = NRF_TIMER_FREQ_31250Hz,
.mode = NRF_TIMER_MODE_TIMER,
.bit_width = NRF_TIMER_BIT_WIDTH_32,
.interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY
};
nrfx_timer_init(timer, &timer_config, &lowpower_timer_interrupt);
nrfx_timer_enable(timer);
nrfx_timer_pause(timer);
nrfx_timer_clear(timer);
timeout = 0;
nrfx_timer_compare(timer, NRF_TIMER_CC_CHANNEL0, ticks, true);
nrfx_timer_resume(timer);
while(timeout == 0) {
// __SEV();
// __WFE();
// __WFE();
__WFI();
}
nrfx_timer_disable(timer);
nrf_peripherals_free_timer(timer);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(lowpower_sleep_obj, lowpower_sleep);
STATIC const mp_rom_map_elem_t lowpower_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_lowpower) },
{ MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&lowpower_sleep_obj) },
};
STATIC MP_DEFINE_CONST_DICT(lowpower_module_globals, lowpower_module_globals_table);
const mp_obj_module_t lowpower_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&lowpower_module_globals,
}; |
Hi Guys, sorry to reopen this topic. Is there a circuitpython module that includes this low power feature? I will either be using the Adafruit STM32F405 EXPRESS or the Adafruit M0 Express board and would like to be able to run off the battery supply if possible. Apologies if @crowecawcaw's code is the answer, I am relatively new to circuitpython, and not experienced enough to implement it if it is. |
@NAPtime2 Not yet, but it's high on our agenda for doing after the 5.0.0 release, which is now in beta. |
Excellent. Any idea of a rough timeframe? |
Not really, but sooner rather than later. We generally avoid schedules, to the disappointment of many. 🙂 5.0.0 will be done when it's done, but we're approaching done. |
I started working on this and have nRF working, atmel-samd in progress. I plan on doing STM and iMX RT as well. My work is here: https://github.com/tannewt/circuitpython/tree/lower_power I don't have pin wake yet. Now it is simply that the CPU will sleep when |
I would love to test your low power version. Is it possible to test it on a Trinket M0 ? Cheers, |
Ya! It should work ok on the Trinket M0. Each PR commit has artifacts automatically built. The latest for the lower_power branch are here: https://github.com/adafruit/circuitpython/runs/575104579 Click the artifacts link in the top right and select Trinket_m0. It'll be a zip of all uf2s for the trinket. |
@tannewt An alternative may be to use a TI TPL5100 for deep sleep of the complete circuit. Cheers, |
@volkerjaenisch Ya, I've done enough to confirm that it enters sleep. If I remember right its 4x or 5x less current when idle. An external chip will be much lower power because it can completely turn off the power. The SAMD21 does have lower power modes but they won't match an external chip. |
any progress on the pin wake? Looking at battery powered SAMD51 ... |
@VR-AntHill Nope. I've moved onto ESP32S2 support. Only the nRF52 is getting more refined lower power thanks to @xobs. |
Curious if this is intending to be in Cpy6, or it it will still be a while before this gets rolling again. |
@kdb424 6.0.0 will have light sleep during |
Subsumed by #2796. The original issue has a low-power implementation for nRF. We are doing ESP32-S2 first, but can open issues for other ports. |
Hi, I am sorry for opening similar issue, now without RTC feature.
I missing only one feature, It can very help for battery operated devices.
Sleep and wait for button for wakeup, I thing that it can be great advantage to expand cpython to wearables. This guys make something for sleeping but wake not working https://github.com/edgecollective/circuitpython. Can anybody make this feature?
The text was updated successfully, but these errors were encountered: