Display on during deep sleep?
-
@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() { }
-
@felmue Yes!! Thank you. You are a Genius. Saved me hours. I get it !. It's working in my code.
-
Hello Andy
thank you very much. I am happy to hear it works to your liking.
Happy Stacking!
Felix -
@felmue Seems my Arduino IDE ulp.h does not have a macro I_i2c_RD. And i can't find a way to assemble the raw assembly instruction set i2C_RD. Am i missing something? As i want to take advantage of the the assembly instructions and also the latest set of Macros. Just spent a day going around the internet and came up with nothing. Trying to write ULP code to wake the M5stack when the battery % changes. Sorry again to trouble you.
-
Hello Andy
I am afraid you're out of luck. The
arduino-esp32
library is based on IDF release 3.3 and the ULP macros for I2C seem to be missing / not implemented yet.#define OPCODE_I2C 3 /*!< Instruction: read/write I2C (not implemented yet) */
But even with the macros in place it would probably still not work. According to this info it seems that the ULP only allows for two predefined sets of GPIOs to be used for SDA and SDL, none of which are GPIO21/22 used in M5Stack.
Felix
-
@felmue Thank you again for the prompt replay. Thank you for the info. I drew a blank at the link you provide as well . Also a good find regarding the pin assignments of the hard coded SDA and SDL for channels 0,1. Did find this link for ulp.h using I_i2C_ READ I_I2C_WRITE etc. But could not get the ZIPed Library to install into my Arduino IDE to try it out.
https://github.com/espressif/esp-idf/blob/master/components/ulp/include/esp32/ulp.h
Maybe start a new thread soon on this as i am getting off the original topic here now that your ULP code above fixed the display going off while sleeping. Just for the record now getting 24hrs off two 700mh add on battery modules at well bright 200 brightness level while the 5Stack is sleeping .