Skip to content
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

Partial refresh inbetween deep sleeps #11

Closed
allllo20 opened this issue Mar 5, 2024 · 6 comments
Closed

Partial refresh inbetween deep sleeps #11

allllo20 opened this issue Mar 5, 2024 · 6 comments

Comments

@allllo20
Copy link

allllo20 commented Mar 5, 2024

First of all, thank you so much for this project! It turned e-waste into something usable..

I have a specific problem that I tried in various ways to approach but none seem to work. I'm trying to code a clock with an esp32 that updates the time on the e-paper display after every minute and then goes to deep sleep for the rest of the time. The idea is to do a full update every full hour and the rest of the time should be partial (or fast-)updates.

The GxEPD2 library allows to skip the initial refresh of the display when initializing. I can't find anything similar here. I basically tried the "fast_mode" example but added a deep sleep command like this:

void setup() {
    display.setTextSize(2);
    display.fastmodeOn();

    display.setCursor(0, f.bottom() - 30);
    display.println("Fastmode:");
    display.println("On");
    display.update();

    display.setTextColor(WHITE);
    display.setWindow( f.left(), f.top(), f.width(), f.height() - 35 ); // Don't overwrite the bottom 35px

    for (int demo = 0; demo <= 5; demo++) { // Count up to 5
      display.drawXBitmap(ICON_L, ICON_T, hourglasses[demo % 3], hourglass_1_width, hourglass_1_height, BLACK);
      display.fillRect(0, 0, 30, 30, BLACK);
      display.setCursor(10, 10);
      display.print(demo);
      display.update();
    }
    display.fastmodeOff();

    esp_sleep_enable_timer_wakeup(2*1000000ULL);
    esp_deep_sleep_start();
}
@todd-herbert
Copy link
Owner

todd-herbert commented Mar 5, 2024

Ah yes, I know what you mean.
The fact that the screen clears after a reboot was originally a deliberate design decision. I always figured a bunch of people would reboot with an existing image on the screen, and then end up with it smearing together with the first fast-mode update.

I hadn't actually considered a situation where the device is waking from deep-sleep, but it's definitely an important use case. It would be nice to disable the clear-at-boot behavior if the library can detect that a device is waking from sleep, but this might be a bit fiddly to implement across all the different platforms. I will probably look into though.

For now, it shouldn't be hard to add an optional argument to bypass the clear-at-boot- behavior. I should be able to get this out in the next few hours.

@todd-herbert
Copy link
Owner

Hmm, okay. I've had a look at the library code. Apparently only devices with limited RAM, such as Arduino Uno, actually enforce a full-refresh clear at boot. With ESP32, no refresh takes place, but the library does wipe the memory.

I will get an update out shortly, which allows bypass of this initial memory wipe.


If I remember, this memory wipe is done to clear the white-noise pattern which fills the display memory if power is removed for >10 seconds. This memory loss is problematic for fast-mode, due to what goes on behind-the-scenes.

For a normal refresh, no problem: the display just blinks and flashes until all the pixels are wrangled into the right spot. For fast-mode though, the display hardware needs to keep track of two sets of data: the new image for update, and the existing image on screen. When the update happens, the display only moves pixels which have changed between the old and new image. It is really a "differential update".

If the display loses power for an extended period (>10 seconds), the memory will be lost, and the display will believe that the "existing image" is just a white-noise pattern. It will be unable to move the correct pixels for a fast-mode update.

I mention this because I see you are trying to minimize power usage with esp_deep_sleep_start().
I believe the displays have quite a low current-draw at standby, however this library does not put them into a true "deep-sleep" state. The reason is that Heltec did not break out the display's reset pin, so the only way to exit the "deep-sleep" state is to completely remove power from the display.

The library does have code to support this, however it is not currently suitable for your use-case. The custom power switch feature is designed to remove all power from the display. It was not written with the intention of using the display's "deep-sleep" method. Because extended power-removal causes display memory loss, it is not possible to use fast-mode immediately after customPowerOn().

What I can look into is writing separate methods to allow the same transistor set-up to use deep-sleep, and then a short power-down (>4s, <10s) to escape the deep-sleep mode. This might allow fast-mode directly after deep-sleep.

Let me know if you think this last option might be helpful, and I can prioritize exploring.

@todd-herbert
Copy link
Owner

todd-herbert commented Mar 6, 2024

What I can look into is writing separate methods to allow the same transistor set-up to use deep-sleep, and then a short power-down (>4s, <10s) to escape the deep-sleep mode. This might allow fast-mode directly after deep-sleep.

I experimented with this today, but there was no appreciable power-saving. Without a physical RST pin, I don't think these Heltec displays can really make use of their deep-sleep function (different from the microcontroller's deep sleep).

@todd-herbert
Copy link
Owner

todd-herbert commented Mar 6, 2024

Using fast-mode with ESP32 deep-sleep is now supported as of v4.2.0. You can install this right now by downloading the .zip release from github, or in the next few hours via the Arduino Library Manager.

You should pass the argument fastmodeOn(false) to bypass the initial memory clearing.

Note that the code in the 1st post would also need a call to clearMemory() at the start of each for loop.
By design, update() does not erase your working image, allowing you to add to it by drawing BLACK, or erase by drawing WHITE. Calling clearMemory() will return the working image to the background color, before drawing the new and different hourglass graphic.

If you are not already doing so, I would suggest calling clear() at first boot, to make sure both the display and the memory are blank.

void setup() {
    if (esp_sleep_get_wakeup_cause() != ESP_SLEEP_WAKEUP_TIMER)
        display.clear();

    display.setTextSize(2);
    display.fastmodeOn(false);  // false to disable memory-init

    display.setCursor(0, f.bottom() - 30);
    display.println("Fastmode:");
    display.println("On");
    display.update();

    display.setTextColor(WHITE);
    display.setWindow( f.left(), f.top(), f.width(), f.height() - 35 ); // Don't overwrite the bottom 35px

    for (int demo = 0; demo <= 5; demo++) { // Count up to 5
      display.clearMemory();    // Start with a blank image
      display.drawXBitmap(ICON_L, ICON_T, hourglasses[demo % 3], hourglass_1_width, hourglass_1_height, BLACK);
      display.fillRect(0, 0, 30, 30, BLACK);
      display.setCursor(10, 10);
      display.print(demo);
      display.update();
    }
    display.fastmodeOff();

    esp_sleep_enable_timer_wakeup(15*1000000ULL);
    esp_deep_sleep_start();
}

Don't overdo the fast-mode or the display will get a nasty afterimage. Once an hour might not be enough for a normal refresh; you might need to experiment. If you do overdo it and need to rescue the display, running a bunch of normal refreshes of random images seems to help.

Thanks for taking the time to point out the issue. Let me know how you get on!

@allllo20
Copy link
Author

@todd-herbert hey there again! I wasn't able to check back until today after the issue, but man.. thank you so much for the extensive explanation and blazing fast fix! Everything's working now as expected and I can't thank you enough. Is there a way I can spend you a coffee via PayPal or anything?

@todd-herbert
Copy link
Owner

Is there a way I can spend you a coffee via PayPal or anything?

No need, but thank you! Just glad to see you get the hardware working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants