GxEPD_MultiDisplayExample.ino - two e-ink displays and animation

Hi,

I wanted to say thank you for putting together the library you created to control multiple e-ink displays. I am a software engineer but wanted to get more involved with hardware so I decided to start off with arudino to make some simple projects.

I was reviewing your example: GxEPD_MultiDisplayExample.ino

I did find your forum post: Waveshare e-paper displays with SPI

https://forum.arduino.cc/?topic=487007#msg3477197

But I was hoping I could ask some simple questions to get myself up and running faster.

  • Is there a tutorial or guide you have created to show how to connect multiple e-ink displays together?
  • Is it possible to use your library to display animation or will a separate library be needed? I am not sure of the limitations of multiple displays and even the limits of e-ink displays themselves?
  • Can each display be used independently or are the all sync or are both options available?

I understand the above questions will seem very simple to you and I apologize. I am simply reaching out and trying to find how to get started. My goal is a simple project where I have 2 e-ink displays that will display an animation within a random period of time (2-5 minutes), and then select another random time once the animation is finished - repeating that cycle in a constant loop. I was hoping that the displays could also work independently of each other.

If I dont hear from you. Thank you again for the library and I will work my way through what you have provided on github.

Thank you for your time and help,
Jonathan

Hi Jonathan,

Welcome to the forum, and thank you for posting your question in the forum!

Is there a tutorial or guide you have created to show how to connect multiple e-ink displays together?

No, the GxEPD_MultiDisplayExample.ino has the purpose to show this.
But for new projects or new users I recommend GxEPD2 and GxEPD2_MultiDisplayExample.ino

Is it possible to use your library to display animation or will a separate library be needed? I am not sure of the limitations of multiple displays and even the limits of e-ink displays themselves?

It is possible to do animation with GxEPD2 or GxEPD. But e-paper displays are not well suited for this. Make sure to use an e-paper with "fast partial update", differential update. Only the smallest b/w e-paper displays have fast enough differential update for animation.

Can each display be used independently or are the all sync or are both options available?

Each display is handled independently, if you use separate instances as in the example. This also allows to use different e-paper displays together.
You can connect several same e-paper displays in parallel to show the same content in sync, using only one display class instance. You would then connect only one BUSY line, as all BUSY times are the same if they work at the same temperature range.

The example GxEPD2_MultiDisplayExample.ino is a bit complicated, as it addresses several aspects:

  • How to use separate display instances for each e-paper display,
  • How BUSY lines can be "shared" using wired-or, to reduce the number of pins needed,
  • How to use a common base class, to use functions or methods with a display instance parameter.

An additional aspect is memory use. For multiple displays I recommend to use processors with enough RAM, e.g. ESP8266 or ESP32.

You could also search for "GxEPD_MultiDisplayExample" or "GxEPD2_MultiDisplayExample" in the forum.

See also an early post: Good Display ePaper for Arduino - #92 by ZinggJM - Displays - Arduino Forum

For more help I would need to know which e-paper display(s) you intend to use, please post (clickable) links, what connector module (if separate from display panel), and what processor.

Jean-Marc

Thank you Jean-Marc for the reply.
It will help me out a lot.

I am going to review each of the links you sent me.

With regards the -eink displays and processor I am using. I had someone help me order the parts. But I think I will need to order some new parts. The parts I currently using are:

Pimoroni Inky pHAT - eInk Display - Black/White

Arduino Mega 2560 R3 (Atmega2560 - assembled) - Mega!

I found this link which tells me the board layout for the inky phat:

I also have a number of other e-ink displays:
Pimoroni Inky pHAT - 3 Color eInk Display - Yellow/Black/White

2.9" Flexible Monochrome eInk / ePaper Display - 296x128 Monochrome

Adafruit 2.13" Tri-Color eInk / ePaper Display with SRAM - Red Black White

After doing some digging I now know that the inky phats are for Raspberry Pi but they should be usable on Arduino? If not I will go onto ebay and try and find some new displays.

After doing some digging I now know that the inky phats are for Raspberry Pi but they should be usable on Arduino?

Yes, they should be usable on an Arduino. But I don't see level converters on the board, so you should use level converters or voltage dividers or at least series resistors for the data lines.

For 5V Arduino it might be better to use bare panels and a connection module such as Adafruit eInk Breakout Friend with 32KB SRAM or (for 3.3V processors) DESPI-C02 .

Needs 5v and 3v3 power

in Inky pHAT at Raspberry Pi GPIO Pinout

Is surprising or unclear.

