Waveshare e-paper displays with SPI

Ah... forgot to enable the right display in the header file:

#define GxEPD2_DRIVER_CLASS GxEPD2_420     // GDEW042T2   400x300, UC8176 (IL0398)

Then it works fine :slight_smile: Thanks a lot!

@ZinggJM
Hello, I see you've provided a lot of information on e-paper displays and I really appreciate it.

I'm in the initial stages of collecting parts for a e-paper display for my kitchen wall. My platform of choice is Arduino for a number of reasons. Mostly because I work best when I can understand the details of what is going on. Although if there was a compelling reason to go to a RasPi I would like to know, and if substantial I may consider using a RasPi.

My question:
What processor requirements are needed / important when selecting an Arduino / e-Paper display?
I see most of the displays on eBay seem to target the RasPi so I'm assuming more processor "power" in important.

Does using a RasPi provide a really significant advantage? (I'm not too worried about speed of display update, I'll be displaying outdoor temperature + other similar variables)

I would like a 3 color 4.2" (or similar) display. Is this too much for the Arduino processors? I don't care which Arduino processor I, my only desires are:

  1. No OS (like the RasPi)
  2. Programs in C or C++

Any information on how to put these together, limitations to be concerned with etc would be very much appreciated.

I found an earlier post from you referencing e-Paper displays that have various amounts of "on display processing power". I am very capable when it comes to reading datasheets but what I find on the web seems to have a minimal of technical details. I'm also concerned about your experience with the Waveshare 4.3 or 4.2 where the display degrades. I'm assuming this happens fast enough for you to be concerned. Do you think this is a practical issue? What do you consider "degrade", contrast ratio?

Sorry if my questions seem to jump around.

Thanks
John

Important thing (for me) is use of PROGMEM for reducing the usage of memory. I use only Uno, nano or mega MCUs.

I plan to buy a 3 color 4.2" just to try it. But not sure when.

No. Output shows that your BUSY line doesn't work, BUSY times are too short.
Try the constructor with the parameters for the new version of the driver board.

OK, I have tried it:

// mapping of Waveshare e-Paper ESP8266 Driver Board, new version
// BUSY -> GPIO5, RST -> GPIO2, DC -> GPIO4, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V
GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=15*/ EPD_CS, /*DC=4*/ 4, /*RST=2*/ 2, /*BUSY=5*/ 5));

It doesn't work. Here is the Serial Output:

20:08:23.844 -> _PowerOn : 10000885
20:08:34.550 -> Busy Timeout!
20:08:34.550 -> _Update_Full : 10000781
20:08:44.574 -> Busy Timeout!
20:08:44.574 -> _PowerOff : 10001085
20:08:59.544 -> Busy Timeout!
20:08:59.544 -> _PowerOn : 10000533
20:09:09.821 -> Busy Timeout!
20:09:09.821 -> _Update_Full : 10000800
20:09:19.816 -> Busy Timeout!
20:09:19.816 -> _PowerOff : 10000893

With the old version settings, the display works:

// mapping of Waveshare e-Paper ESP8266 Driver Board, old version
// BUSY -> GPIO16, RST -> GPIO5, DC -> GPIO4, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V
GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=15*/ EPD_CS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16));

Serial Output (without BUSY-outputs):

20:25:02.778 -> _PowerOn : 9
20:25:03.467 -> _Update_Full : 2
20:25:03.467 -> _PowerOff : 1
20:25:08.463 -> _PowerOn : 1
20:25:08.693 -> _Update_Full : 2
20:25:08.693 -> _PowerOff : 2
20:25:13.696 -> _PowerOn : 10
20:25:13.975 -> _Update_Full : 9
20:25:13.975 -> _PowerOff : 1
20:25:18.966 -> Set wallpaper...
20:25:19.151 -> _PowerOn : 9
20:25:19.567 -> _Update_Full : 9
20:25:19.935 -> _PowerOff : 9

Is there anything I can do to customize the GxEPD2 libraries regarding the BUSY time?

I have checked the wiring. It seems that I have the old version.
No, I don't think so.

Yes, I have checked the two PDFs from Waveshare-Wiki (E-Paper ESP8266 Driver Board). One shows the pinout of the old version (User manual), one the new version (Schematic)... However, I did not measure with meter on the Driver Board.

