Display on during deep sleep?



  • 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.



  • @m5er

    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



  • @PierreD

    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 GPIO37

    Following 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 0x8000000000

    void 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: ");
    }
    }



  • Hey @pierred and @crami25 - no offense, but it looks like you are hijacking this thread to discuss a different topic, i.e. how to wake from sleep. The original topic of this thread is "how to enter deep sleep while keeping the LCD on". This is still not solved and I doubt that it will ever be.



  • @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() {
    }
    


  • @felmue Yes!! Thank you. You are a Genius. Saved me hours. I get it !. It's working in my code.
    0_1604174249013_be97bcb0-73ec-4ef4-aaf0-ad7a9a5c5df7-image.png



  • Hello Andy

    thank you very much. I am happy to hear it works to your liking.

    Happy Stacking!
    Felix