Waveshare e-paper displays with SPI

My Arduino library GxEPD for e-paper displays is updated on GitHub with classes for 3-color displays 1.54", 2.13" and 2.9".

GitHub - ZinggJM/GxEPD - A simple E-Paper display library with common base class and separate IO class.

Thanks to Sponsor Eric.

vertigo72:
Im interested in learning more about the side effects of using partial updates; has anyone been brave enough to test a device with a short, say 1 second partial update cycle, and leave it running for a few weeks to see if it actually degrades/kills the display? If not, I will probably do this myself. ereaders do partial updates, and those dont seem to die quickly.

I read somewhere that you need to do a full refresh every now and then to limit the damage? No idea if that is accurate, or its its just to 'clean' the display. I also read that high temperature has a positive influence on the damage done by partial updates?

As for how it looks; I also wonder, does the the ghosting effect get incrementally worse? If you alternate numbers from 0 to 9 in a loop, does there come a point where you cant read the number anymore and it becomes a smear, or is the ghosting just fairly constant and with every partial refresh, you also get a "partial cleaning" ?

You asked for use cases earlier; here is my use case: a glider variometer (vertical speed indicator). This is my current prototype:

https://youtu.be/7Zbjo2WrcWk

It uses an OLED display to show average climb and some other info. The OLED looks great as long as there is no direct sunlight; which unfortunately makes it useless in a glider. There arent many alternatives either; I will also test sharp memory displays, but those are hard to find. And newhaven has some small sunlight readable TFTs but with precious little arduino support.

So Im looking at eink. A refresh rate of 1 per second, or maybe a few seconds is acceptable here, minutes is clearly not. Whats also not acceptable is doing periodic full refreshes: that would just be too distracting in a cockpit. However, a short life span is acceptable to me. The glider flies no more than maybe 100 hours per year. If I need to replace a €7 display every year, so be it. I'll just stockpile them :).

I got the following answer from Dalian Good Display for your question:

With great pleasure to receive your email.
I read the question, and I think your answer is good and correct.

Here is the video show our 1.54 inch e-paper, in new code, quick full screen update ( realized by partial refresh function)

https://youtu.be/M8kAfMiLMRY

If keep refreshing like this, there will be ghosting after dozens of pictures.

But for 1.54’’, the ghosting is slight, while for 2.13 and 2.9 inch will be obvious.

Also because each customer’s acceptable level of ghosting is different, so hard to give out a precise level, need to test themselves.

Another point it, e-paper is not that suitable for projects that require quick refreshing all the time.

Although customer do not care about lifetime, it still against the natural feature of e-paper display.

But in another hand, from technical point of view, e ink is always trying to realize faster and faster refreshing, also with more colors, also with larger size.

There is still a long way for e ink technology to go, but obviously, will be a bright future.

At last, about the suitable display for sunlight readable needed projects, as I know, there are several choices:

  1. Reflective type monochrome lcd display

  2. Transflective TFT lcd display

  3. Transmissive TFT lcd display, but with super high brightness ( We have one 5.6 inch TFT module, with 800-1600cd/m2 brightness, had been used on outdoor monitor for UAV)

  4. E-paper display (We have customers that use e-papers on motorcycle or similar.)

But for this case, size is small, recommend to try more with e-paper displays.

And my test shows that the 1.54inch black/white e-paper display can be used with continuous partial updates every second, but shows some degradation after 9 days. So I recommend at least one full update per day for continuous use.

ZinggJM:
And my test shows that the 1.54inch black/white e-paper display can be used with continuous partial updates every second, but shows some degradation after 9 days. So I recommend at least one full update per day for continuous use.

Very useful, thanks J-M!

What about the specified lifetime of "5 years or 1 million update cycles" - is there any sign of permanent degradation on your screen now? You must have performed close to a million partial updates.

I just restarted the test to find out, and the display looks as good as new.

I will modify my test code to do one full update per day for the 1.54" display, and start another long term test.

I do the long term test only for the 1.54", as this is the only e-paper I have 2 spares of it.

I initially bought the demo system with 2 1.54" e-paper displays from Dalian Good Display, and it was worth every cent, as you can see from my interest in e-paper displays.