Your shifted image may be caused by the header bytes in the HEX code. Disable header bytes, or comment them out.

Thank you, that was the solution! In the Img2Lcd.exe program I have now deselect the option "Include head data". In some tutorials the option was set.

I too am in the same situation. I am concerned that after purchase I find the Atmel boards don't have enough "horsepower" (I should say kW) to run the display + a little left over for UART control.

I also there is little forum info (that I've found) to suggest which displays are good and which I should stay away from.
It a little frustrating as I'm not a noob, but I also don't want to reinvent the wheel.

It sounds like you have some successful experience with ePaper displays.

What do you mean? Not enough memory or that things go too slowly to update the display?

Success... well it works but I'm still a bit confused how to use it. But with enough time I will find out how to use it in a more advanced way that the two tests I have performed. Time is the biggest problem at the moment. Got a huge project that need to be finished within October (at least the hardware).

You are wasting time! Checking the real wiring is the first thing to do.

You can specify -1 for the BUSY pin parameter with GxEPD2. It will then use default delays from attributes in the driver class header, rounded up values I have measured. These values are for normal room temperature, using the BUSY line is safer.
You could then use a voltmeter on the processor pins to see which one seems to show busy.

Jean-Marc

Maybe the RESE switch is in the wrong position for your panel. Check the RESE value in the reference circuit of the panel spec. or just try both positions.

You need enough RAM and code space for your application. AVR Arduinos can be used with graphics and SPI e-paper displays using paged display, but have almost nothing left for the application. I would use AVR Arduinos only if I need strong driving 5V pins, or many pins (MEGA).

Yes, it has enough RAM for full buffered graphics, and lots of program space.
The RasPi Pico RP2040 can be used with the Arduino IDE. I have only recently tried with GxEPD2.
I mostly use ESP8266 or ESP32, e.g. because of WiFi connection.

Jean-Marc

1 Like

Hello, I have a project were I would like to show a arrow pointing either up, down or horizontal depending on if the temperature is rising, falling or is stable. I am planing on making the arrow a bitmap and drawing that on the screen. My question is, is there an easy way to use the same arrow bitmap and when calling the display.drawBitmap command tell the Arduino to just rotate the image either 90 or 180 degrees?

@calania, Hi,

your question can't be answered without knowing what library you refer to!

GxEPD2 has 2 sets of drawBitmap methods. One using buffered drawing through Adafruit_GFX, one drawing directly through the panel driver (called drawImage() to distinguish).

The Adafruit_GFX methods draw corresponding to the orientation set by setRotation().

Jean-Marc

Version 1.3.6 of library GxEPD2 is available, install or update with Library Manager.

  • added support for Waveshare 2.9" b/w V2, driver class GxEPD2_290_T94_V2
  • Waveshare 2.9" b/w V2 uses a GDEM029T94 variant without partial update wft in OTP
  • driver class GxEPD2_290_T94_V2 uses partial update wft written to registers
  • added NOTE for RST pull-up on ESP8266 with "clever" reset circuit, or alternate pin

Support for Waveshare 2.9" b/w V2 is added thanks to a free sample from Waveshare!
And I even got an additional one separately.

Jean-Marc

@winnie, Hi,

I feel a bit frustrated by your post. This isn't your first post, so you should know the need to provide complete information, and links to your devices.

You have a related post: Problem with compiling Arducam ESP32S Uno.
It may be against forum rules to create duplicate posts without providing cross-links.
Responders would waste time to ask for information already available.

It seems you use a separate package for compilation with your board.
I don't want to install this package, so I don't know the details.

Your board might be Arducam IoTai ESP32 CAM WiFi Bluetooth PSRAM Development Board with Camera Module OV2640

I don't see the pinout on that page. Please provide a link.

You should never need to change pins_arduino.h. In GxEPD2 you just need to make sure your constructor parameters match your wiring, and doesn't conflict with other resources or with boot mode pins of the processor.

Take a look at boot messages in Serial Monitor, to see if you have boot mode issues. And to see diagnostic output from GxEPD2.

Jean-Marc

static const uint8_t SS    =  0;
static const uint8_t MOSI  = 23;
static const uint8_t MISO  = 19;
static const uint8_t SCK   = 18;

Hint

Sometimes to program ESP32 via serial you must keep GPIO0 LOW during the programming process

Avoid GPIO0 with the Waveshare board, as it has a strong pull-down. Or use a strong pull-up (1k).
Use the explicit value (5) in the constructor.
Your DC on pin 0 is an output. But during boot it might be pulled low by the level converter circuit of the Waveshare board, if RST isn't pulled high by an external pull-up. See the Waveshare schematics for the "clever" reset circuit.

Hello everyone,

I use ZinggJM example and code to drive waveshare 4.2" epaper display through ESP8266 for displaying images. I found the display example very useful and adopted to display images.

However I am not able to clear the last image and turn off the display at the end. what code or line do i have to include to turn off the display?

My code example is as follows

#include "DEV_Config.h" // 
#define ENABLE_GxEPD2_GFX 0 // we won't need the GFX base class
#include <GxEPD2_BW.h> // BW for black and white display
#include "Bitmaps.h"
#include <GxEPD2_3C.h>  // 3C - three color display

// Instantiate the GxEPD2_BW class for our display type 
GxEPD2_3C<GxEPD2_420c, GxEPD2_420c::HEIGHT>
display(GxEPD2_420c(SS, 4, 5, 16));

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  // wait for display to become available
  display.init(115200);
  // display image logo on the display
  drawBitmaps(image_LOGO);
}