I don't know if the e-paper panels of your links are supported by GxEPD2. You could consider using the e-paper library from Adafruit, for your Adafruit products.

Arduino MEGA is not the optimal choice for use with (multiple) e-paper displays. You would need paged drawing. This is easier with GxEPD2 than with GxEPD, if you want to use the MultiDisplayExample.

You can report the inking on the flex connector of your panels, then I can compare with my panels to guess if it is supported with GxEPD2.

Jean-Marc

Hello Jean-Marc

Thank you for your time and effort.
I have gathered the parts for my project and following your recommendations I have settled on the following.

An ESP-32 processor

Two of these 2.9 inch displays
https://www.buy-lcd.com/products/29inch-296128-resolution-e029a01-epd-display-eaper-displayanel-gdeh029a1-epaper-screen

I will also have 2 "Connector board DESPI-C02" to run the e-ink displays in parallel from my breadboard

  1. Would these parts achieve multiple e-ink display for animation as discussed

  2. What is the largest e-ink display you recommend that will be usable for animation?

I am trying to match your exact set up, to remove any potential hardware issues, so that the only thing I need to do is modify your code to include animation.

Thanks again for all of your effort

@joduffy,

I am currently short of time, and not well organized to help with such questions.

I thought I have that processor board, but I don't find it.
I may have stored it away, because maybe it is not usable with my libraries, would need to check.
No, I have the ESP8266 Development Platform

Good Display uses SW SPI in their demo code, so they don't care about which pins they use for SPI.
Yes, the ESP32 Development Platform doesn't have HW SPI pins on the e-paper connector.

You need to check yourself, if the connector for DESPI-C02 of this board uses HW SPI pins. Solved.
But with ESP32 HW SPI pins could be re-mapped.

  1. Would these parts achieve multiple e-ink display for animation as discussed

I can't answer this question, as I don't know what your requirements for "animation" speed are.
And your link to the panel is wrong.

  1. What is the largest e-ink display you recommend that will be usable for animation?

Same answer. You could look for partial update times on the vendor site.
For me, only 1.54" b/w would be usable for a sort of animation. But I wouldn't recommend, because of shortened life expectancy

I am trying to match your exact set up, to remove any potential hardware issues, so that the only thing I need to do is modify your code to include animation.

If you have only 2 displays connected, you can use separate pins for the BUSY lines with ESP32.

The example tries to show both options.

Jean-Marc

Thank you for the reply back.
I have managed to get the parts connected. And wrote editted the code down to something more simple:

// GxEPD_MultiDisplayExample : test example for e-Paper displays from Waveshare and from Dalian Good Display Inc.
//
// Created by Jean-Marc Zingg based on demo code from Good Display,
// available on http://www.good-display.com/download_list/downloadcategoryid=34&isMode=false.html
//
// The e-paper displays are available from:
//
// https://www.aliexpress.com/store/product/Wholesale-1-54inch-E-Ink-display-module-with-embedded-controller-200x200-Communicate-via-SPI-interface-Supports/216233_32824535312.html
//
// http://www.buy-lcd.com/index.php?route=product/product&path=2897_8363&product_id=35120
// or https://www.aliexpress.com/store/product/E001-1-54-inch-partial-refresh-Small-size-dot-matrix-e-paper-display/600281_32815089163.html
//

// Supporting Arduino Forum Topics:
// Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0
// Good Dispay ePaper for Arduino : https://forum.arduino.cc/index.php?topic=436411.0

// mapping suggestion from Waveshare 2.9inch e-Paper to Wemos D1 mini
// BUSY -> D2, RST -> D4, DC -> D3, CS -> D8, CLK -> D5, DIN -> D7, GND -> GND, 3.3V -> 3.3V

// mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board
// NOTE: there are variants with different pins for SPI ! CHECK SPI PINS OF YOUR BOARD
// BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V

// mapping suggestion for AVR, UNO, NANO etc.
// BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 13, DIN -> 11

// include library, include base class, make path known
#include <GxEPD.h>

// select the display classes to use
#include <GxGDEH029A1/GxGDEH029A1.h>      // 2.9" b/w

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

#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>

#if defined(ESP32)

// create GxIO_SPI instances for each display, each instance with different CS line;
// disable reset line to disable cross resets by multiple instances
// GxIO_SPI(SPIClass& spi, int8_t cs, int8_t dc, int8_t rst = -1, int8_t bl = -1);
GxIO_Class io1(SPI, 5, 14, -1); // CS = 5(SS), DC = 17, RST disabled
GxIO_Class io2(SPI, 0, 14, -1); // CS = 0, DC = 17, RST disabled