witchole:
Good idea!

Having experimented further, the issue I reported originally is caused by the bm_flip_v mode: if I use that mode in the example I posted, the bitmap is displayed at the wrong co-ordinates. I'm assuming that it is supposed to mirror the bitmap, but still display it at the same screen location.

Can you confirm this?

Also, the bm_flip_h mode doesn't appear to do anything at all.

... and bm_flip_h and bm_flip_v are also "flipped"!

With the updated version bm_flip_h and bm_flip_v are deprecated and replaced by bm_flip_x and bm_flip_y.

drawBitmap to buffer is fixed to flip bitmaps in place for non-fullscreen bitmaps; bm_flip_x and bm_flip_y are both implemented.

bm_flip_h and bm_flip_v will be removed when all display classes are updated.

Note that bm_flip_y for drawBitmap to screen is not available for 2.13" b/w, as the controller of this display does not support y-increment ram data entry mode.

ZinggJM:
With the updated version bm_flip_h and bm_flip_v are deprecated and replaced by bm_flip_x and bm_flip_y.

drawBitmap to buffer is fixed to flip bitmaps in place for non-fullscreen bitmaps; bm_flip_x and bm_flip_y are both implemented.

Great work Jean-Marc!

It now works correctly on the 1.54" B/W display, and the new naming is clearer, thanks.

Thanks a lot for the 'endurance' test. That looks promising! I'll add my own results later, as I received my 1.54" waveshare display today. However, I cant make it work.

Im using the adafruit huzzah32 (ESP32). I wired it like this:

3.3 > 3.3
GND > GND
CS > 17
RESET > 5
DC > 16
DIN > 23
CLK > 18
BUSY > 19

(following this example:Tech Note 055 - Using ePaper SPI Displays with an ESP32/ESP8266 - YouTube)

I commented out

#include <GxGDEP015OC1/GxGDEP015OC1.cpp>    // 1.54" b/w

And modified the pinout here:

#elif defined(ESP32)

// pins_arduino.h, e.g. LOLIN32
//static const uint8_t SS    = 5;
//static const uint8_t MOSI  = 23;
//static const uint8_t MISO  = 19;
//static const uint8_t SCK   = 18;

// GxIO_SPI(SPIClass& spi, int8_t cs, int8_t dc, int8_t rst = -1, int8_t bl = -1);
GxIO_Class io(SPI, 17, 16, 5); // arbitrary selection of 17, 16
// GxGDEP015OC1(GxIO& io, uint8_t rst = D4, uint8_t busy = D2);
GxEPD_Class display(io, 5,19); // arbitrary selection of (16), 4

When I run the test example, the serial monitor shows:

setup
setup done
Busy Timeout!
Busy Timeout!
Busy Timeout!
Busy Timeout!
Busy Timeout!

And the display istn doing anything. Idea's?

I have not installed the package for huzzah32, and do not intend to install it.
So I can't check the wiring for hardware or standard SPI for it. Nor the defaults and implementation of its SPI class.

But when using SPI, I would avoid to use the standard SS pin for anything else than CS.

So I propose to use SS for CS, and use some other pin for RST.
Maybe you have continuous reset to your display, or no reset to wake it up.

Busy Timeout indicates that either the display or some other source ties your busy pin continuously low.
Wrong busy wiring could produce this, but with the timeout the display might still work, but slower.

The continued endurance test shows noticeable degradation after 10 hours, but clean again after restart.
So I will reduce the full update period to 6 hours for next test.

Yeay, I got it working! Thanks for pushing me in the right direction. Turns out there is no default SS pin on this board and I had everything else wrong too :).

Being a newbie, I did have a hard mapping the commented constants with the pins on the board to the pins on the display and with the calls for the class. In case it helps anyone else:

GxIO_Class io(SPI, A, B, C);

A="slave select" = CS on the display -> I chose 21 on ESP (there is no default SS pin on this board!)
B=" DC " = DC on the display ->I chose 23 on ESP
C= "Reset" = RST on the display ->I chose 22 on ESP

GxEPD_Class display(io, D, E);

