274 lines
8.4 KiB
C++
274 lines
8.4 KiB
C++
// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
|
|
// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
|
|
//
|
|
// Display Library based on Demo Example from Good Display: https://www.good-display.com/companyfile/32/
|
|
//
|
|
// Author: Jean-Marc Zingg
|
|
//
|
|
// Version: see library.properties
|
|
//
|
|
// Library: https://github.com/ZinggJM/GxEPD2
|
|
//
|
|
// Purpose: show uses of GxEPD2_GFX base class for references to a display instance
|
|
|
|
// Supporting Arduino Forum Topics (closed, read only):
|
|
// Good Display ePaper for Arduino: https://forum.arduino.cc/t/good-display-epaper-for-arduino/419657
|
|
// Waveshare e-paper displays with SPI: https://forum.arduino.cc/t/waveshare-e-paper-displays-with-spi/467865
|
|
//
|
|
// Add new topics in https://forum.arduino.cc/c/using-arduino/displays/23 for new questions and issues
|
|
|
|
// see GxEPD2_wiring_examples.h for wiring suggestions and examples
|
|
|
|
// base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter, uses ~1.2k more code
|
|
// enable GxEPD2_GFX base class
|
|
#define ENABLE_GxEPD2_GFX 1
|
|
|
|
// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX
|
|
//#include <GFX.h>
|
|
// Note: if you use this with ENABLE_GxEPD2_GFX 1:
|
|
// uncomment it in GxEPD2_GFX.h too, or add #include <GFX.h> before any #include <GxEPD2_GFX.h>
|
|
// !!!! ============================================================================================ !!!!
|
|
|
|
#include <GxEPD2_BW.h>
|
|
#include <GxEPD2_3C.h>
|
|
#include <GxEPD2_4C.h>
|
|
#include <GxEPD2_7C.h>
|
|
#include <Fonts/FreeMonoBold9pt7b.h>
|
|
|
|
#include "BitmapDisplay.h"
|
|
#include "TextDisplay.h"
|
|
|
|
// select the display constructor line in one of the following files (old style):
|
|
#include "GxEPD2_display_selection.h"
|
|
#include "GxEPD2_display_selection_added.h"
|
|
//#include "GxEPD2_display_selection_more.h" // private
|
|
|
|
// or select the display class and display driver class in the following file (new style):
|
|
#include "GxEPD2_display_selection_new_style.h"
|
|
|
|
// for handling alternative SPI pins (ESP32, RP2040) see example GxEPD2_Example.ino
|
|
|
|
BitmapDisplay bitmaps(display);
|
|
|
|
void setup()
|
|
{
|
|
Serial.begin(115200);
|
|
Serial.println();
|
|
Serial.println("setup");
|
|
delay(100);
|
|
//display.init(115200); // default 10ms reset pulse, e.g. for bare panels with DESPI-C02
|
|
display.init(115200, true, 2, false); // USE THIS for Waveshare boards with "clever" reset circuit, 2ms reset pulse
|
|
// first update should be full refresh
|
|
helloWorld(display);
|
|
delay(1000);
|
|
// partial refresh mode can be used to full screen,
|
|
// effective if display panel hasFastPartialUpdate
|
|
helloFullScreenPartialMode(display);
|
|
delay(1000);
|
|
helloArduino(display);
|
|
delay(1000);
|
|
helloEpaper(display);
|
|
delay(1000);
|
|
//helloValue(display, 123.9, 1);
|
|
//delay(1000);
|
|
showFont(display, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b);
|
|
delay(1000);
|
|
//BitmapDisplay(display).drawBitmaps();
|
|
bitmaps.drawBitmaps();
|
|
//return;
|
|
if (display.epd2.hasPartialUpdate)
|
|
{
|
|
showPartialUpdate();
|
|
delay(1000);
|
|
} // else // on GDEW0154Z04 only full update available, doesn't look nice
|
|
//drawCornerTest();
|
|
//showBox(16, 16, 48, 32, false);
|
|
//showBox(16, 56, 48, 32, true);
|
|
display.powerOff();
|
|
deepSleepTest();
|
|
Serial.println("setup done");
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
}
|
|
|
|
void deepSleepTest()
|
|
{
|
|
//Serial.println("deepSleepTest");
|
|
const char hibernating[] = "hibernating ...";
|
|
const char wokeup[] = "woke up";
|
|
const char from[] = "from deep sleep";
|
|
const char again[] = "again";
|
|
display.setRotation(1);
|
|
display.setFont(&FreeMonoBold9pt7b);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
int16_t tbx, tby; uint16_t tbw, tbh;
|
|
// center text
|
|
display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
|
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
|
display.setFullWindow();
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(x, y);
|
|
display.print(hibernating);
|
|
}
|
|
while (display.nextPage());
|
|
display.hibernate();
|
|
delay(5000);
|
|
display.getTextBounds(wokeup, 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t wx = (display.width() - tbw) / 2;
|
|
uint16_t wy = (display.height() / 3) + tbh / 2; // y is base line!
|
|
display.getTextBounds(from, 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t fx = (display.width() - tbw) / 2;
|
|
uint16_t fy = (display.height() * 2 / 3) + tbh / 2; // y is base line!
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(wx, wy);
|
|
display.print(wokeup);
|
|
display.setCursor(fx, fy);
|
|
display.print(from);
|
|
}
|
|
while (display.nextPage());
|
|
delay(5000);
|
|
display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t hx = (display.width() - tbw) / 2;
|
|
uint16_t hy = (display.height() / 3) + tbh / 2; // y is base line!
|
|
display.getTextBounds(again, 0, 0, &tbx, &tby, &tbw, &tbh);
|
|
uint16_t ax = (display.width() - tbw) / 2;
|
|
uint16_t ay = (display.height() * 2 / 3) + tbh / 2; // y is base line!
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.setCursor(hx, hy);
|
|
display.print(hibernating);
|
|
display.setCursor(ax, ay);
|
|
display.print(again);
|
|
}
|
|
while (display.nextPage());
|
|
display.hibernate();
|
|
//Serial.println("deepSleepTest done");
|
|
}
|
|
|
|
void showBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial)
|
|
{
|
|
//Serial.println("showBox");
|
|
display.setRotation(1);
|
|
if (partial)
|
|
{
|
|
display.setPartialWindow(x, y, w, h);
|
|
}
|
|
else
|
|
{
|
|
display.setFullWindow();
|
|
}
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.fillRect(x, y, w, h, GxEPD_BLACK);
|
|
}
|
|
while (display.nextPage());
|
|
//Serial.println("showBox done");
|
|
}
|
|
|
|
void drawCornerTest()
|
|
{
|
|
display.setFullWindow();
|
|
display.setFont(&FreeMonoBold9pt7b);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
for (uint16_t r = 0; r <= 4; r++)
|
|
{
|
|
display.setRotation(r);
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillScreen(GxEPD_WHITE);
|
|
display.fillRect(0, 0, 8, 8, GxEPD_BLACK);
|
|
display.fillRect(display.width() - 18, 0, 16, 16, GxEPD_BLACK);
|
|
display.fillRect(display.width() - 25, display.height() - 25, 24, 24, GxEPD_BLACK);
|
|
display.fillRect(0, display.height() - 33, 32, 32, GxEPD_BLACK);
|
|
display.setCursor(display.width() / 2, display.height() / 2);
|
|
display.print(display.getRotation());
|
|
}
|
|
while (display.nextPage());
|
|
delay(2000);
|
|
}
|
|
}
|
|
|
|
// note for partial update window and setPartialWindow() method:
|
|
// partial update window size and position is on byte boundary in physical x direction
|
|
// the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation
|
|
// see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow()
|
|
// showPartialUpdate() purposely uses values that are not multiples of 8 to test this
|
|
|
|
void showPartialUpdate()
|
|
{
|
|
// some useful background
|
|
helloWorld(display);
|
|
// use asymmetric values for test
|
|
uint16_t box_x = 10;
|
|
uint16_t box_y = 15;
|
|
uint16_t box_w = 70;
|
|
uint16_t box_h = 20;
|
|
uint16_t cursor_y = box_y + box_h - 6;
|
|
float value = 13.95;
|
|
uint16_t incr = display.epd2.hasFastPartialUpdate ? 1 : 3;
|
|
display.setFont(&FreeMonoBold9pt7b);
|
|
display.setTextColor(GxEPD_BLACK);
|
|
// show where the update box is
|
|
for (uint16_t r = 0; r < 4; r++)
|
|
{
|
|
display.setRotation(r);
|
|
display.setPartialWindow(box_x, box_y, box_w, box_h);
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillRect(box_x, box_y, box_w, box_h, GxEPD_BLACK);
|
|
//display.fillScreen(GxEPD_BLACK);
|
|
}
|
|
while (display.nextPage());
|
|
delay(2000);
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
|
|
}
|
|
while (display.nextPage());
|
|
delay(1000);
|
|
}
|
|
//return;
|
|
// show updates in the update box
|
|
for (uint16_t r = 0; r < 4; r++)
|
|
{
|
|
display.setRotation(r);
|
|
display.setPartialWindow(box_x, box_y, box_w, box_h);
|
|
for (uint16_t i = 1; i <= 10; i += incr)
|
|
{
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
|
|
display.setCursor(box_x, cursor_y);
|
|
display.print(value * i, 2);
|
|
}
|
|
while (display.nextPage());
|
|
delay(500);
|
|
}
|
|
delay(1000);
|
|
display.firstPage();
|
|
do
|
|
{
|
|
display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
|
|
}
|
|
while (display.nextPage());
|
|
delay(1000);
|
|
}
|
|
}
|