My e-Paper journey using GxEDP2 library

I will continue to post to this thread with the sage of my EDP and GxEDP2 journey.

I and grateful to Jean-Marc Zingg for his amazing work on the GxEDP2 ePaper Library.

I purchased a Good Display 2.7" BW display for my initial exposure to ePaper.

Good Display PN GDEW027W3 + the DESPI-C02 Adapter Board.

I do have a project in mind however at the moment I'm simply trying to understand how to use the library and get some text on the screen. I started with the GxEPD example "GxEPD2_HelloWorld.ino" and was able to get the display up and running with a Pro Mini.

Now I've moved to a ESP8266 to run the "GxEPD2_NotPagedExample.ino" again with almost no problems. However I'm only a fair(or worse) C coder and a only have a hint of C++ under my belt. I'm basically a visual / graphical guy so I don't pick up somethings as quickly as others do.
So I took the "GxEPD2_NotPagedExample.ino" and pared it down to just printing text and hibernating. I've added comments for the methods used however I'm sure there are some errors. I'm posting my code (actually @ZinggJM's code) in case others.

My next goals is how to understand how the screen data goes from the µP memory to the display IC (with two buffers) to the screen. I expect this has something to do with the writeImageAgain method.

/* Based on "GxEPD2_NotPagedExample.ino" a display Library example for SPI e-paper panels from Dalian Good Display
   and boards from Waveshare.
   Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
     Author: Jean-Marc Zingg

 This file is a pared down version of "GxEPD2_NotPagedExample.ino".  All code except that needed
 to display some text in the middle of the display has been removed.  My goal is to simplify
 the code allowing a better understanding of the functions needed to display text.

 This file is for use with an esp32 or esp8266.  I've only tested it on an esp8266 (NodeMCU)
 All the compiler "#if defined" statements have been removed for clarity (mine) with the decisions for
 the esp8266 and GDEW027W3 display.

 CAUTION:  my line by line comments probably have some errors.

 EPD = electronic paper display aka e-Paper

 Program function:  Display "text_01" in the center of the screen then hibernate.

todo:  These are just programming, little to do with how the display works.
 1) Modify the "displayText()" procedure to accept text pointer.
 2) Modify the "displayText()" procedure to accept coordinates and / or descriptors.  i.e. center, center left, top left, bottom left etc
 3) Modify the "displayText()" procedure to accept different fonts.

// base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter, uses ~1.2k more code
// enable or disable GxEPD2_GFX base class
#define ENABLE_GxEPD2_GFX 0

// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX
//#include <GFX.h>
// Note: if you use this with ENABLE_GxEPD2_GFX 1:
//       uncomment it in GxEPD2_GFX.h too, or add #include <GFX.h> before any #include <GxEPD2_GFX.h>

#include <GxEPD2_BW.h>            // in this file you must find the #include for your display and uncomment it.
//#include <GxEPD2_3C.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <StreamString.h>         // Apparently needed to "Print" to the screen.  Seems to be special for the ESP8266
                                  //     or at least different
#define PrintString StreamString  // guess this is only a name change (for clarity?)

// Constructor:  creates an EPD object named "display"
// select one and adapt to your mapping, can use full buffer size (full HEIGHT)
GxEPD2_BW<GxEPD2_270, GxEPD2_270::HEIGHT> display(GxEPD2_270(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4));

void setup()
  // for output to IDE Serial monitor
  display.init(115200);       // the init fcn simply sends a low pulse to display board rst line.
                              // This is the only way to wake the display IC from hibernation.

  // first update should be full refresh

  // partial refresh mode can be used to full screen,
  // effective if display panel hasFastPartialUpdate
//  helloFullScreenPartialMode();


  Serial.println("setup done");

void loop() { }

// note for partial update window and setPartialWindow() method:
// partial update window size and position is on byte boundary in physical x direction
// the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation
// see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow()

const char text_01[] = "Good Display 2.7\"";
const char hibernating[] = "hibernating ...";
const char again[] = "again";

void displayText()

  int16_t tbx, tby; uint16_t tbw, tbh;
  display.getTextBounds(text_01, 0, 0, &tbx, &tby, &tbw, &tbh);  // send a textarray, originx, originy returns the center point of the text and
                                                                 // the height & width at the previously defined font... I think?

  // center bounding box by transposition of origin:
  uint16_t x = ((display.width() - tbw) / 2) - tbx;
  uint16_t y = ((display.height() - tbh) / 2) - tby;
  // full window mode is the initial mode, set it anyway
  display.setFullWindow();            // setspartial_mode = false; sets the screen x,y = 0 and height & width to display max
  display.setCursor(x, y);
  display.print(text_01);           // writes text_01 in the controllers memory.
  display.display(false);           // screen will not change until this command is made.
                                    //  with partial update = false.  display buffer content to screen, useful for full screen buffer
                                    //  not sure which buffer is in play here.  µP or the display IC buffer(s)

  display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t hx = (display.width() - tbw) / 2;
  uint16_t hy = (display.height() / 3) + tbh / 2; // y is base line!
  display.getTextBounds(again, 0, 0, &tbx, &tby, &tbw, &tbh);
  uint16_t ax = (display.width() - tbw) / 2;
  uint16_t ay = (display.height() * 2 / 3) + tbh / 2; // y is base line!
  display.setCursor(hx, hy);
  display.setCursor(ax, ay);
  display.hibernate();          //turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)
                                //  here powerOff() = turns off generation of panel driving voltages, avoids screen fading over time

I try to be patient with your posts. But I am not a teacher and I will not correct whatever wrong you write. I may just stop responding to your posts.

From GxEPD2_EPD.h, the driver class interface:

    // write to controller memory, without screen refresh; x and w should be multiple of 8
    virtual void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0;
    // for differential update: set current and previous buffers equal (for fast partial update to work correctly)
    virtual void writeScreenBufferAgain(uint8_t value = 0xFF) // init controller memory (default white)
      // most controllers with differential update do switch buffers on refresh, can use:
    virtual void writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false)
      // most controllers with differential update do switch buffers on refresh, can use:
      writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);

See also this post: GxEPD2 - Partial update with deep sleep

I'm sorry if it seemed like I was asking for your help. You've done quite a lot already.

This post was to hopefully help others who are in my situation, or convince those considering using ePaper for some project. I've made a number of similar posts, mostly in the Hubitat forum but some here as well. If I struggle with some device (usually the case) I try to summarize my findings to help those behind.
My Caution that there may be some mistakes was just that. It was not a cry for someone to correct those mistakes.

I will admit I was kinda asking for help with the different buffers, however I don't expect you to spend time teaching me. I will, once I get them figured out create a similar post on what I find hoping to pass on the knowledge I've found.

So I'm sorry if I made it feel like I was badgering you for information :slight_smile: I only included your forum name because I was uncomfortable posting this code without folks understanding there was absolutely no unique code from me and all the posted code was written by you.



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