D="Reset" = RST on the display ->I chose 22on ESP
E= "Busy" = BUSY on the display ->I chose 17 on ESP

Furthermore,

CLK on the display should be connected to SCK on the ESP
DIN on the display should be connected to MOSI on the ESP

Okay, off to do some real testing now :slight_smile:

My wife just told me I should learn to speak "Newbie-Language"! :slight_smile:

I will try to add example mappings to the examples for ESP32 also.

First I had to re-discover how to get the ESP32 package, this time the actual one, it also contains feather_esp32:

GitHub - espressif/arduino-esp32: Arduino core for the ESP32

Then I downloaded the package as zip-file, unpacked it, and copied it to Arduino/hardware (I renamed it to remove "-master").

This does not work; there is a document in .docs how to install esp32.

So I just changed the path of the package to:
C:\Users\ZinggJ\Documents\Arduino\hardware\espressif\esp32
and double clicked:
C:\Users\ZinggJ\Documents\Arduino\hardware\espressif\esp32\tools\get.exe

This compiler obviously is more strict than the (assumed same) compiler for ESP8266; it produces warnings with the examples.
But it compiled anyway with my settings in preferences.

And in a subdirectory the variants can be found, e.g.:

C:\Users\ZinggJ\Documents\Arduino\hardware\espressif\esp32\variants\feather_esp32\pins_arduino.h

And of course the SPI pins can be found there, including SS:

static const uint8_t LED_BUILTIN = 13;
#define BUILTIN_LED  LED_BUILTIN // backward compatibility

static const uint8_t TX = 17;
static const uint8_t RX = 16;

static const uint8_t SDA = 23;
static const uint8_t SCL = 22;

static const uint8_t SS    = 2;
static const uint8_t MOSI  = 18;
static const uint8_t MISO  = 19;
static const uint8_t SCK   = 5;

These pin definitions are different from the LOLIN32 I have - I hope they are correct - so I can't provide a general mapping suggestion for ESP32.

Most variants have this SPI mapping, but there are various different ones:

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

Noobspeak is hard to master. It took me 40 years of mostly not programming!

Zingg, a few more questions if I may;

  • Have you published the code you are running for the partial update degradation test?
  • Did you modify: #define PU_DELAY 300

With the default PU_DELAY it takes about a full second to achieve a partial update. The weird thing is, that it doesnt seem to matter if you're updating a single pixel or the entire screen, it takes about the same time?

But lowering the number increases the speed by a lot. Im currently running with PU_DELAY 30, and Im getting ~3FPS. Im not sure why lowering the delay by 10x 'only' results in a ~3x speedup, and lowering it even further doesnt seem to make a difference; but 3FPS is usable for my application. I assume degradation will be a lot worse too, but I have no idea yet about the correlation. After 30 minutes, the screen still looks good to me, and I can live with a full refresh every 30 minutes or so.

Lastly, this may not be the place to ask.. but display.updateWindow is blocking. I cant really afford a blocking process running 100s of milliseconds, as I will be driving a stepper motor too. The ESP32 is a dual core, and Ive seen it can be used in Arduino. I'll have to read and try, but do you have any thoughts on running the display driver on its own cpu core/thread?

The camera doesnt lie; or does it? I was shooting some video to show the display to my brother, and I was rather shocked how bad the ghosting looked on camera when using partial updates (and immediately) :

With my own eyes, I can only barely perceive it, and it doesnt bother me at all.
Weird?

Be prepared for delayed answers. I have more updates to do, and fixes to incomplete updates.

The PartialUpdateTest example will be put on GitHub, as soon as I have done initial tests with 2.9".

Adding a isBusy() method and changing to method update(bool nonblocking = false) would be an option, but I leave that to the advanced user who modifies the library anyway.

The initial idea of GxEPD was to give e-paper users something to start with, something more than was available from the e-paper suppliers. It IS intended to be adapted by experienced users.

Modifying your library in to a non blocking one is way above my paygrade, but I like this display and so I'll find a solution. If using 2 cores / threading doesnt work, or I cant do with a timing interrupt, at worst I can go back to using 2 microcontrollers. I did that initially when I only had nano's and ran out of memory running an LCD, stepper, menu library,.. Its not elegant, but its cheap and it works :).

