GxEPD2 power efficiency tip for _waitWhileBusy

Hi, first timer here!

Wanted to share some significant (~40%) power saving gains I've achieved by a couple of simple tweaks to @ZinggJM 's awesome library :wink:

When looking at the _waitWhileBusy function I noticed that it polls the 'busy' pin twice per millisecond (one before the delay, and again after the delay).

I setup a quick test, where I do one partial update to the epaper and run a counter on that loop: my epaper goes over the loop some 420 times, for 1 single partial update (that's polling the busy pin some 840 times for 1 partial update!).

I figured, since epaper is slow by nature, I'd rather have this loop run a bit less frequently, and instead have my esp32 enjoy some more time in light-sleep (I use esp-idf in my project, which can automatically set the MCU to enter light sleep when there's nothing to do).

The changes I implemented sum up as:

  1. polling the pin once per loop iteration, instead of twice
  2. delay for 40ms, instead of 1ms.

this way, in my case the loop is going to run ~10 - 12 times per partial update, as opposed to ~420 times. This saves considerable power, specially when running on batteries.

in diff format, these are the changes I made for above point:

diff --git a/src/GxEPD2_EPD.cpp b/src/GxEPD2_EPD.cpp
index 2f06ff2..af67f0f 100644
--- a/src/GxEPD2_EPD.cpp
+++ b/src/GxEPD2_EPD.cpp
@@ -140,12 +140,14 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time)
   {
     delay(1); // add some margin to become active
     unsigned long start = micros();
+    //int busy_count = 0;
     while (1)
     {
+      //busy_count++;
       if (digitalRead(_busy) != _busy_level) break;
       if (_busy_callback) _busy_callback(_busy_callback_parameter);
-      else delay(1);
-      if (digitalRead(_busy) != _busy_level) break;
+      else delay(40); //with previous delay(1) this loops ~420 times for a partial update. Reduce to ~10 times.
+      //if (digitalRead(_busy) != _busy_level) break;
       if (micros() - start > _busy_timeout)
       {
         Serial.println("Busy Timeout!");
@@ -155,6 +157,7 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time)
       yield(); // avoid wdt
 #endif
     }
+    //printf("busy loop iterations: %d\n", busy_count);
     if (comment)
     {
 #if !defined(DISABLE_DIAGNOSTIC_OUTPUT)

The second tweak might be more specific for my epaper, worth sharing anyway!

In this case, I simply edit GxEPD2_290::_PowerOff to combine power off and hibernate into one. For some reason, this executes 200ms faster than calling hibernate() separately.

diff --git a/src/epd/GxEPD2_290_BS.cpp b/src/epd/GxEPD2_290_BS.cpp
index 7e3ead4..8d5793c 100644
--- a/src/epd/GxEPD2_290_BS.cpp
+++ b/src/epd/GxEPD2_290_BS.cpp
@@ -340,6 +340,14 @@ void GxEPD2_290_BS::_PowerOff()
   }
   _power_is_on = false;
   _using_partial_mode = false;
+
+  if (_rst >= 0)
+    {
+        _writeCommand(0x10); // deep sleep mode
+        _writeData(0x1);     // enter deep sleep
+        _hibernating = true;
+        _init_display_done = false;
+    }
 }

My project is a simple clock that updates every 1 minute, running on esp32 and powered by a 950mAh battery. Before these tweaks, I was getting an estimated 3 months on battery. After tweaks, new estimate is a little above 5 months :slight_smile:

There's probably some better ways to tweak the busy loop for efficiency. Happy hacking!

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.