Display on during deep sleep?
-
@watson, thanks for the screenshot. However, this solution doesn't work. As mentioned in my original post, the problem is that
esp_deep_sleep_start()
itself turns off the display. So changing thepowerOFF()
function won't solve the problem.In fact, try this minimal sketch and see how sleeping turns off the display.
#include <M5Stack.h> void setup(){ M5.begin(); M5.Lcd.println("Setup"); } void loop() { if(M5.BtnA.wasPressed()) { // wake up after 5 seconds esp_sleep_enable_timer_wakeup(5000000); // start deep sleep. Display goes out! esp_deep_sleep_start(); } M5.update(); }
Can we have the display on during deep sleep at all?
-
Hello, @m5er ESP32 can enter 5 kinds of power saving modes. esp_deep_sleep_start(); means deep sleep mode. You can try the light sleep mode by using esp_light_sleep_start()
You can refer to this article.
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/sleep_modes.htmlLooking forward to your good news~
-
Thanks @watson. As I mentioned, I also tried with light sleep, but the display again turns off. Do you know of any command to put the ESP in sleep mode without turning off the display?
-
Is there a solution to this problem? I find it really strange that we can't have the display on during light/deep sleep. This harms all kinds of low-power applications that rely on a screen.
-
I can't believe this problem has no solution: keeping the display of M5stack ON during light or deep sleep. It should be trivial and yet no one on this forum can present a working solution. This seems to be an impossible task!
-
@m5er said in Display on during deep sleep?:
I can't believe this problem has no solution: keeping the display of M5stack ON during light or deep sleep. It should be trivial and yet no one on this forum can present a working solution. This seems to be an impossible task!
The reason no solution exist is because having the screen on goes against the purpose of deep sleep and also because it’s such an unusual question that you have asked, no one has yet to think of a solution in the esp32 world.
Please be patient, M5Stack is still a young project and not everything is thought off until the end user posses a query. If you discover a way to do please let us know but in the mean time please continue to wait patiently.
-
I agree with @ajb2k3 that M5Stack is a young project, so that indeed explains the lack of such queries. However, I don't think my use case is unusual - I can think of a lot of applications that would benefit from sleeping while the display is on, such as: a clock showing hours and minutes only (so waking up only once a minute); sensor monitoring application (e.g. temperature, humidity, etc.) that constantly displays the latest values and wakes up once each X minutes to update measurements; displaying the number of twitter followers, likes, page visits, etc. In all these use cases it is useful to have the CPU sleep most of the time while the display remains on.
In any case, it would be great if someone can present a working solution. It is probably just a few lines of code, but I just can't seem to get the right ones.
-
Thank you.
What some people dont know is that the esp32 is not like an arduino.
the esp32 has 3 cores, 2 primary and 1 Ultra Low power.
In true deep sleep, the primary core are deactivated and the basic "Upkeep" code is off loaded to the ULP.
Because the M5Stack is based on the ESP32 and not much is understood about the ULP, very little progress has been made on deep sleep.
In theory, from what I have read the ULP could maintain a low power screen for a Like (to use your example) and then wake up the core to take the sensor measurements before storing them (for the ulp to recall and display) putting the cores back to sleep.If you are interested in leaning more, look into the ESP32's ULP (Ultra Low Power core)
-
@m5er said in Display on during deep sleep?:
dernières valeurs et se réveille toutes les X minutes pour mettre à jour les mesures; affichage du nombre d'abonnés twitter, de likes, de visites de pages, etc. Dans tous ces cas d'utilisation, il est utile de laisser le CPU dormir la plupart du temps pendant que l'affichage reste allumé.
Dans tous les cas, ce serait bien si quelqu'un pouvait présenter une solution de travail. Ce n'est probablement que quelques lignes de code, mais je n'arrive pas à trouver les bonnes.Hello,
I'm editing this old post... Do you have a solution?
Pierre
-
Random Nerd Tutorials published by Rui and Sara Santos have a tutorial how to use the deep sleep mode on the ESP32and how to store data in the RTC memory:
https://randomnerdtutorials.com/esp32-timer-wake-up-deep-sleep/
I havn't tried it out yet, but it probably should also work with the M5Stack ESP32.
@PierreD Tu trouves une code exemplaire de programmation pour le sub-ordnateur ESP32-RTC au site de Rui et Sara Santos à https://randomnerdtutorials.com/esp32-timer-wake-up-deep-sleep/
bonne chance crami25
-
Hello Crami25,
Thank you for your help.
I took the time to try, to test.For sleep, it's OK.
I made a small example but it doesn't work every time ???On the other hand, I wish to wake up with the buttons.
I've searched the schematics:
Button A GPIO39
Button B GPIO38
Button C GPIO37Following the example of this site:
https://randomnerdtutorials.com/esp32-external-wake-up-deep-sleep/ext0
In this example, the ESP32 wakes up when the GPIO 33 is triggered to high:esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1); //1 = High, 0 = Low
Instead of GPIO 33, you can use any other RTC GPIO pin.#include <M5Stack.h>
#define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds /
#define TIME_TO_SLEEP 10 / Time ESP32 will go to sleep (in seconds) */
//#define BUTTON_PIN_BITMASK 0x8000000000void setup()
{
Serial.begin(115200);
M5.begin(true, false, true);
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds");esp_sleep_enable_ext0_wakeup(GPIO_NUM_39,0); //1 = High, 0 = Low
//esp_deep_sleep_start(); //entre en someil profond
}
void loop() {
M5.update();// update button state
if (M5.BtnA.wasReleased())
{
esp_sleep_enable_ext0_wakeup(GPIO_NUM_39,0); //1 = High, 0 = Low
}if (M5.BtnB.wasReleased())
{
esp_deep_sleep_start(); //entre en someil profond
}if (M5.BtnC.wasReleased())
{
M5.Lcd.fillScreen(WHITE);
M5.Lcd.setTextColor(BLUE);
M5.Lcd.setBrightness(100);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(40, 60);
M5.Lcd.print("Temperature: ");
}
} -
-
@m5er During deep sleep the LCD background led draws(a lot of) current. Also you have to refresh your screen 50 times per second
The only solution to your problem would be adding an e-ink display which doesn't need any refresh during deep_sleep. -
Hello all
the reason nothing can be seen on the LCD during deep sleep is that the backlight is off. The LCD backlight is driven by GPIO32 (PWM) which is stopped when the ESP32 goes into deep sleep. Luckily GPIO32 can be controlled by the Ultra Low Processor (ULP) too. Below is a small test program which implements PWM for GPIO32 with ULP C macros / assembler.
Cheers
Felix#include <M5Stack.h> #include "esp32/ulp.h" #include "driver/rtc_io.h" const int lcdBrightness = 1; // (1-255) void ulp_start(void) { // Slow memory initialization memset(RTC_SLOW_MEM, 0, 8192); // M5Stack LCD backlight is connected to GPIO32 (specify by +14) const gpio_num_t lcdPWMPin = GPIO_NUM_32; const int lcdPWMBit = RTCIO_GPIO32_CHANNEL + 14; // GPIO32 initialization (set to output and initial value is 0) rtc_gpio_init(lcdPWMPin); rtc_gpio_set_direction(lcdPWMPin, RTC_GPIO_MODE_OUTPUT_ONLY); rtc_gpio_set_level(lcdPWMPin, 0); // Define ULP program const ulp_insn_t ulp_prog[] = { M_LABEL(1), I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 1), // on I_DELAY(lcdBrightness * 100), I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 0), // off I_DELAY(25500), M_BX(1), }; // Run ULP program size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); ulp_process_macros_and_load(0, ulp_prog, &size); ulp_run(0); } void setup() { M5.begin(true, false, true, false); M5.Power.begin(); M5.Lcd.println("Put something onto the LCD..."); ulp_start(); M5.Lcd.println("Going to deep sleep"); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); esp_deep_sleep_start(); } void loop() { }
-
@felmue Thanks for the above routine. Works well. However i was storing a RTC_bootCount so i could display a sequence of images on the screen after waking from sleep. However it seem the ulp over rights the bootCounter stored there. How do i need to change the above code to preserve the RTC_bootCounter?
i tried this but never worked, I am new a ULP coding, so not sure how to locate a free memory space in ULP memory. and retrive it back into the main routine.
// Define ULP program
const ulp_insn_t ulp_prog[] = {
I_ST(ulp_bootCount, R0, 0), // trying to store my bootCounter
M_LABEL(1),
I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 1), // on
I_DELAY(lcdBrightness * 100),
I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 0), // off
I_DELAY(25500),
M_BX(1),
};
and in my main code use ++ulp_bootCounter;
please help . Thanks AndyT -
Hello @AndyT
please have a look at the following example which stores variables after the ULP code: deep sleep example
Cheers
Felix -
This post is deleted! -
@felmue Thanks for the link. Lot of code to sift through , spent hours trying to get clues from it. Tried snipets of code out of it, But still can't fully understand what' the problem is. I think i am missing a fundamental principle, how after a SLEEP the esp32 loads all it's variables which would include
RTC_DATA_ATTR int bootCount = 0;
So no wonder it is 0 when the main loop runs, as it is always being set to 0 on wake up. So confused about this from the outset the code even worked in the first place.
But it did work until i introduced the ULP program to PWM a GPIO while sleeping to keep my esp32 M5Stack LCD back light pin operating.
if I don't call the ulp_start(void) routine before sleeping then the ++bootCount increments on each wake just fine.
Why is the below code effecting the RTC_DATA_ATTR int bootCount = 0; ???
what do i need to add to fix it?
I am using the Arduino IDE. So maybe there is an issue on where the Config is assigning the RTC_ to fast or slow ULP memory. I really can't fathom it out. why calling ulp_start(void) resets my counter to 0. Please give me an explanation and solution. Cheers Andy
void ulp_start(void) {
// Slow memory initialization
memset(RTC_SLOW_MEM, 0, 8192);
// M5Stack LCD backlight is connected to GPIO32 (specify by +14)
const gpio_num_t lcdPWMPin = GPIO_NUM_32;
const int lcdPWMBit = RTCIO_GPIO32_CHANNEL + 14;
// GPIO32 initialization (set to output and initial value is 0)
rtc_gpio_init(lcdPWMPin);
rtc_gpio_set_direction(lcdPWMPin, RTC_GPIO_MODE_OUTPUT_ONLY);
rtc_gpio_set_level(lcdPWMPin, 0);
// Define ULP program
const ulp_insn_t ulp_prog[] = {
M_LABEL(1),
I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 1), // on
I_DELAY(lcdBrightness * 100),
I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 0), // off
I_DELAY(25500),
M_BX(1),
};
// Run ULP program
size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t);
ulp_process_macros_and_load(0, ulp_prog, &size);
ulp_run(00);
} -
@andyt coming From a background of coding 8bit PIC's etc, I have a fare grip on assembler language. So once i get to grips with this ULP coding methods . My next step will be to add a routine to check battery level% change and wake from sleep to update the LCD battery level icon. As at the moment while it is sleeping with the LCD on the M5stack could run out of power and shut down. Or stay displaying the wrong battery level while it sleeps as at the moment it only updates while awake. Just need to get my head around the fundamentals of data handling and storage and setup of ULP. Good that there is more info on this topic these days. Exciting times!!![
My M5stack waking up and quickly turning on wifi, grabbing my local environment agency river levels .and showing the levels and if they are rising or falling triggering speaker alarms and displaying waring icons when reaching or above flood levels. To conserve battery it is asleep while the backlight remains on at a duty cycle dependant on battery level. Getting dimmer as the battery % lowers for 10 minutes minimum and then display the weather forecast from a weather API. cycling through these screens quicker or slower depending on the level of importance to the viewer. So while the river levels are low the weather will be displayed longer. pressing one of the front buttons wakes the device and scrolls to the next page, so that the user can look through the pages at a glance. It's like doing a painting. Always improving to the code to finished slick working device. next stage is to right a nice routine for a user interface to input their own wifi and postcode location. So the device can select local levels and weather. -
Hello Andy
ULP code and ULP variables share the same area of RTC_SLOW_MEM which is about 8 kB. Right now your ULP variable is reset to 0 at every boot since all of that area is reset to 0 by this command:
memset(RTC_SLOW_MEM, 0, 8192);
. In addition the ULP code and your ULP variable both are located at the same offset 0 in that area.ulp_process_macros_and_load(0, ulp_prog, &size);
In order to fix this the RTC_SLOW_MEM needs to be orgnanised, e.g. the ULP variables need to be located after (or before) the ULP code and the area used for ULP variables needs to be excluded from being cleared to 0 at every boot.
There are many ways to solve this. In the example I've linked earlier ULP variables are located shortly after the ULP code (offset 36). The solution I've chosen puts the ULP variables into the last of the eight 1 kB blocks of RTC_SLOW_MEM. That leaves more than enough space (the first 7 kB) for ULP code.
Note: Next to the boot count ULP variable I've added a second ULP dummy variable to illustrate how multiple ULP variables could be handled.
Cheers
Felix#include <M5Stack.h> #include "esp32/ulp.h" #include "driver/rtc_io.h" const int lcdBrightness = 50; // (1-255) // RTC slow memory map (vars are in the last 1 kB of total 8 kB) // Note: all ULP commands / vars are 4 bytes in size const size_t rtc_slow_mem_total_size = 2048; // 8 kB = 4 * 2048 const size_t rtc_slow_mem_vars_space = 256; // 1 kB = 4 * 256 const size_t rtc_slow_mem_vars_start = rtc_slow_mem_total_size - rtc_slow_mem_vars_space; const size_t rtc_slow_mem_prog_start = 0; const size_t rtc_slow_mem_prog_space = rtc_slow_mem_total_size - rtc_slow_mem_vars_space; // 7 kB const size_t ulp_boot_count_var_offset = 0; const size_t ulp_dummy_var_offset = 1; void ulp_start(void) { // RTC slow mem init (except space allocated for vars) memset(RTC_SLOW_MEM, 0, rtc_slow_mem_prog_space * sizeof(uint32_t)); // M5Stack LCD backlight is connected to GPIO32 (specify by +14) const gpio_num_t lcdPWMPin = GPIO_NUM_32; const int lcdPWMBit = RTCIO_GPIO32_CHANNEL + 14; // GPIO32 initialization (set to output and initial value is 0) rtc_gpio_init(lcdPWMPin); rtc_gpio_set_direction(lcdPWMPin, RTC_GPIO_MODE_OUTPUT_ONLY); rtc_gpio_set_level(lcdPWMPin, 0); // Define ULP program const ulp_insn_t ulp_prog[] = { M_LABEL(1), I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 1), // on I_DELAY(lcdBrightness * 100), I_WR_REG(RTC_GPIO_OUT_REG, lcdPWMBit, lcdPWMBit, 0), // off I_DELAY(25500), M_BX(1), }; // Run ULP program size_t size = sizeof(ulp_prog) / sizeof(ulp_insn_t); ulp_process_macros_and_load(rtc_slow_mem_prog_start, ulp_prog, &size); ulp_run(rtc_slow_mem_prog_start); } void setup() { M5.begin(true, false, true, false); M5.Power.begin(); M5.Lcd.println("Put something onto the LCD..."); if(esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TIMER) { M5.Lcd.println("Woken from timer"); RTC_SLOW_MEM[rtc_slow_mem_vars_start + ulp_boot_count_var_offset]++; } else { M5.Lcd.println("Woken after reset"); RTC_SLOW_MEM[rtc_slow_mem_vars_start + ulp_boot_count_var_offset] = 0; RTC_SLOW_MEM[rtc_slow_mem_vars_start + ulp_dummy_var_offset] = 4711; } M5.Lcd.println(RTC_SLOW_MEM[rtc_slow_mem_vars_start + ulp_boot_count_var_offset]); M5.Lcd.println(RTC_SLOW_MEM[rtc_slow_mem_vars_start + ulp_dummy_var_offset]); ulp_start(); M5.Lcd.println("Going to deep sleep"); esp_sleep_enable_timer_wakeup(5000); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); esp_deep_sleep_start(); } void loop() { }