Anyway, just wanted to thank you for all your work on this, and your help!

hi, in your lib the "GxGDEW029Z10" especially for 2.9bwr don't work, generate an error

In file included from sketch\GxGDEW029Z10.cpp:33:0:

sketch\GxGDEW029Z10.h:36:22: fatal error: ../GxEPD.h: No such file or directory

 #include "../GxEPD.h"

                      ^

compilation terminated.

exit status 1
Erreur de compilation pour la carte Arduino Nano

i use the "GxEPD_SPI_TestExample" modified for my nano+2.9bwr with differents images that i made

Test pour 2.9bwr

You need to add GxEPD as library.

Download library as zip-file, add zip-file with Library-Manager.

Compile and run GxEPD_SPI_TestExample with uncommented
#include <GxGDEW029Z10/GxGDEW029Z10.cpp>

If this fails, you can complain again.

#include "../GxEPD.h" fails, if the display class is not included from the library path.

when i Compile and run GxEPD_SPI_TestExample with uncommented

#include <GxGDEW029Z10/GxGDEW029Z10.cpp>

Le croquis utilise 31452 octets (102%) de l'espace de stockage de programmes. Le maximum est de 30720 octets.
Les variables globales utilisent 1743 octets (85%) de mémoire dynamique, ce qui laisse 305 octets pour les variables locales. Le maximum est de 2048 octets.

Now is good on my GxGDEW029Z10 with this file

thanks for your job ;-))

hello, thanks for great library works perfect on my wemos mini 8266
with 4,2 http://waveshare.com e-ink

now i want to try it on esp32 with my module (afaik it should work as pocket32)
https://www.aliexpress.com/store/product/WEMOS-WiFi-Bluetooth-Battery-ESP32-development-tool/2090076_32814163663.html

here is my config

GxIO_Class io(SPI, 5, 17, 14); //cs/dc/reset
GxEPD_Class display(io, 14, 15); //reset/busy

//static const uint8_t SS = 5;
//static const uint8_t MOSI = 23; /DIN
//static const uint8_t MISO = 19;
//static const uint8_t SCK = 18; /CK

but so far no luck....
serial output is empty
any idea what could be wrong? (tried several pin setting without success)

My goal is to create e-ink display for my domoticz home system, battery powered with deep sleep refreshed every 5 min. Thinking about generate on my orangePC from json values image file, and then download it every 5 minutes over WIFI.

Thank you for pointing to that interesting ESP32 device. I had seen it on AliExpress, but not noticed that it takes a battery on the backside. Double the price of a Wemos D1 mini Pro, but perfect for my IoT network.

I have tested once with Wemos LOLIN32 V1.0.0, but not re-tested (regression test) on updates of GxEPD.
I will do that, but would be surprised if it doesn't work.

The pin mapping should be correct for your device, from the picture on the website.
There are ESP32 devices with different pin mappings, see Arduino.h of the variant you compile for.

All my examples set up Serial with 115200 and print at least "setup", so I am surprised you don't see this in Serial Monitor.

Some devices need a push on the reset button after download, or sometimes reset helps, but I see no reset button on the picture of your device, and "boot" may cause it to wait for download, maybe.

I suggest you make sure a "blink" example and a serial output example works.

I will look what "pocket32" is. You could also try if your device works as LOLIN32, for basic functions.

Google found "pocket32" for me, but I don't know which ESP32 Board you use for it, is it in a different Arduino package?

The GxEPD_SPI_TestExample works fine with LOLIN32 Lite:

thanks for all help, its still not working
board looks good, it would be interesting how long it could work with deepsleep + battery and E-ink together

-tried blink and serial communication it works without problem

-im using this board setting (arduino-esp32/pins_arduino.h at master · espressif/arduino-esp32 · GitHub) looks ok, BUILTIN_LED 16 works.....

-display worked on Wemos 8266 so maybe my clone board have different pins compare to original board

my pins:
CS = 5
DC = 17
RESET = 14
BUSY = 15
DIN = 23
SCK = 18
GND = GND
3V = VIN

any idea what else should i check
thanks a lot