void loop() {
  // put your main code here, to run repeatedly:
}

void drawBitmaps(const unsigned char *bitmap) {
  // Configure the display according to our preferences
  display.setRotation(0);
  display.setFullWindow();
  // Display the bitmap image
  
  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK);
          }
 
  while(display.nextPage()); 
  DEV_Delay_ms(5000);  
  do {
    display.fillScreen(GxEPD_BLACK);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_WHITE);
    // DEV_Delay_ms(5000);    
     }
    
 while(display.nextPage());
 DEV_Delay_ms(5000);

 }

You clear the display by calling display.clearScreen().

    virtual void clearScreen(uint8_t value = 0xFF) = 0; // init controller memory and screen (default white)
    virtual void writeScreenBuffer(uint8_t value = 0xFF) = 0; // init controller memory (default white)

You turn of the booster circuit for panel driving voltages by calling display.powerOff().
You can hibernate the controller for lowest power use by calling display.hibernate().

    virtual void powerOff() = 0; // turns off generation of panel driving voltages, avoids screen fading over time
    virtual void hibernate() = 0; // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)

The easiest way to find all methods is by looking at GxEPD2_GFX.h

With the Waveshare board you can pull RST low to turn off power completely by the "clever" reset circuit. I don't recommend this.

Welcome to the forum! Please read How to get the best out of this forum.

Please edit your first post and put code in a code window: select your code, click </>.
Better: format your code first, using Auto Format from the Tools menu.

Jean-Marc

Thanks a lot ZinggJM, I tried including the line
virtual void clearScreen(uint8_t value = 0xFF) = 0;
in the end. But I get the following error message

"'virtual' outside class declaration "
Could you please let me know how I should proceed. Sorry, my programing skills are very primitive

// based on https://www.youtube.com/watch?v=CMNuMOcvpFM
// Online tool for converting images to byte arrays: 
// https://javl.github.io/image2cpp/

#include "DEV_Config.h" // to include delaz function
#define ENABLE_GxEPD2_GFX 0 // we won't need the GFX base class
#include <GxEPD2_BW.h> // BW for black and white display
#include "Bitmaps.h"
#include <GxEPD2_3C.h>  // 3C - three color display
#include <GxEPD2_GFX.h>
#include <GxEPD2_EPD.h> 

// Instantiate the GxEPD2_BW class for our display type 
GxEPD2_3C<GxEPD2_420c, GxEPD2_420c::HEIGHT>
display(GxEPD2_420c(SS, 4, 5, 16));

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  // wait for display to become available
  display.init(115200);
  // display ACROBOTIC logo on the display
  drawBitmaps(ACROBOTIC_LOGO);
}

void loop() {
  // put your main code here, to run repeatedly:
}

