GxEPD2: fuzzy display if partial update after deep sleep, flawless if partial update without

Hi all,

I'm having a bit of an issue with a 2.9" Waveshare E-Paper BW V2 display, used together with an Arduino Nano ESP32 microcontroller.

Specifically, I have a function that draws some text and normally performs a partial update, with a full update being performed every 10 refreshes, with 20 seconds between refreshes. To keep track of the refreshes a "bootCount" variable is used.

For testing and easier flashing I disabled the controller's deep sleep while simulating the behaviour of the bootCount variable and the successive calls to the display drawing function - in this case everything works flawslessly and the display stays crisp.

If, however, I enable the "real" deep sleep of the controller and use the display.init additional parameters to avoid a full refresh except on the first "real" boot, on successive partial refreshes the updated characters look very fuzzy. Once the threshold for a full refresh is reached, the display is crisp, but once again becomes fuzzy in the updated areas during partial refreshes.

The full (short) code follows - to switch between the two behaviours it's enough to change the "testing" boolean to either true or false.

// https://github.com/ZinggJM/GxEPD/tree/master

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <GxEPD2_BW.h>
#include <GxEPD2_3C.h>
#include <GxEPD2_7C.h>

// constructor for AVR Arduino, copy from GxEPD_Example else
GxEPD2_BW<GxEPD2_290_T94_V2, GxEPD2_290_T94_V2::HEIGHT> display(GxEPD2_290_T94_V2(/*CS=5*/ SS, /*DC=*/9, /*RST=*/8, /*BUSY=*/7));  // GDEM029T94 128x296, SSD1680, Waveshare 2.9" V2 variant

// FreeFonts from Adafruit_GFX
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>

const GFXfont* f = &FreeMonoBold18pt7b;

#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) */

unsigned long currentMillis;
unsigned long previousTempRHMillis;
unsigned long tempRHInterval = 1000;

RTC_DATA_ATTR int bootCount = 0;

float t;
float rh;

bool testing = true;  // If true disables deep sleep and fakes bootCount variable, in addition to separately calling a display refresh a number of times

Adafruit_BME280 bme;  // I2C

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  delay(1000);

  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  /*
  First we configure the wake up source
  We set our ESP32 to wake up every 5 seconds
  */
  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");

  // Initialize sensor
  unsigned status = bme.begin(0x76);

  // Initialize e-paper display
  if (bootCount == 1) {
    display.init(115200, true, 2, false);  // USE THIS for Waveshare boards with "clever" reset circuit, 2ms reset pulse
  } else {
    display.init(115200, false, 2, false); // Omits initial full refresh on successive restarts after deep sleep
  }

  // Measure conditions
  measureTemp();
  measureRH();
  drawDataOnDisplay();

  // For testing without deep sleep - simulate bootCount and use it for partial update
  if (testing == true) {
    for (int i = 0; i < 100; i++) {
      bootCount++;
      drawDataOnDisplay();
      delay(TIME_TO_SLEEP*1000);
    }
  }

  // Going to deep sleep
  Serial.println("Going to sleep now");
  delay(1000);
  Serial.flush();
  if (testing == false) {
    esp_deep_sleep_start();
  }
  Serial.println("This will never be printed");
}

void loop() {
}

void measureTemp() {
  t = bme.readTemperature();
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.println(" °C");
}

void measureRH() {
  rh = bme.readHumidity();
  Serial.print("Humidity = ");
  Serial.print(rh);
  Serial.println(" %");
}

void drawDataOnDisplay() {
  display.setTextColor(GxEPD_BLACK);
  display.setRotation(3);

  display.setFont(f);
  display.setFullWindow();
  display.fillScreen(GxEPD_WHITE);
  display.setCursor(0, 24);

  display.firstPage();
  display.print("T: ");
  display.print(t);
  display.println(" C");

  display.print("rh: ");
  display.print(rh);
  display.println(" %");

  display.print("Bootcount: ");
  display.println(bootCount);

  if ((bootCount % 10) == 0) {
    display.display(false);  // Full update
  } else {
    display.display(true);  // Partial update
  }
  display.hibernate();
}

/*
Method to print the reason by which ESP32
has been awaken from sleep
*/
void print_wakeup_reason() {
  esp_sleep_wakeup_cause_t wakeup_reason;

  wakeup_reason = esp_sleep_get_wakeup_cause();

  switch (wakeup_reason) {
    case ESP_SLEEP_WAKEUP_EXT0: Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1: Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER: Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD: Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP: Serial.println("Wakeup caused by ULP program"); break;
    default: Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); break;
  }
}

@fabri91, Hi, welcome to the forum!

Your issue is caused by the "clever" reset circuit of the Waveshare display board.

Add a 1k pull-up resistor to the reset line of the display, to keep the controller on the e-paper panel powered during processor deep sleep.
-jz-

Hi, thanks for the tip and for the work behind the library!

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