Waveshare e-paper displays with SPI

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.

I've added

  display.hibernate();
  digitalWrite(D4, LOW);

But nevertheless I measure 0.9 Volts on D4 during deep sleep.

D4 (GPIO2) is a strapping pin for boot mode. It has a weak internal pull-up. I should have known.
This explains the 0.9 Volts caused by the base-emitter voltage of the transistor.
This is enough to keep the board powered.
Use a different pin. A pull-down on D4 would prevent normal boot of the processor.

This is a quick guess. I may investigate more next days.

Jean-Marc

Thanks Zinggj, I tried the commands in the example and i get the same error I mentioned earlier. In fact i tried them before reaching for help here, thinking someone could help me understand the code.

I've changed it to D6 and now I read 0 Volts during deepsleep. Lets see if this helps to drain less battery.

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

  • added support for GDEW0102T4 1.02" b/w 80x128 panel or Waveshare 1.02" b/w board
  • the GDEW0102T4 panel has a different connector than the other SPI panels
  • the GDEW0102T4 panel can be used with the DESPI-C102 connection module
  • HAT Connection board demo kit for 1.02 inch e-ink display
  • my test have been done with the Waveshare 1.02" b/w board

Support for GDEW0102T4 has been added thanks to a panel and a Waveshare board donated by @laminar.

Jean-Marc

1 Like

Unfortunately I still have issues with the power consumption. Altough I changed the Reset-Pin, my setup still draws 3 mA during deep-sleep, while the same code withput the display attached only needs 0.2 mA. @ZinggJM Do you have any additional tipps to investigate? Shouldn't be display.hibernate();shut down the display completly? I also tried display.powerOff();, but its the same...