// create display class instances for each display, each instance with different BUSY line, or BUSY lines or-ed to one pin
// GxGDEP015OC1(GxIO& io, int8_t rst = D4, int8_t busy = D2);
// BUSY lines can be or-ed with diodes and pulldown resistor for displays with BUSY active HIGH
GxGDEH029A1 display1(io1, -1, 4); // BUSY = 4, or-ed
GxGDEH029A1 display2(io2, -1, 15); // BUSY = 4, or-ed

// BUSY lines can be or-ed with diodes and pulldown resistor for displays with BUSY active LOW
//GxGDEW042T2 display4(io4, -1, 15); // BUSY = 15, or-ed

#define RST_PIN 16

#endif

#if defined(_GxGDEH029A1_H_)
namespace BMxGDEH029A1
{
#include "GxGDEH029A1/BitmapExamples.h"
void showBitmapExample(GxEPD& display)
{
  display.drawExampleBitmap(BitmapExample1, sizeof(BitmapExample1));
  delay(2000);
  display.drawExampleBitmap(BitmapExample2, sizeof(BitmapExample2));
  delay(2000);
  display.setRotation(0);
  display.fillScreen(GxEPD_WHITE);
  display.drawExampleBitmap(BitmapExample1, 0, 0, GxGDEH029A1_WIDTH, GxGDEH029A1_HEIGHT, GxEPD_BLACK);
  display.update();
  delay(2000);
}
#undef _BitmapWaveshare_H_
#undef _GxBitmapExamples_H_
}
#endif

void setup()
{
  Serial.begin(115200);
  Serial.println();
  Serial.println("setup");

  // one common reset for all displays
  pinMode(RST_PIN, OUTPUT);
  digitalWrite(RST_PIN, LOW);
  delay(20);
  digitalWrite(RST_PIN, HIGH);
  delay(20);

  display1.init(115200); // enable diagnostic output on Serial
  display2.init(115200); // enable diagnostic output on Serial

  Serial.println("setup done");
}