void drawBitmaps(const unsigned char *bitmap) {
  // Configure the display according to our preferences
  display.setRotation(0);
  display.setFullWindow();
  // Display the bitmap image
  
  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK);
          }
 
  while(display.nextPage()); 
  DEV_Delay_ms(30000);  
  do {
    display.fillScreen(GxEPD_BLACK);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_WHITE);
    // DEV_Delay_ms(5000);    
     }
     
  while(display.nextPage()); 
  DEV_Delay_ms(30000);  
 do {
    display.fillScreen(GxEPD_WHITE);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED);
    // DEV_Delay_ms(5000);    
     }

  while(display.nextPage()); 
  DEV_Delay_ms(30000);  
 do {
    display.fillScreen(GxEPD_BLACK);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED);
    // DEV_Delay_ms(5000);    
     }

  while(display.nextPage()); 
  DEV_Delay_ms(30000);  
 do {
    display.fillScreen(GxEPD_RED);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK);
    // DEV_Delay_ms(20000);    
     }
     
 while(display.nextPage()); 
 DEV_Delay_ms(30000);  
 do {
    display.fillScreen(GxEPD_RED);
    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_WHITE);    
     }    
    
 while(display.nextPage());
 DEV_Delay_ms(30000);  
//do {
//
//display.fillScreen(GxEPD_WHITE);
//    display.drawInvertedBitmap(0, 0, bitmap, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_WHITE);   
//     
//     } 
//while(display.nextPage());  

virtual void clearScreen(uint8_t value = 0xFF) = 0; 

 }

Sorry, my library can't be used without some fundamental knowledge with programming in C++.

Look at the example GxEPD2_Example.ino. In this example you find use of these methods.

Please edit your first post. I like if this topic looks clean and doesn't hurt the eyes. Thanks, done.

BTW: each page loop needs the call of display.firstPage(); before the do {...

Hi @ZinggJM, thank you for this great library.
I have a waveshare 7.5 e-Paper (product page) and a Wemos D1 mini (ESP8266). I would like to put both, the ESP and the display into deep-sleep and everytime the ESP wakes up, it should get a full-page-sized bitmap from a server, display it, and go back to sleep.

I use the showBitmapFrom_HTTP from your example and my setup-code looks like this:

void setup() {
  pinMode(D0, WAKEUP_PULLUP);
  WiFi.begin(ssid, password);
  showBitmapFrom_HTTP("192.168.178.43", "/calendar/", "img.bmp", 0, 0, false);
  WiFi.disconnect();
  ESP.deepSleep(0xffffffff);
  delay(10);
}

Everything works fine, but the battrey lasts a lot shorter than I expected, and the display sometimes has a wrong y-Offset (where the first line of the bitmap is rendered in the middle of the screen and then wraps around at the top).

At the beginning of the showBitmapFrom_HTTP I have the display.init(115200, true, 2); and at the end I have inserted display.hibernate();. Do you have any sugeestions to optimize the setup? Thanks in advance!

@kielnino, Hi, welcome to the forum.

Thank you for providing almost all relevant information, and clickable links. Congratulation.

The only additional useful information would be, what wiring do you use, the recommended one? And do you use any added pull-ups or pull-downs?

For low power use with 3.3V processors I recommend the DESPI-C02 connection module.

The current Waveshare boards and their connection HAT have level converters and a "clever" reset circuit, see e.g. E-Paper-Driver-HAT-Schematic.pdf.
The level converters will consume current as long as the HAT is powered.

The HAT can be used for low power by letting RST be pulled low by its internal pull-down. This will turn off supply to the whole board, the level converters and the connected display.
I don't know if ESP8266 keeps IO states active during hibernation. You could measure the pin used for RST.
Having RST low during processor wake-up may interfere with ESP8266 boot modes. I haven't ever tried.

Jean-Marc

@ZinggJM Thank you so much for your support.
I use indeed the suggested Wiring
BUSY -> D2, RST -> D4, DC -> D3, CS -> D8, CLK -> D5, DIN -> D7, GND -> GND, 3.3V -> 3.3V and have no pull-ups/pull-downs. The only additional connection in my setup is from D0 of the ESP to its own RST to let it wake up from deep-sleep.

To know more please measure the state of the pin used for RST (D4) during ESP8266 deep sleep.

You could also set RST low after display.hibernate(), for a test.