Waveshare e-paper displays with SPI

ZinggJM:
@rncernic,

Please be more specific, what you tried, what did work, and what didn't.

Jean-Marc

And report the inking on the flex connector, then I can compare with the panels I have.

Hi guys,

I got my 7.5 inch v2 display (800x480) from waveshare the other day. I'm currently using the esp8266 driver board.

The waveshare examples did work for me, so I can print text, numbers and so on onto the display. I encounter a weird bug as soon as I use the "Paint_DrawImage" function to print an convertet bmp-file. The image shows up just fine, but on the right edge there is a thick black line. This happens on every image and is not depended on the image-size. I used the "Image2LCD" software to convert the image to a c-array.

I also read here that you guys are using the GxEPD2-Library, but I had no luck getting the examples to work with my driver board.

  1. Did any of you guys face the same challenges with the waveshare-librarys? Do you have an idea why the draw-image behaves so weird? This only happens on a white background...
  2. Is there an example for the GxEPD(2) library that works out of the box with the driver board? What would be a good starting point to read up on the configuration for the esp8266 driver board?

Thanks guys!

@jj1029,

always post a link to the product in question, to make sure.

try GxEPD2_Example.ino and uncomment line 123:

GxEPD2_BW < GxEPD2_750_T7, GxEPD2_750_T7::HEIGHT / 2 > display(GxEPD2_750_T7(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); // GDEW075T7 800x480

I can't help you with the issue with the Waveshare code.

Jean-Marc

Jean-Marc,

I tried to run GxEPD_Example and GxEPD2_Example, both selecting the following line.

#include <GxGDEH0213B73/GxGDEH0213B73.h>  // 2.13" b/w newer panel

ZinggJM:
And report the inking on the flex connector, then I can compare with the panels I have.

HINK-E0213-A01
Date: 2017-06-02
SYX1834

Thank you,
Ricardo

@rncernic,

I give up. I still don't know what worked, what didn't, and what produced which effect.

Your inking doesn't correspond to any of the panels I have. The style is closest to the GDE0213B1.

I can't support your display, you need to resolve your issue with TTGO. Ask them which controller is used, or which panel from Good Display corresponds to the panel you got.

Jean-Marc

Jean-Mark,

Thank you for your effort helping me. Really appreciated.

Will try to find out what is going on with this display. If I'm lucky will let you know.

Best regards,
Ricardo

hello everyone -- I just wanted to post how I resolved my particular problems with this after losing about a day with trial and error, in the hope that it will be useful to someone.

I use the waveshare 3-color 2.9 inch display with a NodeMCU 1.0 (ESP-E12).
In addition with the trouble with pin D8 (GPIO15), already solved somewhere in this thread and already noted in the example source code, I had trouble with using pin D4 (GPIO2).
I ended up moving RST to GPIO12 (D6) and CS to GPIO5 (D1) to get the minimal example code to work, as follows:

BUSY -> D2, RST -> D6, DC -> D3, CS -> D1, CLK -> D5, DIN -> D7, GND -> GND, VCC -> 3V3.

here is the full "minimal example" code that ended up working for me:

#include <GxEPD.h>
#include <GxGDEW029Z10/GxGDEW029Z10.h>    // 2.9" b/w/r
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>

GxIO_Class io(SPI, /*CS=D8*/ 5, /*DC=D3*/ 0, /*RST=D6*/ 12); 
GxEPD_Class display(io, /*RST=D6*/12, /*BUSY=D2*/4); 

void setup()
{
  display.init();
  display.eraseDisplay();
  display.drawPaged(drawHelloWorld); 
}

void drawHelloWorld()
{
  display.setTextColor(GxEPD_BLACK);
  display.print("Hello World!");
}

void loop() {};

Version 1.2.10 of library GxEPD2 is available in Library Manager.

  • added support for GDEH075Z90 7.5" b/w/r 880x528
  • the controller of GDEH075Z90 supports partial update, but refesh is full screen
  • the controller of GDEH075Z90 doesn't support differential update (not possible on 3-color anyway)
  • note: the connector of the GDEH075Z90 is mirrored; connects downward on DESPI-C02
  • added optional init parameter "reset_duration" in ms, same default 20ms as before
  • reset_duration = 2 may help with "clever" reset circuit of newer boards from Waveshare

Support for GDEH075Z90 is available thanks to the panel donated by Lukas @luki_v11.

Note the flex connector: the pins connect to the bottom connection of the connector.
I didn't know the connector makes connection on both sides before.

Jean-Marc

Any idea why Partial Refresh aka display.updateWindow doesn't work correctly after DeepSleep?
It works fine normally, (Button 1, aka Left) But after Deepsleep (Button 3) it refreshes the maximum vertical range.

The Original Plan was the use this thingy to Display Room Temperature and then go into sleep for a few Minutes and then refresh only the numbers without flickering too much. But that's my first time playing with an e-ink display so maybe i'm going the wrong way?

//#include "SD.h"
#include "SPI.h"
#include <GxEPD.h>
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>

#include <GxGDEH029A1/GxGDEH029A1.h> // 2.9" b/w 296 x 128 Pixel

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

//int bmpWidth = 3, bmpHeight = 1;
//width:230,height:60
//const unsigned char lilygo[] = {0xff, 0xff, 0xff};

int freq = 2000;
const char *skuNum = "Hier Steht Text";
int startX = 0, startY = 0;

#define SPI_MOSI        23
#define SPI_MISO        2
#define SPI_CLK         18

#define ELINK_SS        5
#define ELINK_BUSY      4
#define ELINK_RESET     12
#define ELINK_DC        19

#define SDCARD_SS       13

#define BUTTON_1        37
#define BUTTON_2        38
#define BUTTON_3        39

#define SPEAKER_OUT     25

GxIO_Class io(SPI, ELINK_SS, ELINK_DC, ELINK_RESET);
GxEPD_Class display(io, ELINK_RESET, ELINK_BUSY);
// SPIClass sdSPI(VSPI);


void setup()
{
    pinMode(BUTTON_1, INPUT);
    pinMode(BUTTON_2, INPUT);
    pinMode(BUTTON_3, INPUT);

    Serial.begin(115200);

    // Lautsprecher
    ledcSetup(0, 1000, 8);
    ledcAttachPin(SPEAKER_OUT, 0);
    //int i = 3;
    //while (i--) {
    //    ledcWriteTone(0, 1000);
    //    delay(200);
    //    ledcWriteTone(0, 0);
    //}

    SPI.begin(SPI_CLK, SPI_MISO, SPI_MOSI, ELINK_SS);
   
    display.init();
    display.setRotation(1);
    

   
}

void loop()
{
    if (digitalRead(BUTTON_1) == LOW) {
        
        display.setCursor(1, 1);
        display.fillRect(1, 1, 62, 62, GxEPD_WHITE);
        display.updateWindow(1, 1, 62, 62, true);
        display.setFont(&FreeMonoBold24pt7b);
        display.setTextColor(GxEPD_BLACK);
        display.setCursor(2,60);
        display.println("36");
        display.updateWindow(1, 1, 62, 62, true);
        //display.update();
        delay(500);
        
    } else if (digitalRead(BUTTON_2) == LOW) {
        
        display.fillScreen(GxEPD_BLACK);
        display.setCursor(1, 1);
        display.fillRect(1, 1, 62, 62, GxEPD_WHITE);
        display.fillRect(64, 1, 62, 62, GxEPD_WHITE);
        display.fillRect(127, 1, 62, 62, GxEPD_WHITE);
        display.fillRect(1, 64, 62, 63, GxEPD_WHITE);
        display.fillRect(64, 64, 62, 63, GxEPD_WHITE);
        display.fillRect(127, 64, 62, 63, GxEPD_WHITE);
        //display.setCursor(display.width()  - display.width() / 2 - 20, display.height() - 35);
        //display.println(skuNum);
        display.setFont(&FreeMonoBold24pt7b);
        display.setTextColor(GxEPD_BLACK);
        display.setCursor(2,60);
        display.println("25");
        
        display.fillRect(190, 1, 105, 126, GxEPD_WHITE);
        display.setCursor(191,40);
        display.println("17");
        display.setCursor(191,80);
        display.println("38");
    
        display.update();
        delay(500);
      
       
       
       
       
       /* SOUND Button 
        int i = 3;
        while (i--) {
        ledcWriteTone(0, freq);
        delay(200);
        ledcWriteTone(0, 0);
        };
        if (freq >= 100) freq = freq - 200;
        if (freq < 100) freq = 2000; */
    } else if (digitalRead(BUTTON_3) == LOW) {
        esp_sleep_enable_ext0_wakeup((gpio_num_t )BUTTON_3, LOW);
        esp_deep_sleep_start();
    }
}

Edit: Device Link: TTGO T5 V2.2

@Haldi,

please always post a clickable link to the device in question, e-paper and processor.

I don't know if your ESP32 Ttgo T5 V2.2 switches off power to the display panel on processor deep sleep.

With GxEPD you need to do a first full refresh, followed by a partial refresh to full screen with same content, before using partial updates (with differential refresh) after power was removed to the controller. This because the content of the "previous" buffer of the controller needs to correspond to the display on screen for differential update to work.

In GxEPD2 this initial update is handled by the driver class automatically.

Maybe this is an explanation for your issue. My TTGO T5 is buried somewhere; I will not go test with it.

Jean-Marc

Added:

But the reason might be simple: partial windows should have width of multiple of eight in physical x direction, and start at a multiple of eight boundary. They are increased if this is not the case.
The graphics buffer in the GxEPD display class is initialized to white in init(). This "erases" part of your grid.

Edited the Link in.

Does GxEPD2 have the same need for multiples of 8 for refreshing?

I read that gxEPD2 needs hardware SPI to work. When I tried the Example on my TTGO T5 v2.2 I failed.
Going by my last code i assume i used Software SPI or did i somehow fail at the configuration? The Example file was quite ladden for a noob like me.

Edit:

ZinggJM:
Added:
But the reason might be simple: partial windows should have width of multiple of eight in physical x direction, and start at a multiple of eight boundary. They are increased if this is not the case.
The graphics buffer in the GxEPD display class is initialized to white in init(). This "erases" part of your grid.

You are Indeed right! That is the issue. making the 2nd Square black makes it so much more obvious. Mea Cupla.

Edit2: Okay, GxEPD2 is worked if configured correctly :slight_smile:
Would you reccomend v2 in all cases? I haven't really started coding yet, just some small testing.

@Haldi

Does GxEPD2 have the same need for multiples of 8 for refreshing?

Yes, and not only for refreshing. All writes to controller memory have 8 bit granularity, for 8 pixels.
Same is true for windows addressing, e.g. partial windows. See also README.md

Would you reccomend v2 in all cases?

You mean GxEPD2 versus GxEPD?

Yes, I recommend GxEPD2 for all new users and new projects.

But there are more users of GxEPD than of GxEPD2, and therefore more real-life examples around.

Actually GxEPD lags behind GxEPD2 with support for new panels, but this is not intentional.

Jean-Marc

Please help me out here... i've completly lost my ways with the multiples of 8...

Rectangle starts at Pixel 1, goes down by 63 to Pixel 64. 1 Black then Starts next at 65.

Now the Refresh Starts at Pixel 8 goes down by 54 and ends on Pixel 62, leaves 2 White. According to program.

But the Text starts at pixel 59 and there is still one black which shows black ends on Pixel 60....

Multiples of 8 are 48, 56 and 64..... which are none of those -.-
I don't get it anymore.

void loop()
{
    if (digitalRead(BUTTON_1) == LOW) {
        
        display.setCursor(1, 1);
        display.fillRect(1, 8, 62, 54, GxEPD_BLACK);
        display.updateWindow(1, 8, 62, 54, true);
        display.setFont(&FreeMonoBold24pt7b);
        display.setTextColor(GxEPD_WHITE);
        display.setCursor(2,59);
        display.println("36");
        display.updateWindow(1, 8, 62, 54, true);
        //display.update();
        delay(500);
        
    } else if (digitalRead(BUTTON_2) == LOW) {
        
        display.fillScreen(GxEPD_BLACK);
        display.setCursor(1, 1);
        display.fillRect(1, 1, 62, 63, GxEPD_WHITE);
        display.fillRect(64, 1, 62, 63, GxEPD_WHITE);
        display.fillRect(127, 1, 62, 63, GxEPD_WHITE);
        display.fillRect(1, 65, 62, 62, GxEPD_BLACK);
        display.fillRect(64, 65, 62, 62, GxEPD_WHITE);
        display.fillRect(127, 65, 62, 62, GxEPD_WHITE);
        //display.setCursor(display.width()  - display.width() / 2 - 20, display.height() - 35);
        //display.println(skuNum);
        display.setFont(&FreeMonoBold24pt7b);
        display.setTextColor(GxEPD_BLACK);
        display.setCursor(2,59);
        display.println("25");
        
        display.fillRect(190, 1, 105, 126, GxEPD_WHITE);
        display.setCursor(191,40);
        display.println("17");
        display.setCursor(191,80);
        display.println("38");
    
        display.update();
        delay(500);

@Haldi,

I am not going to debug your program, neither in practice, nor in my head!

        display.updateWindow(1, 8, 62, 54, true);

will result in:

        display.updateWindow(1, 8, 62, 56, true);

the encompassing rectangle of your target rectangle. Native x direction is your y direction.

Hi everybody, I'm using an ESP32 Bluetooth/Wifi (https://www.waveshare.com/e-paper-esp32-driver-board.htm) with this epaper (1.54 inch e-paper display high resolution 200x200 fast refresh, GDEW0154M09_Good Display) and I'm having problems with the digitalRead function on ESP32 pins.
For example, I needed the board to display something on the epaper while pin number 2 is on, so using a button. I did some checks and the serial print of digitalRead(pin 2) worked well. When I put the digitalRead in a condition (for example an if) it doesn't work properly. In fact, if I request digitalRead to be == 1 (or HIGH) nothing happens pressing the button, never enters the if, if I request == 0 the code always enters the if condition also pressing the button.

I used pin number 2 because much of the other pins had some problems that I really don't understand: their state becomes HIGH (so = 1) just by touching them! And that's really wired, never happened with other boards. Maybe are too much sensitive, while pin 2 lights the internal led, so I'm sure it works well.

Sorry for my English, hope someone could help me. Thank you!

ZinggJM:
will result in:

        display.updateWindow(1, 8, 62, 56, true);

No... and that is what fucks me up so much....

display.setCursor(1, 1);
        display.fillRect(1, 8, 62, 56, GxEPD_WHITE);
        display.updateWindow(1, 8, 62, 56, true);
        display.setFont(&FreeMonoBold24pt7b);
        display.setTextColor(GxEPD_BLACK);
        display.setCursor(2,60);
        display.println("36");
        display.updateWindow(1, 8, 62, 56, true);

Works fine in Normal Mode, but after Deepsleep it goes way beyond that!
While 56 IS A Multiple of 8 and Should work right?

ZinggJM:
the encompassing rectangle of your target rectangle. Native x direction is your y direction.

Sorry i don't follow... my english comprehension is not up to par.
display.updateWindow(Xstart, Ystart, Xwidth, Yhight, true) right?
Width works fine so i don't care, but Y has some issues after deep sleep.

@Haldi, you had your chance to get help from me. No longer, sorry.

So you're saying everything is working as intended?
Good, then i'll just fiddle around until i get it working as i want.

For those who insist in using differential update with GxEPD:

ZinggJM:
...
With GxEPD you need to do a first full refresh, followed by a partial refresh to full screen with same content, before using partial updates (with differential refresh) after power was removed to the controller. This because the content of the "previous" buffer of the controller needs to correspond to the display on screen for differential update to work.
...

and there is even one controller that needs two partial updates to full screen after a full update.

ZinggJM:
Version 1.2.10 of library GxEPD2 is available in Library Manager.

  • added support for GDEH075Z90 7.5" b/w/r 880x528
  • the controller of GDEH075Z90 supports partial update, but refesh is full screen
  • the controller of GDEH075Z90 doesn't support differential update (not possible on 3-color anyway)
  • note: the connector of the GDEH075Z90 is mirrored; connects downward on DESPI-C02
  • added optional init parameter "reset_duration" in ms, same default 20ms as before
  • reset_duration = 2 may help with "clever" reset circuit of newer boards from Waveshare

Support for GDEH075Z90 is available thanks to the panel donated by Lukas @luki_v11.

Note the flex connector: the pins connect to the bottom connection of the connector.
I didn't know the connector makes connection on both sides before.

Jean-Marc

Hi, could you tell me what are the times of partial update?