void loop()
{
  Serial.println("BMxGDEH029A1::showBitmapExample(display1)");
  BMxGDEH029A1::showBitmapExample(display1);
  Serial.println("BMxGDEH029A1::showBitmapExample(display2)");
  BMxGDEH029A1::showBitmapExample(display2);

  Serial.println("showFont(display1, \"FreeMonoBold9pt7b\", &FreeMonoBold9pt7b)");
  showFont(display1, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
  Serial.println("showFont(display2, \"FreeMonoBold9pt7b\", &FreeMonoBold9pt7b)");
  showFont(display2, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
  
  delay(10000);
}

void showFont(GxEPD& display, const char name[], const GFXfont* f)
{
  display.fillScreen(GxEPD_WHITE);
  display.setTextColor(GxEPD_BLACK);
  display.setFont(f);
  display.setCursor(0, 0);
  display.println();
  display.println(name);
  display.println(" !\"#$%&'()*+,-./");
  display.println("0123456789:;<=>?");
  display.println("@ABCDEFGHIJKLMNO");
  display.println("PQRSTUVWXYZ[\\]^_");
#if defined(_GxGDEW0154Z04_H_) || defined(_GxGDEW0213Z16_H_) || defined(_GxGDEW029Z10_H_) || defined(_GxGDEW027C44_H_)
  display.setTextColor(GxEPD_RED);
#endif
  display.println("`abcdefghijklmno");
  display.println("pqrstuvwxyz{|}~ ");
  display.update();
  delay(5000);
}

But I am having trouble with any images showing up on the e-ink displays. This link shows the setup needed for the board to work correctly.

https://v4.cecdn.yun300.cn/100001_1909185148/EN-ESP32-02.pdf

Here is a screenshot of the needed settings:

and here is my settings:

My issue is that I cannot get the programmer model AVRISP MkII
I have looked for resources on how to install the above model but to no luck.

I have tried the normal upload and this is the output I get but nothing works. So I am assumin gI need the programmer model to make the ESP32 board work?
Box

@joduffy,

I am not curious enough to try to find out what your issue is.

I dislike to have to open links to foreign places to find out.

I don't understand why AVRISP MkII comes into play.

@ZinggIM

I tried to scale the example to as simple as possible to simply get one display working.

I attached an image and I simply have an SPI connector to a GxGDEH029A1 // 2.9" b/w
display. The SPI connector is attached to an ESP32 board.

But when I look into the header file:
C:\Users\xxx\Documents\Arduino\hardware\espressif\esp32\variants\lolin32\pins_arduino.h

It does not have any pins defined for 16 or 17

The code uploads fine, but the e-ink display does not work.
Hopefully this removes any issues of my previous post which you said you couldn't understand and didn't want to dig into which I understand.

I was trying to combine the manufactures directions with your directions. Now I am simply trying to get the simplest example to work but to no avail.

The example I am trying to get working is the: GxEPD_Example

I have uncommented out the line for my display:

#include <GxGDEH029A1/GxGDEH029A1.h>      // 2.9" b/w

@joduffy,

I tried to scale the example to as simple as possible to simply get one display working.

Congratulations! This is a very sensible first step to do. By "scale" you mean to use the example GxEPD_Example.

It does not have any pins defined for 16 or 17

These are valid pins. See:

#define NUM_DIGITAL_PINS        40

You need to check on your processor board if they are available as pins.

The code uploads fine, but the e-ink display does not work.

This isn't surprising, as you ignored the following:

Good Display uses SW SPI in their demo code, so they don't care about which pins they use for SPI.
Yes, the ESP32 Development Platform doesn't have HW SPI pins on the e-paper connector.

You either need to connect your DESPI-C02 to the HW SPI pins available on the Arduino headers, or remap the HW SPI pins to the pins used by the e-paper connector.

You can find a method to remap SPI pins in: GxEPD2_WS_ESP32_Driver.ino

Hi.
I managed to get the GxEPD_Example working on an Ardunio Mega 2560.
So success!

But I cannot get the GxEPD_MultiDisplayExample to work.
I did noticed that it didn't have an if else code block for the mega. So I looked at the previous example I could get working and added the following code but no luck:

#if defined(ARDUINO_AVR_MEGA2560)

// for SPI pin definitions see e.g.:
// C:\Users\xxx\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.6.21\variants\mega\pins_arduino.h

// select one, depending on your CS connection
//GxIO_Class io(SPI, /*CS=*/ SS, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9 selected for default of GxEPD_Class
//GxIO_Class io(SPI, /*CS=*/ 10, /*DC=*/ 8, /*RST=*/ 9); // arbitrary selection of 8, 9, CS on 10 (for CS same as on UNO, for SPI on ICSP use)
GxIO_Class io1(SPI, 53, 8, -1); //  RST disabled
GxIO_Class io2(SPI, 10, 8, -1); //  RST disabled

//GxEPD_Class display(io, /*RST=*/ 9, /*BUSY=*/ 7); // default selection of (9), 7
GxGDEH029A1 display1(io1, -1, 7); // BUSY = 4, or-ed
GxGDEH029A1 display2(io2, -1, 7); // BUSY = 4, or-ed

#define RST_PIN 9

#endif

I also did the same for the displays in the setup:

#if defined(ARDUINO_AVR_MEGA2560)
  display1.init(115200); // enable diagnostic output on Serial
  display2.init(115200); // enable diagnostic output on Serial
#else
  display1.init(115200); // enable diagnostic output on Serial
  display2.init(115200); // enable diagnostic output on Serial
  display3.init(115200); // enable diagnostic output on Serial
#endif

And loop functions:

#if defined(ARDUINO_AVR_MEGA2560)
  Serial.println("BMxGDEH029A1::showBitmapExample(display1)");
  BMxGDEH029A1::showBitmapExample(display1);
  Serial.println("BMxGDEH029A1::showBitmapExample(display2)");
  BMxGDEH029A1::showBitmapExample(display2);
  Serial.println("showFont(display1, \"FreeMonoBold9pt7b\", &FreeMonoBold9pt7b)");
  showFont(display1, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
  Serial.println("showFont(display2, \"FreeMonoBold9pt7b\", &FreeMonoBold9pt7b)");
  showFont(display2, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
#else
  Serial.println("BMxGDEP015OC1::showBitmapExample(display1)");
  BMxGDEP015OC1::showBitmapExample(display1);
  Serial.println("BMxGDEH029A1::showBitmapExample(display2)");
  BMxGDEH029A1::showBitmapExample(display2);
  //Serial.println("BMxGDE0213B1::showBitmapExample(display3)");
  BMxGDE0213B1::showBitmapExample(display3);
  Serial.println("showFont(display1, \"FreeMonoBold9pt7b\", &FreeMonoBold9pt7b)");
  showFont(display1, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
  Serial.println("showFont(display2, \"FreeMonoBold9pt7b\", &FreeMonoBold9pt7b)");
  showFont(display2, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
  Serial.println("showFont(display3, \"FreeMonoBold9pt7b\", &FreeMonoBold9pt7b)");
  showFont(display3, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
#endif