From 44d68c63cf57acacbbb065c9b4bbaeeea4523151 Mon Sep 17 00:00:00 2001 From: ZinggJM Date: Tue, 19 Nov 2019 17:10:42 +0100 Subject: [PATCH] Version 1.2.3 - fixed partial update for 2.13" 3-color and 2.9" 3-color e-paper - partial update can be disabled with attribute usePartialUpdateWindow = false - added GxEPD2_GFX_Example to show uses of GxEPD2_GFX base class - replaced GxEPD2_MultiDisplayExample code, same code as GxEPD2_GFX_MultiDisplayExample - added extras/examples/GxEPD2_T_MultiDisplayExample, alternate example using template functions - major and minor fixes, such as typos that survived too long --- README.md | 9 +- examples/GxEPD2_Example/GxEPD2_Example.ino | 3 + examples/GxEPD2_GFX_Example/BitmapDisplay.cpp | 768 +++++++++++++ examples/GxEPD2_GFX_Example/BitmapDisplay.h | 48 + .../GxEPD2_GFX_Example/GxEPD2_GFX_Example.ino | 468 ++++++++ .../GxEPD2_GFX_Example/GxEPD2_boards_added.h | 153 +++ examples/GxEPD2_GFX_Example/TextDisplay.cpp | 302 +++++ examples/GxEPD2_GFX_Example/TextDisplay.h | 30 + .../GxEPD2_MultiDisplayExample.ino | 162 ++- .../GxEPD2_ParticleExample/project.properties | 2 +- .../project.properties | 2 +- .../GxEPD2_T_MultiDisplayExample.ino | 1003 +++++++++++++++++ library.properties | 2 +- src/GxEPD2_EPD.h | 4 + src/GxEPD2_GFX.h | 4 + src/epd3c/GxEPD2_213c.cpp | 4 + src/epd3c/GxEPD2_213c.h | 1 + src/epd3c/GxEPD2_290c.cpp | 4 + src/epd3c/GxEPD2_290c.h | 1 + src/epd3c/GxEPD2_420c.cpp | 9 + src/epd3c/GxEPD2_420c.h | 1 + 21 files changed, 2884 insertions(+), 96 deletions(-) create mode 100644 examples/GxEPD2_GFX_Example/BitmapDisplay.cpp create mode 100644 examples/GxEPD2_GFX_Example/BitmapDisplay.h create mode 100644 examples/GxEPD2_GFX_Example/GxEPD2_GFX_Example.ino create mode 100644 examples/GxEPD2_GFX_Example/GxEPD2_boards_added.h create mode 100644 examples/GxEPD2_GFX_Example/TextDisplay.cpp create mode 100644 examples/GxEPD2_GFX_Example/TextDisplay.h create mode 100644 extras/examples/GxEPD2_T_MultiDisplayExample/GxEPD2_T_MultiDisplayExample.ino diff --git a/README.md b/README.md index 4673e91..e038470 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,14 @@ #### other supported panels - ED060SCT 6" grey levels, on Waveshare e-Paper IT8951 Driver HAT -### Version 1.2.2 +### Version 1.2.3 +- fixed partial update for 2.13" 3-color and 2.9" 3-color e-paper +- partial update can be disabled with attribute usePartialUpdateWindow = false +- added GxEPD2_GFX_Example to show uses of GxEPD2_GFX base class +- replaced GxEPD2_MultiDisplayExample code, same code as GxEPD2_GFX_MultiDisplayExample +- added extras/examples/GxEPD2_T_MultiDisplayExample, alternate example using template functions +- major and minor fixes, such as typos that survived too long +#### Version 1.2.2 - fixed BMP handling, e.g. for BMPs created by ImageMagick - see also Arduino Forum Topic https://forum.arduino.cc/index.php?topic=642343.0 #### Version 1.2.1 diff --git a/examples/GxEPD2_Example/GxEPD2_Example.ino b/examples/GxEPD2_Example/GxEPD2_Example.ino index 2d61644..c6a8e17 100644 --- a/examples/GxEPD2_Example/GxEPD2_Example.ino +++ b/examples/GxEPD2_Example/GxEPD2_Example.ino @@ -241,6 +241,9 @@ #if !defined(__AVR) && !defined(_BOARD_GENERIC_STM32F103C_H_) +// note 16.11.2019: the compiler may exclude code based on constant if statements (display.epd2.panel == constant), +// therefore bitmaps may get optimized out by the linker + // comment out unused bitmaps to reduce code space used #include "bitmaps/Bitmaps200x200.h" // 1.54" b/w #include "bitmaps/Bitmaps104x212.h" // 2.13" b/w flexible GDEW0213I5F diff --git a/examples/GxEPD2_GFX_Example/BitmapDisplay.cpp b/examples/GxEPD2_GFX_Example/BitmapDisplay.cpp new file mode 100644 index 0000000..ec91f33 --- /dev/null +++ b/examples/GxEPD2_GFX_Example/BitmapDisplay.cpp @@ -0,0 +1,768 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// 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 +// +// BitmapDisplay shows the use of the display instance reference as a class member + +#include "BitmapDisplay.h" + +#if !defined(__AVR) && !defined(_BOARD_GENERIC_STM32F103C_H_) + +// note 16.11.2019: the compiler may exclude code based on constant if statements (display.epd2.panel == constant), +// therefore bitmaps may get optimized out by the linker +// but here display.epd2.panel is not known at compile time. + +// comment out unused bitmaps to reduce code space used +#include "bitmaps/Bitmaps200x200.h" // 1.54" b/w +#include "bitmaps/Bitmaps104x212.h" // 2.13" b/w flexible GDEW0213I5F +#include "bitmaps/Bitmaps128x250.h" // 2.13" b/w +#include "bitmaps/Bitmaps128x296.h" // 2.9" b/w +#include "bitmaps/Bitmaps152x296.h" // 2.6" b/w +#include "bitmaps/Bitmaps176x264.h" // 2.7" b/w +#include "bitmaps/Bitmaps240x416.h" // 3.71" b/w +#include "bitmaps/Bitmaps400x300.h" // 4.2" b/w +#include "bitmaps/Bitmaps640x384.h" // 7.5" b/w +#include "bitmaps/Bitmaps800x480.h" // 7.5" b/w +// 3-color +#include "bitmaps/Bitmaps3c200x200.h" // 1.54" b/w/r +#include "bitmaps/Bitmaps3c104x212.h" // 2.13" b/w/r +#include "bitmaps/Bitmaps3c128x296.h" // 2.9" b/w/r +#include "bitmaps/Bitmaps3c176x264.h" // 2.7" b/w/r +#include "bitmaps/Bitmaps3c400x300.h" // 4.2" b/w/r +#if defined(ESP8266) || defined(ESP32) +#include "bitmaps/Bitmaps3c800x480.h" // 7.5" b/w/r +#endif +#if defined(ESP32) +#include "bitmaps/WS_Bitmaps800x600.h" // 6.0" grey +#endif + +#elif !defined(__AVR) // Sketch too big for AVR + +// select only one to fit in code space +#include "bitmaps/Bitmaps200x200.h" // 1.54" b/w +//#include "bitmaps/Bitmaps104x212.h" // 2.13" b/w flexible GDEW0213I5F +//#include "bitmaps/Bitmaps128x250.h" // 2.13" b/w +//#include "bitmaps/Bitmaps128x296.h" // 2.9" b/w +//#include "bitmaps/Bitmaps176x264.h" // 2.7" b/w +////#include "bitmaps/Bitmaps400x300.h" // 4.2" b/w // not enough code space +////#include "bitmaps/Bitmaps640x384.h" // 7.5" b/w // not enough code space +// 3-color +//#include "bitmaps/Bitmaps3c200x200.h" // 1.54" b/w/r +//#include "bitmaps/Bitmaps3c104x212.h" // 2.13" b/w/r +//#include "bitmaps/Bitmaps3c128x296.h" // 2.9" b/w/r +//#include "bitmaps/Bitmaps3c176x264.h" // 2.7" b/w/r +////#include "bitmaps/Bitmaps3c400x300.h" // 4.2" b/w/r // not enough code space + +#endif + +void BitmapDisplay::drawBitmaps() +{ + display.setFullWindow(); +#ifdef _GxBitmaps104x212_H_ + drawBitmaps104x212(); +#endif +#ifdef _GxBitmaps128x250_H_ + drawBitmaps128x250(); +#endif +#ifdef _GxBitmaps128x296_H_ + drawBitmaps128x296(); +#endif +#ifdef _GxBitmaps176x264_H_ + drawBitmaps176x264(); +#endif +#ifdef _GxBitmaps400x300_H_ + drawBitmaps400x300(); +#endif +#ifdef _GxBitmaps640x384_H_ + drawBitmaps640x384(); +#endif +#ifdef _GxBitmaps800x480_H_ + drawBitmaps800x480(); +#endif +#ifdef _WS_Bitmaps800x600_H_ + drawBitmaps800x600(); +#endif + // 3-color +#ifdef _GxBitmaps3c104x212_H_ + drawBitmaps3c104x212(); +#endif +#ifdef _GxBitmaps3c128x296_H_ + drawBitmaps3c128x296(); +#endif +#ifdef _GxBitmaps152x296_H_ + drawBitmaps152x296(); +#endif +#ifdef _GxBitmaps3c176x264_H_ + drawBitmaps3c176x264(); +#endif +#ifdef _GxBitmaps240x416_H_ + drawBitmaps240x416(); +#endif +#ifdef _GxBitmaps3c400x300_H_ + drawBitmaps3c400x300(); +#endif +#ifdef _GxBitmaps3c800x480_H_ + drawBitmaps3c800x480(); +#endif + // show these after the specific bitmaps +#ifdef _GxBitmaps200x200_H_ + drawBitmaps200x200(); +#endif + // 3-color +#ifdef _GxBitmaps3c200x200_H_ + drawBitmaps3c200x200(); +#endif +} + +#ifdef _GxBitmaps200x200_H_ +void BitmapDisplay::drawBitmaps200x200() +{ +#if defined(ARDUINO_AVR_PRO) + const unsigned char* bitmaps[] = + { + logo200x200 + }; +#elif defined(__AVR) + const unsigned char* bitmaps[] = + { + logo200x200, first200x200 + }; +#elif defined(_BOARD_GENERIC_STM32F103C_H_) + const unsigned char* bitmaps[] = + { + logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200 //, sixth200x200, senventh200x200, eighth200x200 + }; +#else + const unsigned char* bitmaps[] = + { + logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEP015OC1) + { + bool m = display.mirror(true); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + display.mirror(m); + } + //else + { + bool mirror_y = (display.epd2.panel != GxEPD2::GDE0213B1); + display.clearScreen(); // use default for white + int16_t x = (int16_t(display.epd2.WIDTH) - 200) / 2; + int16_t y = (int16_t(display.epd2.HEIGHT) - 200) / 2; + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.drawImage(bitmaps[i], x, y, 200, 200, false, mirror_y, true); + delay(2000); + } + } + bool mirror_y = (display.epd2.panel != GxEPD2::GDE0213B1); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + int16_t x = -60; + int16_t y = -60; + for (uint16_t j = 0; j < 10; j++) + { + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmaps[i], x, y, 200, 200, false, mirror_y, true); + display.refresh(true); + if (display.epd2.hasFastPartialUpdate) + { + // for differential update: set previous buffer equal to current buffer in controller + display.epd2.writeScreenBufferAgain(); // use default for white + display.epd2.writeImageAgain(bitmaps[i], x, y, 200, 200, false, mirror_y, true); + } + delay(2000); + x += 40; + y += 40; + if ((x >= int16_t(display.epd2.WIDTH)) || (y >= int16_t(display.epd2.HEIGHT))) break; + } + if (!display.epd2.hasFastPartialUpdate) break; // comment out for full show + break; // comment out for full show + } + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmaps[0], int16_t(0), 0, 200, 200, false, mirror_y, true); + display.writeImage(bitmaps[0], int16_t(int16_t(display.epd2.WIDTH) - 200), int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, mirror_y, true); + display.refresh(true); + delay(2000); +} +#endif + +#ifdef _GxBitmaps104x212_H_ +void BitmapDisplay::drawBitmaps104x212() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + WS_Bitmap104x212, Bitmap104x212_1, Bitmap104x212_2, Bitmap104x212_3 + }; +#else + const unsigned char* bitmaps[] = + { + WS_Bitmap104x212, Bitmap104x212_1, Bitmap104x212_2, Bitmap104x212_3 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW0213I5F) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps128x250_H_ +void BitmapDisplay::drawBitmaps128x250() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap128x250_1, logo128x250, first128x250, second128x250, third128x250 + }; +#else + const unsigned char* bitmaps[] = + { + Bitmap128x250_1, logo128x250, first128x250, second128x250, third128x250 + }; +#endif + if ((display.epd2.panel == GxEPD2::GDE0213B1) || (display.epd2.panel == GxEPD2::GDEH0213B72)) + { + bool m = display.mirror(true); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + display.mirror(m); + } +} +#endif + +#ifdef _GxBitmaps128x296_H_ +void BitmapDisplay::drawBitmaps128x296() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap128x296_1, logo128x296, first128x296, second128x296, third128x296 + }; +#else + const unsigned char* bitmaps[] = + { + Bitmap128x296_1, logo128x296 //, first128x296, second128x296, third128x296 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEH029A1) + { + bool m = display.mirror(true); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + display.mirror(m); + } +} +#endif + +#ifdef _GxBitmaps152x296_H_ +void BitmapDisplay::drawBitmaps152x296() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap152x296_1, Bitmap152x296_2, Bitmap152x296_3 + }; +#else + const unsigned char* bitmaps[] = + { + Bitmap152x296_1, Bitmap152x296_2, Bitmap152x296_3 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW026T0) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps176x264_H_ +void BitmapDisplay::drawBitmaps176x264() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap176x264_1, Bitmap176x264_2, Bitmap176x264_3, Bitmap176x264_4, Bitmap176x264_5 + }; +#else + const unsigned char* bitmaps[] = + { + Bitmap176x264_1, Bitmap176x264_2 //, Bitmap176x264_3, Bitmap176x264_4, Bitmap176x264_5 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW027W3) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps240x416_H_ +void BitmapDisplay::drawBitmaps240x416() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap240x416_1, Bitmap240x416_2, Bitmap240x416_3 + }; +#else + const unsigned char* bitmaps[] = + { + Bitmap240x460_1, Bitmap240x460_2, Bitmap240x460_3 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW0371W7) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps400x300_H_ +void BitmapDisplay::drawBitmaps400x300() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap400x300_1, Bitmap400x300_2 + }; +#else + const unsigned char* bitmaps[] = {}; // not enough code space +#endif + if (display.epd2.panel == GxEPD2::GDEW042T2) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps640x384_H_ +void BitmapDisplay::drawBitmaps640x384() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap640x384_1, Bitmap640x384_2 + }; +#else + const unsigned char* bitmaps[] = {}; // not enough code space +#endif + if ((display.epd2.panel == GxEPD2::GDEW075T8) || (display.epd2.panel == GxEPD2::GDEW075Z09)) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps800x480_H_ +void BitmapDisplay::drawBitmaps800x480() +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap800x480_1, Bitmap800x480_2, Bitmap800x480_3, Bitmap800x480_4 + }; +#else + const unsigned char* bitmaps[] = {}; // not enough code space +#endif + if ((display.epd2.panel == GxEPD2::GDEW075T7) || (display.epd2.panel == GxEPD2::GDEW075Z08)) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + //display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + if (display.epd2.panel == GxEPD2::GDEW075T7) + { + // avoid ghosting caused by OTP waveform + display.clearScreen(); + display.refresh(false); // full update + } + } +} +#endif + +#ifdef _WS_Bitmaps800x600_H_ +void BitmapDisplay::drawBitmaps800x600() +{ +#if defined(ESP8266) || defined(ESP32) + if (display.epd2.panel == GxEPD2::ED060SCT) + { + // Serial.print("sizeof(WS_zoo_800x600) is "); Serial.println(sizeof(WS_zoo_800x600)); + display.drawNative(WS_zoo_800x600, 0, 0, 0, 800, 600, false, false, true); + delay(2000); + // Serial.print("sizeof(WS_pic_1200x825) is "); Serial.println(sizeof(WS_pic_1200x825)); + // display.drawNative((const uint8_t*)WS_pic_1200x825, 0, 0, 0, 1200, 825, false, false, true); + // delay(2000); + // Serial.print("sizeof(WS_acaa_1024x731) is "); Serial.println(sizeof(WS_acaa_1024x731)); + // display.drawNative(WS_acaa_1024x731, 0, 0, 0, 1024, 731, false, false, true); + // delay(2000); + } +#endif +} +#endif + +struct bitmap_pair +{ + const unsigned char* black; + const unsigned char* red; +}; + +#ifdef _GxBitmaps3c200x200_H_ +void BitmapDisplay::drawBitmaps3c200x200() +{ + bitmap_pair bitmap_pairs[] = + { + //{Bitmap3c200x200_black, Bitmap3c200x200_red}, + {WS_Bitmap3c200x200_black, WS_Bitmap3c200x200_red} + }; + if (display.epd2.panel == GxEPD2::GDEW0154Z04) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + // Bitmap3c200x200_black has 2 bits per pixel + // taken from Adafruit_GFX.cpp, modified + int16_t byteWidth = (display.epd2.WIDTH + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + for (int16_t j = 0; j < display.epd2.HEIGHT; j++) + { + for (int16_t i = 0; i < display.epd2.WIDTH; i++) + { + if (i & 3) byte <<= 2; + else + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + byte = pgm_read_byte(&Bitmap3c200x200_black[j * byteWidth * 2 + i / 4]); +#else + byte = Bitmap3c200x200_black[j * byteWidth * 2 + i / 4]; +#endif + } + if (!(byte & 0x80)) + { + display.drawPixel(i, j, GxEPD_BLACK); + } + } + } + display.drawInvertedBitmap(0, 0, Bitmap3c200x200_red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } + if (display.epd2.hasColor) + { + display.clearScreen(); // use default for white + int16_t x = (int16_t(display.epd2.WIDTH) - 200) / 2; + int16_t y = (int16_t(display.epd2.HEIGHT) - 200) / 2; + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.drawImage(bitmap_pairs[i].black, bitmap_pairs[i].red, x, y, 200, 200, false, false, true); + delay(2000); + } + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + int16_t x = -60; + int16_t y = -60; + for (uint16_t j = 0; j < 10; j++) + { + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmap_pairs[i].black, bitmap_pairs[i].red, x, y, 200, 200, false, false, true); + display.refresh(); + delay(1000); + x += 40; + y += 40; + if ((x >= int16_t(display.epd2.WIDTH)) || (y >= int16_t(display.epd2.HEIGHT))) break; + } + } + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmap_pairs[0].black, bitmap_pairs[0].red, 0, 0, 200, 200, false, false, true); + display.writeImage(bitmap_pairs[0].black, bitmap_pairs[0].red, int16_t(display.epd2.WIDTH) - 200, int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, false, true); + display.refresh(); + delay(2000); + } +} +#endif + +#ifdef _GxBitmaps3c104x212_H_ +void BitmapDisplay::drawBitmaps3c104x212() +{ +#if !defined(__AVR) + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c104x212_1_black, Bitmap3c104x212_1_red}, + {Bitmap3c104x212_2_black, Bitmap3c104x212_2_red}, + {WS_Bitmap3c104x212_black, WS_Bitmap3c104x212_red} + }; +#else + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c104x212_1_black, Bitmap3c104x212_1_red}, + //{Bitmap3c104x212_2_black, Bitmap3c104x212_2_red}, + {WS_Bitmap3c104x212_black, WS_Bitmap3c104x212_red} + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW0213Z16) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + if (bitmap_pairs[i].red == WS_Bitmap3c104x212_red) + { + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + else display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps3c128x296_H_ +void BitmapDisplay::drawBitmaps3c128x296() +{ +#if !defined(__AVR) + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c128x296_1_black, Bitmap3c128x296_1_red}, + {Bitmap3c128x296_2_black, Bitmap3c128x296_2_red}, + {WS_Bitmap3c128x296_black, WS_Bitmap3c128x296_red} + }; +#else + bitmap_pair bitmap_pairs[] = + { + //{Bitmap3c128x296_1_black, Bitmap3c128x296_1_red}, + //{Bitmap3c128x296_2_black, Bitmap3c128x296_2_red}, + {WS_Bitmap3c128x296_black, WS_Bitmap3c128x296_red} + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW029Z10) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + if (bitmap_pairs[i].red == WS_Bitmap3c128x296_red) + { + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + else display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps3c176x264_H_ +void BitmapDisplay::drawBitmaps3c176x264() +{ + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c176x264_black, Bitmap3c176x264_red} + }; + if (display.epd2.panel == GxEPD2::GDEW027C44) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps3c400x300_H_ +void BitmapDisplay::drawBitmaps3c400x300() +{ +#if !defined(__AVR) + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c400x300_1_black, Bitmap3c400x300_1_red}, + {Bitmap3c400x300_2_black, Bitmap3c400x300_2_red}, + {WS_Bitmap3c400x300_black, WS_Bitmap3c400x300_red} + }; +#else + bitmap_pair bitmap_pairs[] = {}; // not enough code space +#endif + if (display.epd2.panel == GxEPD2::GDEW042Z15) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps3c800x480_H_ +void BitmapDisplay::drawBitmaps3c800x480() +{ +#if !defined(__AVR) + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c800x480_1_black, Bitmap3c800x480_1_red} + }; +#else + bitmap_pair bitmap_pairs[] = {}; // not enough code space +#endif + if (display.epd2.panel == GxEPD2::GDEW075Z08) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif diff --git a/examples/GxEPD2_GFX_Example/BitmapDisplay.h b/examples/GxEPD2_GFX_Example/BitmapDisplay.h new file mode 100644 index 0000000..904d69b --- /dev/null +++ b/examples/GxEPD2_GFX_Example/BitmapDisplay.h @@ -0,0 +1,48 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// 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 +// +// BitmapDisplay shows the use of the display instance reference as a class member + +#ifndef _BitmapDisplay_H_ +#define _BitmapDisplay_H_ + +#include "GxEPD2_GFX.h" + +class BitmapDisplay +{ + private: + GxEPD2_GFX& display; + public: + BitmapDisplay(GxEPD2_GFX& _display) : display(_display) {}; + void drawBitmaps(); + private: + void drawBitmaps200x200(); + void drawBitmaps104x212(); + void drawBitmaps128x250(); + void drawBitmaps128x296(); + void drawBitmaps152x296(); + void drawBitmaps176x264(); + void drawBitmaps240x416(); + void drawBitmaps400x300(); + void drawBitmaps640x384(); + void drawBitmaps800x480(); + void drawBitmaps800x600(); + void drawBitmaps3c200x200(); + void drawBitmaps3c104x212(); + void drawBitmaps3c128x296(); + void drawBitmaps3c176x264(); + void drawBitmaps3c400x300(); + void drawBitmaps3c800x480(); +}; + +#endif diff --git a/examples/GxEPD2_GFX_Example/GxEPD2_GFX_Example.ino b/examples/GxEPD2_GFX_Example/GxEPD2_GFX_Example.ino new file mode 100644 index 0000000..36f8d7c --- /dev/null +++ b/examples/GxEPD2_GFX_Example/GxEPD2_GFX_Example.ino @@ -0,0 +1,468 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// 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: +// Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0 +// Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0 + +// mapping suggestion from Waveshare SPI e-Paper to Wemos D1 mini +// BUSY -> D2, RST -> D4, DC -> D3, CS -> D8, CLK -> D5, DIN -> D7, GND -> GND, 3.3V -> 3.3V +// NOTE: connect 4.7k pull-down from D8 to GND if your board or shield has level converters +// NOTE for ESP8266: using SS (GPIO15) for CS may cause boot mode problems, use different pin in case, or 4k7 pull-down + +// mapping suggestion from Waveshare SPI e-Paper to generic ESP8266 +// BUSY -> GPIO4, RST -> GPIO2, DC -> GPIO0, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V +// NOTE: connect 4.7k pull-down from GPIO15 to GND if your board or shield has level converters +// NOTE for ESP8266: using SS (GPIO15) for CS may cause boot mode problems, use different pin in case, or 4k7 pull-down + +// mapping of Waveshare e-Paper ESP8266 Driver Board +// BUSY -> GPIO16, RST -> GPIO5, DC -> GPIO4, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V +// NOTE for ESP8266: using SS (GPIO15) for CS may cause boot mode problems, use different pin in case + +// 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 + +// new mapping suggestion for STM32F1, e.g. STM32F103C8T6 "BluePill" +// BUSY -> A1, RST -> A2, DC -> A3, CS-> A4, CLK -> A5, DIN -> A7 + +// mapping suggestion for AVR, UNO, NANO etc. +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 13, DIN -> 11 + +// mapping of Waveshare Universal e-Paper Raw Panel Driver Shield for Arduino / NUCLEO +// BUSY -> 7, RST -> 8, DC -> 9, CS-> 10, CLK -> 13, DIN -> 11 + +// mapping suggestion for Arduino MEGA +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 53, CLK -> 52, DIN -> 51 + +// 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 + +#include +#include +#include + +#include "BitmapDisplay.h" +#include "TextDisplay.h" + +#if defined (ESP8266) +// select one and adapt to your mapping, can use full buffer size (full HEIGHT) +//GxEPD2_BW display(GxEPD2_154(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_BW display(GxEPD2_213(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_BW display(GxEPD2_270(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_BW display(GxEPD2_371(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_BW display(GxEPD2_420(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +// can use only half buffer size +//GxEPD2_BW < GxEPD2_583, GxEPD2_583::HEIGHT / 2 > display(GxEPD2_583(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_BW < GxEPD2_750, GxEPD2_750::HEIGHT / 2 > display(GxEPD2_750(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_BW < GxEPD2_750_T7, GxEPD2_750_T7::HEIGHT / 2 > display(GxEPD2_750_T7(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); // GDEW075T7 800x480 +// 3-color e-papers +//GxEPD2_3C display(GxEPD2_154c(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +// can use only half buffer size +//GxEPD2_3C display(GxEPD2_420c(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +// can use only quarter buffer size +//GxEPD2_3C < GxEPD2_583c, GxEPD2_583c::HEIGHT / 4 > display(GxEPD2_583c(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); +//GxEPD2_3C < GxEPD2_750c_Z08, GxEPD2_750c_Z08::HEIGHT / 4 > display(GxEPD2_750c_Z08(/*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2, /*BUSY=D2*/ 4)); // GDEW075Z08 800x480 +// grey levels parallel IF e-papers on Waveshare e-Paper IT8951 Driver HAT +// HRDY -> 4, RST -> 2, CS -> SS(15), SCK -> SCK(14), MOSI -> MOSI(D7(13)), MISO -> MISO(D6(12)), GND -> GND, 5V -> 5V +// note: 5V supply needs to be exact and strong; 5V pin of USB powered Wemos D1 mini doesn't work! +//GxEPD2_BW display(GxEPD2_it60(/*CS=5*/ SS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 4)); + +// ***** for mapping of Waveshare e-Paper ESP8266 Driver Board ***** +// select one , can use full buffer size (full HEIGHT) +//GxEPD2_BW display(GxEPD2_154(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_BW display(GxEPD2_213(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_BW display(GxEPD2_270(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_BW display(GxEPD2_371(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_BW display(GxEPD2_420(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +// can use only half buffer size +//GxEPD2_BW < GxEPD2_583, GxEPD2_583::HEIGHT / 2 > display(GxEPD2_583(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_BW < GxEPD2_750, GxEPD2_750::HEIGHT / 2 > display(GxEPD2_750(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//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 +// 3-color e-papers +//GxEPD2_3C display(GxEPD2_154c(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +// can use only half buffer size +//GxEPD2_3C display(GxEPD2_420c(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +// can use only quarter buffer size +//GxEPD2_3C display(GxEPD2_583c(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=15*/ SS, /*DC=4*/ 4, /*RST=5*/ 5, /*BUSY=16*/ 16)); // GDEW075Z08 800x480 +#endif + +#if defined(ESP32) +// select one and adapt to your mapping, can use full buffer size (full HEIGHT) +//GxEPD2_BW display(GxEPD2_154(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_213(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_270(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_371(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_420(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_583(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_750(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW075T7 800x480 +// 3-color e-papers +//GxEPD2_3C display(GxEPD2_154c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_583c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW075Z08 800x480 +// grey levels parallel IF e-papers on Waveshare e-Paper IT8951 Driver HAT +// HRDY -> 4, RST -> 16, CS -> SS(5), SCK -> SCK(18), MOSI -> MOSI(23), MISO -> MISO(19), GND -> GND, 5V -> 5V +// note: 5V supply needs to be exact and strong; 5V over diode from USB (e.g. Wemos D1 mini) doesn't work! +//GxEPD2_BW display(GxEPD2_it60(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); +#endif + +#if defined(_BOARD_GENERIC_STM32F103C_H_) +#define MAX_DISPLAY_BUFFER_SIZE 15000ul // ~15k is a good compromise +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +// select one and adapt to your mapping +//GxEPD2_BW display(GxEPD2_154(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_213(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_270(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_371(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_420(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_583(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_750(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // GDEW075T7 800x480 +// 3-color e-papers +#define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +//GxEPD2_3C display(GxEPD2_154c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_3C display(GxEPD2_583c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1)); // GDEW075Z08 800x480 +#endif + +#if defined(__AVR) +#define MAX_DISPLAY_BUFFER_SIZE 800 // +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +// select one and adapt to your mapping +//GxEPD2_BW display(GxEPD2_154(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_213(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_270(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_371(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_420(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_583(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_750(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW075T7 800x480 +// 3-color e-papers +#define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +//GxEPD2_3C display(GxEPD2_154c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_583c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW075Z08 800x480 + +// ***** for mapping of Waveshare Universal e-Paper Raw Panel Driver Shield for Arduino / NUCLEO ***** +// the RST line is not connected through level converter, but has a pull up resistor and a pull down diode to the Arduino pin; this is safe for 5V Arduino +// NOTE: the 11-pinholes for pin connectors are not through level converter, and the VCC pin is ~4.2V, only FCP connector pins are through level converter +// NOTE: the VCC pin on the 11-pinholes for pin connectors shouldn't be used, it seems to get back-fed from Arduino data pins through protection diodes of the level converter +// NOTE: the VCC pin should be fed from Arduino 5V pin for use on any 5V Arduino (did they forget to add this connection or add a jumper?) +// select one and adapt to your mapping +//GxEPD2_BW display(GxEPD2_154(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_213(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_270(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_371(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_420(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_583(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_750(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); // GDEW075T7 800x480 +// 3-color e-papers +#define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +//GxEPD2_3C display(GxEPD2_154c(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_583c(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=10*/ SS, /*DC=*/ 9, /*RST=*/ 8, /*BUSY=*/ 7)); // GDEW075Z08 800x480 +#endif + +#include "GxEPD2_boards_added.h" +//#include "GxEPD2_more_boards_added.h" // private + +BitmapDisplay bitmaps(display); + +void setup() +{ + Serial.begin(115200); + Serial.println(); + Serial.println("setup"); + delay(100); + display.init(115200); + // 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); + } +} diff --git a/examples/GxEPD2_GFX_Example/GxEPD2_boards_added.h b/examples/GxEPD2_GFX_Example/GxEPD2_boards_added.h new file mode 100644 index 0000000..357ac8c --- /dev/null +++ b/examples/GxEPD2_GFX_Example/GxEPD2_boards_added.h @@ -0,0 +1,153 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// Author: Jean-Marc Zingg +// +// Version: see library.properties +// +// Library: https://github.com/ZinggJM/GxEPD2 + +#ifndef _GxEPD2_boards_added_H_ +#define _GxEPD2_boards_added_H_ + +// Arduino DUE + +// mapping suggestion for Arduino DUE +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 77, CLK -> 76, DIN -> 75 +// SPI pins are on 6 pin 2x3 SPI header + +#if defined(ARDUINO_ARCH_SAM) +#define MAX_DISPLAY_BUFFER_SIZE 15000ul // ~15k is a good compromise +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +// select one and adapt to your mapping +//GxEPD2_BW display(GxEPD2_154(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_213(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_270(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_371(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_420(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_583(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_750(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW075T7 800x480 +// 3-color e-papers +#define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +//GxEPD2_3C display(GxEPD2_154c(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_583c(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=77*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // GDEW075Z08 800x480 +#endif + +// Arduino MKR1000 or MKRZERO + +// mapping suggestion for Arduino MKR1000 or MKRZERO +// note: can't use SS on MKR1000: is defined as 24, should be 4 +// BUSY -> 5, RST -> 6, DC -> 7, CS-> 4, CLK -> 9, DIN -> 8 + +#if defined(ARDUINO_ARCH_SAMD) +#define MAX_DISPLAY_BUFFER_SIZE 15000ul // ~15k is a good compromise +#define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPLAY_BUFFER_SIZE / (EPD::WIDTH / 8)) +// select one and adapt to your mapping +//GxEPD2_BW display(GxEPD2_154(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_213(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_270(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_371(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_420(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_583(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_750(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); // GDEW075T7 800x480 +// 3-color e-papers +#define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8)) +//GxEPD2_3C display(GxEPD2_154c(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_3C display(GxEPD2_583c(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=4*/ 4, /*DC=*/ 7, /*RST=*/ 6, /*BUSY=*/ 5)); // GDEW075Z08 800x480 +#endif + +// mapping suggestion for ESP32, e.g. LOLIN32 D32 PRO +// BUSY -> 15, RST -> 2, DC -> 0, CS -> 5, CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V +// note: use explicit value for CS, as SS is re-defined to TF_CS(4) in pins_arduino.h for Board: "LOLIN D32 PRO" + +#if defined(ESP32) && defined(ARDUINO_LOLIN_D32_PRO) +// select one and adapt to your mapping, can use full buffer size (full HEIGHT) +//GxEPD2_BW display(GxEPD2_154(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_BW display(GxEPD2_213(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_BW display(GxEPD2_270(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_BW display(GxEPD2_371(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_BW display(GxEPD2_420(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_BW display(GxEPD2_750(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // GDEW075T7 800x480 +// 3-color e-papers +//GxEPD2_3C display(GxEPD2_154c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // GDEW075Z08 800x480 +// grey levels parallel IF e-papers on Waveshare e-Paper IT8951 Driver HAT +// HRDY -> 4, RST -> 16, CS -> 5, SCK -> SCK(18), MOSI -> MOSI(23), MISO -> MISO(19), GND -> GND, 5V -> 5V +// note: 5V supply needs to be exact and strong; 5V over diode from USB (e.g. Wemos D1 mini) doesn't work! +//GxEPD2_BW display(GxEPD2_it60(/*CS=5*/ 5, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); +#endif + +// mapping suggestion for ESP32, e.g. TTGO T8 ESP32-WROVER +// BUSY -> 4, RST -> 0, DC -> 2, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V +// for use with Board: "ESP32 Dev Module": + +#if defined(ESP32) && defined(ARDUINO_ESP32_DEV) +// select one and adapt to your mapping, can use full buffer size (full HEIGHT) +//GxEPD2_BW display(GxEPD2_154(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_213(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // GDE0213B1, phased out +//GxEPD2_BW display(GxEPD2_213_B72(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // GDEH0213B72 +//GxEPD2_BW display(GxEPD2_213_B73(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // GDEH0213B73 +//GxEPD2_BW display(GxEPD2_213_flex(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // GDEW0213I5F +//GxEPD2_BW display(GxEPD2_290(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_290_T5(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // GDEW029T5 +//GxEPD2_BW display(GxEPD2_260(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_270(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_371(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_420(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_750(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_BW display(GxEPD2_750_T7(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // GDEW075T7 800x480 +// 3-color e-papers +//GxEPD2_3C display(GxEPD2_154c(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_750c(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +//GxEPD2_3C display(GxEPD2_750c_Z08(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // GDEW075Z08 800x480 +// grey levels parallel IF e-papers on Waveshare e-Paper IT8951 Driver HAT +// HRDY -> 4, RST -> 16, CS -> SS(5), SCK -> SCK(18), MOSI -> MOSI(23), MISO -> MISO(19), GND -> GND, 5V -> 5V +// note: 5V supply needs to be exact and strong; 5V over diode from USB (e.g. Wemos D1 mini) doesn't work! +//GxEPD2_BW display(GxEPD2_it60(/*CS=5*/ 5, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); +#endif + +#endif diff --git a/examples/GxEPD2_GFX_Example/TextDisplay.cpp b/examples/GxEPD2_GFX_Example/TextDisplay.cpp new file mode 100644 index 0000000..cadfac1 --- /dev/null +++ b/examples/GxEPD2_GFX_Example/TextDisplay.cpp @@ -0,0 +1,302 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// 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 +// +// TextDisplay shows the use of the display instance reference as a function parameter + +// 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() + +#include "TextDisplay.h" +#include + +const char HelloWorld[] = "Hello World!"; +const char HelloArduino[] = "Hello Arduino!"; +const char HelloEpaper[] = "Hello E-Paper!"; + +void helloWorld(GxEPD2_GFX& display) +{ + //Serial.println("helloWorld"); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_BLACK); + int16_t tbx, tby; uint16_t tbw, tbh; + display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + // center bounding box by transposition of origin: + 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(HelloWorld); + } + while (display.nextPage()); + //Serial.println("helloWorld done"); +} + +void helloWorldForDummies(GxEPD2_GFX& display) +{ + //Serial.println("helloWorld"); + const char text[] = "Hello World!"; + // most e-papers have width < height (portrait) as native orientation, especially the small ones + // in GxEPD2 rotation 0 is used for native orientation (most TFT libraries use 0 fix for portrait orientation) + // set rotation to 1 (rotate right 90 degrees) to have enough space on small displays (landscape) + display.setRotation(1); + // select a suitable font in Adafruit_GFX + display.setFont(&FreeMonoBold9pt7b); + // on e-papers black on white is more pleasant to read + display.setTextColor(GxEPD_BLACK); + // Adafruit_GFX has a handy method getTextBounds() to determine the boundary box for a text for the actual font + int16_t tbx, tby; uint16_t tbw, tbh; // boundary box window + display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); // it works for origin 0, 0, fortunately (negative tby!) + // center bounding box by transposition of origin: + uint16_t x = ((display.width() - tbw) / 2) - tbx; + uint16_t y = ((display.height() - tbh) / 2) - tby; + // full window mode is the initial mode, set it anyway + display.setFullWindow(); + // here we use paged drawing, even if the processor has enough RAM for full buffer + // so this can be used with any supported processor board. + // the cost in code overhead and execution time penalty is marginal + // tell the graphics class to use paged drawing mode + display.firstPage(); + do + { + // this part of code is executed multiple times, as many as needed, + // in case of full buffer it is executed once + // IMPORTANT: each iteration needs to draw the same, to avoid strange effects + // use a copy of values that might change, don't read e.g. from analog or pins in the loop! + display.fillScreen(GxEPD_WHITE); // set the background to white (fill the buffer with value for white) + display.setCursor(x, y); // set the postition to start printing text + display.print(text); // print some text + // end of part executed multiple times + } + // tell the graphics class to transfer the buffer content (page) to the controller buffer + // the graphics class will command the controller to refresh to the screen when the last page has been transferred + // returns true if more pages need be drawn and transferred + // returns false if the last page has been transferred and the screen refreshed for panels without fast partial update + // returns false for panels with fast partial update when the controller buffer has been written once more, to make the differential buffers equal + // (for full buffered with fast partial update the (full) buffer is just transferred again, and false returned) + while (display.nextPage()); + //Serial.println("helloWorld done"); +} + +void helloFullScreenPartialMode(GxEPD2_GFX& display) +{ + //Serial.println("helloFullScreenPartialMode"); + const char fullscreen[] = "full screen update"; + const char fpm[] = "fast partial mode"; + const char spm[] = "slow partial mode"; + const char npm[] = "no partial mode"; + display.setPartialWindow(0, 0, display.width(), display.height()); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_BLACK); + const char* updatemode; + if (display.epd2.hasFastPartialUpdate) + { + updatemode = fpm; + } + else if (display.epd2.hasPartialUpdate) + { + updatemode = spm; + } + else + { + updatemode = npm; + } + // do this outside of the loop + int16_t tbx, tby; uint16_t tbw, tbh; + // center update text + display.getTextBounds(fullscreen, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t utx = ((display.width() - tbw) / 2) - tbx; + uint16_t uty = ((display.height() / 4) - tbh / 2) - tby; + // center update mode + display.getTextBounds(updatemode, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t umx = ((display.width() - tbw) / 2) - tbx; + uint16_t umy = ((display.height() * 3 / 4) - tbh / 2) - tby; + // center HelloWorld + display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t hwx = ((display.width() - tbw) / 2) - tbx; + uint16_t hwy = ((display.height() - tbh) / 2) - tby; + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(hwx, hwy); + display.print(HelloWorld); + display.setCursor(utx, uty); + display.print(fullscreen); + display.setCursor(umx, umy); + display.print(updatemode); + } + while (display.nextPage()); + //Serial.println("helloFullScreenPartialMode done"); +} + +void helloArduino(GxEPD2_GFX& display) +{ + //Serial.println("helloArduino"); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + int16_t tbx, tby; uint16_t tbw, tbh; + // align with centered HelloWorld + display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((display.width() - tbw) / 2) - tbx; + // height might be different + display.getTextBounds(HelloArduino, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t y = ((display.height() / 4) - tbh / 2) - tby; // y is base line! + // make the window big enough to cover (overwrite) descenders of previous text + uint16_t wh = FreeMonoBold9pt7b.yAdvance; + uint16_t wy = (display.height() / 4) - wh / 2; + display.setPartialWindow(0, wy, display.width(), wh); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + //display.drawRect(x, y - tbh, tbw, tbh, GxEPD_BLACK); + display.setCursor(x, y); + display.print(HelloArduino); + } + while (display.nextPage()); + delay(1000); + //Serial.println("helloArduino done"); +} + +void helloEpaper(GxEPD2_GFX& display) +{ + //Serial.println("helloEpaper"); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + int16_t tbx, tby; uint16_t tbw, tbh; + // align with centered HelloWorld + display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((display.width() - tbw) / 2) - tbx; + // height might be different + display.getTextBounds(HelloEpaper, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t y = (display.height() * 3 / 4) + tbh / 2; // y is base line! + // make the window big enough to cover (overwrite) descenders of previous text + uint16_t wh = FreeMonoBold9pt7b.yAdvance; + uint16_t wy = (display.height() * 3 / 4) - wh / 2; + display.setPartialWindow(0, wy, display.width(), wh); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.print(HelloEpaper); + } + while (display.nextPage()); + //Serial.println("helloEpaper done"); +} + +#if defined(ESP8266) || defined(ESP32) +#include +#define PrintString StreamString +#else +class PrintString : public Print, public String +{ + public: + size_t write(uint8_t data) override + { + return concat(char(data)); + }; +}; +#endif + +void helloValue(GxEPD2_GFX& display, double v, int digits) +{ + //Serial.println("helloValue"); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + PrintString valueString; + valueString.print(v, digits); + int16_t tbx, tby; uint16_t tbw, tbh; + display.getTextBounds(valueString, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((display.width() - tbw) / 2) - tbx; + uint16_t y = (display.height() * 3 / 4) + tbh / 2; // y is base line! + // show what happens, if we use the bounding box for partial window + uint16_t wx = (display.width() - tbw) / 2; + uint16_t wy = (display.height() * 3 / 4) - tbh / 2; + display.setPartialWindow(wx, wy, tbw, tbh); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.print(valueString); + } + while (display.nextPage()); + delay(2000); + // make the partial window big enough to cover the previous text + uint16_t ww = tbw; // remember window width + display.getTextBounds(HelloEpaper, 0, 0, &tbx, &tby, &tbw, &tbh); + // adjust, because HelloEpaper was aligned, not centered (could calculate this to be precise) + ww = max(ww, uint16_t(tbw + 12)); // 12 seems ok + wx = (display.width() - tbw) / 2; + // make the window big enough to cover (overwrite) descenders of previous text + uint16_t wh = FreeMonoBold9pt7b.yAdvance; + wy = (display.height() * 3 / 4) - wh / 2; + display.setPartialWindow(wx, wy, ww, wh); + // alternately use the whole width for partial window + //display.setPartialWindow(0, wy, display.width(), wh); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.print(valueString); + } + while (display.nextPage()); + //Serial.println("helloValue done"); +} + +void showFont(GxEPD2_GFX& display, const char name[], const GFXfont* f) +{ + display.setFullWindow(); + display.setRotation(0); + display.setTextColor(GxEPD_BLACK); + display.firstPage(); + do + { + drawFont(display, name, f); + } + while (display.nextPage()); +} + +void drawFont(GxEPD2_GFX& display, const char name[], const GFXfont* f) +{ + //display.setRotation(0); + 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 (display.epd2.hasColor) + { + display.setTextColor(GxEPD_RED); + } + display.println("`abcdefghijklmno"); + display.println("pqrstuvwxyz{|}~ "); +} diff --git a/examples/GxEPD2_GFX_Example/TextDisplay.h b/examples/GxEPD2_GFX_Example/TextDisplay.h new file mode 100644 index 0000000..3dc57bf --- /dev/null +++ b/examples/GxEPD2_GFX_Example/TextDisplay.h @@ -0,0 +1,30 @@ +// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// 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 +// +// TextDisplay shows the use of the display instance reference as a function parameter + +#ifndef _TextDisplay_H_ +#define _TextDisplay_H_ + +#include "GxEPD2_GFX.h" + +void helloWorld(GxEPD2_GFX& display); +void helloWorldForDummies(GxEPD2_GFX& display); +void helloFullScreenPartialMode(GxEPD2_GFX& display); +void helloArduino(GxEPD2_GFX& display); +void helloEpaper(GxEPD2_GFX& display); +void helloValue(GxEPD2_GFX& display, double v, int digits); +void showFont(GxEPD2_GFX& display, const char name[], const GFXfont* f); +void drawFont(GxEPD2_GFX& display, const char name[], const GFXfont* f); + +#endif diff --git a/examples/GxEPD2_MultiDisplayExample/GxEPD2_MultiDisplayExample.ino b/examples/GxEPD2_MultiDisplayExample/GxEPD2_MultiDisplayExample.ino index 2daa50c..c24d1a5 100644 --- a/examples/GxEPD2_MultiDisplayExample/GxEPD2_MultiDisplayExample.ino +++ b/examples/GxEPD2_MultiDisplayExample/GxEPD2_MultiDisplayExample.ino @@ -32,6 +32,10 @@ // mapping suggestion for AVR, UNO, NANO etc. // BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 13, DIN -> 11 +// base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter +// enable GxEPD2_GFX base class +#define ENABLE_GxEPD2_GFX 1 + #include #include #include @@ -111,30 +115,6 @@ GxEPD2_3C display4(GxEPD2_750c(/*CS=*/ CS_4, / #include "bitmaps/Bitmaps3c176x264.h" // 2.7" b/w/r #include "bitmaps/Bitmaps3c400x300.h" // 4.2" b/w/r -// Ok, I will learn how to use nested templates in my next life, maybe -// Ok, this works at least, maybe I learned enough for a start - -// the compiler needs separate declarations for template functions - -template class T> -void helloWorld(T& display); -template class T> -void helloFullScreenPartialMode(T& display); -template class T> -void helloArduino(T& display); -template class T> -void helloEpaper(T& display); -template class T> -void showBox(T& display, uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial); -template class T> -void drawCornerTest(T& display); -template class T> -void showFont(T& display, const char name[], const GFXfont* f); -template class T> -void drawBitmaps(T& display); -template class T> -void showPartialUpdate(T& display); - void setup() { Serial.begin(115200); @@ -218,8 +198,8 @@ void loop() { } -template class T> -void helloWorld(T& display) + +void helloWorld(GxEPD2_GFX& display) { //Serial.println("helloWorld"); display.setRotation(1); @@ -239,8 +219,8 @@ void helloWorld(T& display) //Serial.println("helloWorld done"); } -template class T> -void helloFullScreenPartialMode(T& display) + +void helloFullScreenPartialMode(GxEPD2_GFX& display) { //Serial.println("helloFullScreenPartialMode"); display.setPartialWindow(0, 0, display.width(), display.height()); @@ -278,8 +258,8 @@ void helloFullScreenPartialMode(T& display) //Serial.println("helloFullScreenPartialMode done"); } -template class T> -void helloArduino(T& display) + +void helloArduino(GxEPD2_GFX& display) { //Serial.println("helloArduino"); display.setRotation(1); @@ -300,8 +280,8 @@ void helloArduino(T& display) //Serial.println("helloArduino done"); } -template class T> -void helloEpaper(T& display) + +void helloEpaper(GxEPD2_GFX& display) { //Serial.println("helloEpaper"); display.setRotation(1); @@ -321,8 +301,8 @@ void helloEpaper(T& display) //Serial.println("helloEpaper done"); } -template class T> -void showBox(T& display, uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial) + +void showBox(GxEPD2_GFX& display, uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial) { //Serial.println("showBox"); display.setRotation(1); @@ -344,8 +324,8 @@ void showBox(T& display, uint16_t x, uint16_t y, uint1 //Serial.println("showBox done"); } -template class T> -void drawCornerTest(T& display) + +void drawCornerTest(GxEPD2_GFX& display) { display.setFullWindow(); display.setFont(&FreeMonoBold9pt7b); @@ -369,8 +349,8 @@ void drawCornerTest(T& display) } } -template class T> -void showFont(T& display, const char name[], const GFXfont* f) + +void showFont(GxEPD2_GFX& display, const char name[], const GFXfont* f) { display.setFullWindow(); display.setRotation(0); @@ -383,11 +363,11 @@ void showFont(T& display, const char name[], const GFX while (display.nextPage()); } -template class T> -void drawFont(T& display, const char name[], const GFXfont* f); -template class T> -void drawFont(T& display, const char name[], const GFXfont* f) +//void drawFont(GxEPD2_GFX& display, const char name[], const GFXfont* f); + + +void drawFont(GxEPD2_GFX& display, const char name[], const GFXfont* f) { //display.setRotation(0); display.fillScreen(GxEPD_WHITE); @@ -408,8 +388,8 @@ void drawFont(T& display, const char name[], const GFX display.println("pqrstuvwxyz{|}~ "); } -template class T> -void showPartialUpdate(T& display) + +void showPartialUpdate(GxEPD2_GFX& display) { // some useful background helloWorld(display); @@ -475,10 +455,10 @@ void showPartialUpdate(T& display) #ifdef _GxBitmaps200x200_H_ -template class T> -void drawBitmaps200x200(T& display); -template class T> -void drawBitmaps200x200(T& display) + +void drawBitmaps200x200(GxEPD2_GFX& display); + +void drawBitmaps200x200(GxEPD2_GFX& display) { #if defined(__AVR) const unsigned char* bitmaps[] = @@ -551,10 +531,10 @@ void drawBitmaps200x200(T& display) #endif #ifdef _GxBitmaps128x250_H_ -template class T> -void drawBitmaps128x250(T& display); -template class T> -void drawBitmaps128x250(T& display) + +void drawBitmaps128x250(GxEPD2_GFX& display); + +void drawBitmaps128x250(GxEPD2_GFX& display) { #if !defined(__AVR) const unsigned char* bitmaps[] = @@ -587,10 +567,10 @@ void drawBitmaps128x250(T& display) #endif #ifdef _GxBitmaps128x296_H_ -template class T> -void drawBitmaps128x296(T& display); -template class T> -void drawBitmaps128x296(T& display) + +void drawBitmaps128x296(GxEPD2_GFX& display); + +void drawBitmaps128x296(GxEPD2_GFX& display) { #if !defined(__AVR) const unsigned char* bitmaps[] = @@ -623,10 +603,10 @@ void drawBitmaps128x296(T& display) #endif #ifdef _GxBitmaps176x264_H_ -template class T> -void drawBitmaps176x264(T& display); -template class T> -void drawBitmaps176x264(T& display) + +void drawBitmaps176x264(GxEPD2_GFX& display); + +void drawBitmaps176x264(GxEPD2_GFX& display) { const unsigned char* bitmaps[] = { @@ -650,10 +630,10 @@ void drawBitmaps176x264(T& display) #endif #ifdef _GxBitmaps400x300_H_ -template class T> -void drawBitmaps400x300(T& display); -template class T> -void drawBitmaps400x300(T& display) + +void drawBitmaps400x300(GxEPD2_GFX& display); + +void drawBitmaps400x300(GxEPD2_GFX& display) { #if !defined(__AVR) const unsigned char* bitmaps[] = @@ -681,10 +661,10 @@ void drawBitmaps400x300(T& display) #endif #ifdef _GxBitmaps640x384_H_ -template class T> -void drawBitmaps640x384(T& display); -template class T> -void drawBitmaps640x384(T& display) + +void drawBitmaps640x384(GxEPD2_GFX& display); + +void drawBitmaps640x384(GxEPD2_GFX& display) { #if !defined(__AVR) const unsigned char* bitmaps[] = @@ -718,10 +698,10 @@ struct bitmap_pair }; #ifdef _GxBitmaps3c200x200_H_ -template class T> -void drawBitmaps3c200x200(T& display); -template class T> -void drawBitmaps3c200x200(T& display) + +void drawBitmaps3c200x200(GxEPD2_GFX& display); + +void drawBitmaps3c200x200(GxEPD2_GFX& display) { bitmap_pair bitmap_pairs[] = { @@ -809,10 +789,10 @@ void drawBitmaps3c200x200(T& display) #endif #ifdef _GxBitmaps3c104x212_H_ -template class T> -void drawBitmaps3c104x212(T& display); -template class T> -void drawBitmaps3c104x212(T& display) + +void drawBitmaps3c104x212(GxEPD2_GFX& display); + +void drawBitmaps3c104x212(GxEPD2_GFX& display) { #if !defined(__AVR) bitmap_pair bitmap_pairs[] = @@ -852,10 +832,10 @@ void drawBitmaps3c104x212(T& display) #endif #ifdef _GxBitmaps3c128x296_H_ -template class T> -void drawBitmaps3c128x296(T& display); -template class T> -void drawBitmaps3c128x296(T& display) + +void drawBitmaps3c128x296(GxEPD2_GFX& display); + +void drawBitmaps3c128x296(GxEPD2_GFX& display) { #if !defined(__AVR) bitmap_pair bitmap_pairs[] = @@ -895,10 +875,10 @@ void drawBitmaps3c128x296(T& display) #endif #ifdef _GxBitmaps3c176x264_H_ -template class T> -void drawBitmaps3c176x264(T& display); -template class T> -void drawBitmaps3c176x264(T& display) + +void drawBitmaps3c176x264(GxEPD2_GFX& display); + +void drawBitmaps3c176x264(GxEPD2_GFX& display) { bitmap_pair bitmap_pairs[] = { @@ -923,10 +903,10 @@ void drawBitmaps3c176x264(T& display) #endif #ifdef _GxBitmaps3c400x300_H_ -template class T> -void drawBitmaps3c400x300(T& display); -template class T> -void drawBitmaps3c400x300(T& display) + +void drawBitmaps3c400x300(GxEPD2_GFX& display); + +void drawBitmaps3c400x300(GxEPD2_GFX& display) { #if !defined(__AVR) bitmap_pair bitmap_pairs[] = @@ -956,8 +936,8 @@ void drawBitmaps3c400x300(T& display) } #endif -template class T> -void drawBitmaps(T& display) + +void drawBitmaps(GxEPD2_GFX& display) { display.setFullWindow(); display.setRotation(0); @@ -998,5 +978,3 @@ void drawBitmaps(T& display) drawBitmaps3c200x200(display); #endif } - - diff --git a/extras/Particle/examples/GxEPD2_ParticleExample/project.properties b/extras/Particle/examples/GxEPD2_ParticleExample/project.properties index d23d9f3..0bd3f40 100644 --- a/extras/Particle/examples/GxEPD2_ParticleExample/project.properties +++ b/extras/Particle/examples/GxEPD2_ParticleExample/project.properties @@ -1,2 +1,2 @@ name=GxEPD2_ParticleExample -dependencies.GxEPD2=1.2.1 \ No newline at end of file +dependencies.GxEPD2=1.2.3 \ No newline at end of file diff --git a/extras/Particle/examples/GxEPD2_WiFi_ParticleExample/project.properties b/extras/Particle/examples/GxEPD2_WiFi_ParticleExample/project.properties index 5aa25c7..a7c6dc5 100644 --- a/extras/Particle/examples/GxEPD2_WiFi_ParticleExample/project.properties +++ b/extras/Particle/examples/GxEPD2_WiFi_ParticleExample/project.properties @@ -1,2 +1,2 @@ name=GxEPD2_WiFi_ParticleExample -dependencies.GxEPD2=1.2.1 \ No newline at end of file +dependencies.GxEPD2=1.2.3 \ No newline at end of file diff --git a/extras/examples/GxEPD2_T_MultiDisplayExample/GxEPD2_T_MultiDisplayExample.ino b/extras/examples/GxEPD2_T_MultiDisplayExample/GxEPD2_T_MultiDisplayExample.ino new file mode 100644 index 0000000..4cac5b0 --- /dev/null +++ b/extras/examples/GxEPD2_T_MultiDisplayExample/GxEPD2_T_MultiDisplayExample.ino @@ -0,0 +1,1003 @@ +// GxEPD2_T_MultiDisplayExample: Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. +// Requires HW SPI and Adafruit_GFX. Caution: these e-papers require 3.3V supply AND data lines! +// +// Display Library based on Demo Example from Good Display: http://www.good-display.com/download_list/downloadcategoryid=34&isMode=false.html +// +// Author: Jean-Marc Zingg +// +// Version: see library.properties +// +// Library: https://github.com/ZinggJM/GxEPD2 + +// 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 SPI 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 from Waveshare SPI e-Paper to generic ESP8266 +// BUSY -> GPIO4, RST -> GPIO2, DC -> GPIO0, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V + +// mapping of Waveshare e-Paper ESP8266 Driver Board +// BUSY -> GPIO16, RST -> GPIO5, DC -> GPIO4, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, 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 + +// new mapping suggestion for STM32F1, e.g. STM32F103C8T6 "BluePill" +// BUSY -> A1, RST -> A2, DC -> A3, CS-> A4, CLK -> A5, DIN -> A7 + +// mapping suggestion for AVR, UNO, NANO etc. +// BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 13, DIN -> 11 + +#include +#include +#include + +// create display class instances for each display, each instance with different CS line, each instance with RST disabled, +// (or use separate RST pins for each display), +// each instance with different BUSY line, or BUSY lines or-ed to one pin +// disable reset line to disable cross resets by multiple instances + +#if defined (ESP8266) +#define RST_PIN 0 // D3(0) +#define CS_1 SS // CS = D8(15) +#define CS_2 16 // CS = D0(16) +#define CS_3 5 // CS = D1(5) +// BUSY lines can be or-ed with diodes and pulldown register for displays with BUSY active HIGH +#define BUSY_H_x 4 // BUSY = D2(4) +// BUSY lines can be or-ed with diodes and pullup resistor for displays with BUSY active LOW +//#define BUSY_L_x 4 // BUSY = D2(4) +// select one and adapt to your mapping, can use full buffer size (full HEIGHT) +GxEPD2_BW display1(GxEPD2_154(/*CS=*/ CS_1, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_H_x)); +GxEPD2_BW display2(GxEPD2_213(/*CS=*/ CS_2, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_H_x)); +GxEPD2_BW display3(GxEPD2_290(/*CS=*/ CS_3, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_H_x)); +//GxEPD2_BW display(GxEPD2_270(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_BW display(GxEPD2_420(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +// can use only half buffer size +//GxEPD2_BW < GxEPD2_583, GxEPD2_583::HEIGHT / 2 > display(GxEPD2_583(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_BW < GxEPD2_750, GxEPD2_750::HEIGHT / 2 > display(GxEPD2_750(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +// 3-color e-papers +//GxEPD2_3C display(GxEPD2_154c(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +// can use only half buffer size +//GxEPD2_3C display(GxEPD2_420c(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +// can use only quarter buffer size +//GxEPD2_3C display(GxEPD2_583c(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display3(GxEPD2_750c(/*CS=*/ CS_x, /*DC=D3*/ 0, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +#endif + +#if defined(ESP32) +#define RST_PIN 16 +#define CS_1 SS // CS = 5(SS) +#define CS_2 0 // CS = 0 +#define CS_3 2 // CS = 2 +#define CS_4 13 // CS = 13 +// BUSY lines can be or-ed with diodes and pulldown register for displays with BUSY active HIGH +#define BUSY_H_x 4 // BUSY = 4 +// BUSY lines can be or-ed with diodes and pullup resistor for displays with BUSY active LOW +#define BUSY_L_x 15 // BUSY = 15 +// select one and adapt to your mapping, can use full buffer size (full HEIGHT) +GxEPD2_BW display1(GxEPD2_154(/*CS=*/ CS_1, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_H_x)); +GxEPD2_BW display2(GxEPD2_213(/*CS=*/ CS_2, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_H_x)); +GxEPD2_BW display3(GxEPD2_290(/*CS=*/ CS_3, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_H_x)); +//GxEPD2_BW display(GxEPD2_270(/*CS=*/ CS_x, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_BW display4(GxEPD2_420(/*CS=*/ CS_4, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_BW display(GxEPD2_750(/*CS=*/ CS_x, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +// 3-color e-papers +//GxEPD2_3C display(GxEPD2_154c(/*CS=*/ CS_x, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display(GxEPD2_213c(/*CS=*/ CS_x, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display(GxEPD2_290c(/*CS=*/ CS_x, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display(GxEPD2_270c(/*CS=*/ CS_x, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +//GxEPD2_3C display(GxEPD2_420c(/*CS=*/ CS_x, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +GxEPD2_3C display4(GxEPD2_750c(/*CS=*/ CS_4, /*DC=*/ 17, /*RST=*/ -1, /*BUSY=*/ BUSY_L_x)); +#endif + +// comment out unused bitmaps to reduce code space used +#include "bitmaps/Bitmaps200x200.h" // 1.54" b/w +#include "bitmaps/Bitmaps128x250.h" // 2.13" b/w +#include "bitmaps/Bitmaps128x296.h" // 2.9" b/w +#include "bitmaps/Bitmaps176x264.h" // 2.7" b/w +#include "bitmaps/Bitmaps400x300.h" // 4.2" b/w +#include "bitmaps/Bitmaps640x384.h" // 7.5" b/w +// 3-color +#include "bitmaps/Bitmaps3c200x200.h" // 1.54" b/w/r +#include "bitmaps/Bitmaps3c104x212.h" // 2.13" b/w/r +#include "bitmaps/Bitmaps3c128x296.h" // 2.9" b/w/r +#include "bitmaps/Bitmaps3c176x264.h" // 2.7" b/w/r +#include "bitmaps/Bitmaps3c400x300.h" // 4.2" b/w/r + +// This example uses template functions for use of display instance reference parameter. +// This makes it complicated, because of the GxEPD2_BW and GxEPD2_3C template classes. +// The example GxEPD2_MultiDisplayExample uses a common base class and is easier to use. + +// the compiler needs separate declarations for template functions + +template class GxGFX_Type> +void helloWorld(GxGFX_Type& display); +template class GxGFX_Type> +void helloFullScreenPartialMode(GxGFX_Type& display); +template class GxGFX_Type> +void helloArduino(GxGFX_Type& display); +template class GxGFX_Type> +void helloEpaper(GxGFX_Type& display); +template class GxGFX_Type> +void showBox(GxGFX_Type& display, uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial); +template class GxGFX_Type> +void drawCornerTest(GxGFX_Type& display); +template class GxGFX_Type> +void showFont(GxGFX_Type& display, const char name[], const GFXfont* f); +template class GxGFX_Type> +void drawBitmaps(GxGFX_Type& display); +template class GxGFX_Type> +void showPartialUpdate(GxGFX_Type& display); + +void setup() +{ + Serial.begin(115200); + Serial.println(); + Serial.println("setup"); + + // one common reset for all displays + digitalWrite(RST_PIN, HIGH); + pinMode(RST_PIN, OUTPUT); + delay(20); + digitalWrite(RST_PIN, LOW); + delay(20); + digitalWrite(RST_PIN, HIGH); + delay(200); + + display1.init(115200); // enable diagnostic output on Serial + display2.init(115200); // enable diagnostic output on Serial + display3.init(115200); // enable diagnostic output on Serial +#if defined(ESP32) + display4.init(115200); // enable diagnostic output on Serial +#endif + // first update should be full refresh + helloWorld(display1); + helloWorld(display2); + helloWorld(display3); +#if defined(ESP32) + helloWorld(display4); +#endif + delay(1000); + // partial refresh mode can be used to full screen, + // effective if display panel hasFastPartialUpdate + helloFullScreenPartialMode(display1); + helloFullScreenPartialMode(display2); + helloFullScreenPartialMode(display3); +#if defined(ESP32) + helloFullScreenPartialMode(display4); +#endif + delay(1000); + helloArduino(display1); + helloArduino(display2); + helloArduino(display3); +#if defined(ESP32) + helloArduino(display4); +#endif + delay(1000); + helloEpaper(display1); + helloEpaper(display2); + helloEpaper(display3); +#if defined(ESP32) + helloEpaper(display4); +#endif + delay(1000); + showFont(display1, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b); + showFont(display2, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b); + showFont(display3, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b); +#if defined(ESP32) + showFont(display4, "FreeMonoBold9pt7b", &FreeMonoBold9pt7b); +#endif + delay(1000); + drawBitmaps(display1); + drawBitmaps(display2); + drawBitmaps(display3); +#if defined(ESP32) + drawBitmaps(display4); +#endif +// if (display1.epd2.hasPartialUpdate) +// { +// showPartialUpdate(display1); +// delay(1000); +// } // else // on GDEW0154Z04 only full update available, doesn't look nice + //drawCornerTest(display1); + //showBox(display1, 16, 16, 48, 32, false); + //showBox(display1, 16, 56, 48, 32, true); + display1.powerOff(); + display2.powerOff(); + display3.powerOff(); + Serial.println("setup done"); +} + +void loop() +{ +} + +//template class GxGFX_Type> +//void helloWorld(GxGFX_Type& display) +template class GxGFX_Type> +void helloWorld(GxGFX_Type& display) +{ + //Serial.println("helloWorld"); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_BLACK); + uint16_t x = (display.width() - 160) / 2; + uint16_t y = display.height() / 2; + display.setFullWindow(); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.println("Hello World!"); + } + while (display.nextPage()); + //Serial.println("helloWorld done"); +} + +template class GxGFX_Type> +void helloFullScreenPartialMode(GxGFX_Type& display) +{ + //Serial.println("helloFullScreenPartialMode"); + display.setPartialWindow(0, 0, display.width(), display.height()); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(GxEPD_BLACK); + display.firstPage(); + do + { + uint16_t x = (display.width() - 160) / 2; + uint16_t y = display.height() / 2; + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.println("Hello World!"); + y = display.height() / 4; + display.setCursor(x, y); + display.println("full screen"); + y = display.height() * 3 / 4; + if (display.width() <= 200) x = 0; + display.setCursor(x, y); + if (display.epd2.hasFastPartialUpdate) + { + display.println("fast partial mode"); + } + else if (display.epd2.hasPartialUpdate) + { + display.println("slow partial mode"); + } + else + { + display.println("no partial mode"); + } + } + while (display.nextPage()); + //Serial.println("helloFullScreenPartialMode done"); +} + +template class GxGFX_Type> +void helloArduino(GxGFX_Type& display) +{ + //Serial.println("helloArduino"); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + uint16_t x = (display.width() - 160) / 2; + uint16_t y = display.height() / 4; + display.setPartialWindow(0, y - 14, display.width(), 20); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.println("Hello Arduino!"); + } + while (display.nextPage()); + delay(1000); + //Serial.println("helloArduino done"); +} + +template class GxGFX_Type> +void helloEpaper(GxGFX_Type& display) +{ + //Serial.println("helloEpaper"); + display.setRotation(1); + display.setFont(&FreeMonoBold9pt7b); + display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); + uint16_t x = (display.width() - 160) / 2; + uint16_t y = display.height() * 3 / 4; + display.setPartialWindow(0, y - 14, display.width(), 20); + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.setCursor(x, y); + display.println("Hello E-Paper!"); + } + while (display.nextPage()); + //Serial.println("helloEpaper done"); +} + +template class GxGFX_Type> +void showBox(GxGFX_Type& display, 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"); +} + +template class GxGFX_Type> +void drawCornerTest(GxGFX_Type& display) +{ + 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); + } +} + +template class GxGFX_Type> +void showFont(GxGFX_Type& display, const char name[], const GFXfont* f) +{ + display.setFullWindow(); + display.setRotation(0); + display.setTextColor(GxEPD_BLACK); + display.firstPage(); + do + { + drawFont(display, name, f); + } + while (display.nextPage()); +} + +template class GxGFX_Type> +void drawFont(GxGFX_Type& display, const char name[], const GFXfont* f); + +template class GxGFX_Type> +void drawFont(GxGFX_Type& display, const char name[], const GFXfont* f) +{ + //display.setRotation(0); + 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 (display.epd2.hasColor) + { + display.setTextColor(GxEPD_RED); + } + display.println("`abcdefghijklmno"); + display.println("pqrstuvwxyz{|}~ "); +} + +template class GxGFX_Type> +void showPartialUpdate(GxGFX_Type& display) +{ + // 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); + } +} + + +#ifdef _GxBitmaps200x200_H_ +template class GxGFX_Type> +void drawBitmaps200x200(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps200x200(GxGFX_Type& display) +{ +#if defined(__AVR) + const unsigned char* bitmaps[] = + { + logo200x200, first200x200 //, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200 + }; +#elif defined(_BOARD_GENERIC_STM32F103C_H_) + const unsigned char* bitmaps[] = + { + logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200 //, sixth200x200, senventh200x200, eighth200x200 + }; +#else + const unsigned char* bitmaps[] = + { + logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEP015OC1) + { + bool m = display.mirror(true); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + display.mirror(m); + } + //else + { + bool mirror_y = (display.epd2.panel != GxEPD2::GDE0213B1); + display.clearScreen(); // use default for white + int16_t x = (int16_t(display.epd2.WIDTH) - 200) / 2; + int16_t y = (int16_t(display.epd2.HEIGHT) - 200) / 2; + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.drawImage(bitmaps[i], x, y, 200, 200, false, mirror_y, true); + delay(2000); + } + } + bool mirror_y = (display.epd2.panel != GxEPD2::GDE0213B1); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + int16_t x = -60; + int16_t y = -60; + for (uint16_t j = 0; j < 10; j++) + { + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmaps[i], x, y, 200, 200, false, mirror_y, true); + display.refresh(true); + delay(2000); + x += 40; + y += 40; + if ((x >= int16_t(display.epd2.WIDTH)) || (y >= int16_t(display.epd2.HEIGHT))) break; + } + if (!display.epd2.hasFastPartialUpdate) break; // comment out for full show + break; // comment out for full show + } + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmaps[0], int16_t(0), 0, 200, 200, false, mirror_y, true); + display.writeImage(bitmaps[0], int16_t(int16_t(display.epd2.WIDTH) - 200), int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, mirror_y, true); + display.refresh(true); + delay(2000); +} +#endif + +#ifdef _GxBitmaps128x250_H_ +template class GxGFX_Type> +void drawBitmaps128x250(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps128x250(GxGFX_Type& display) +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap128x250_1, logo128x250, first128x250, second128x250, third128x250 + }; +#else + const unsigned char* bitmaps[] = + { + Bitmap128x250_1, logo128x250, first128x250, second128x250, third128x250 + }; +#endif + if (display.epd2.panel == GxEPD2::GDE0213B1) + { + bool m = display.mirror(true); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + display.mirror(m); + } +} +#endif + +#ifdef _GxBitmaps128x296_H_ +template class GxGFX_Type> +void drawBitmaps128x296(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps128x296(GxGFX_Type& display) +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap128x296_1, logo128x296, first128x296, second128x296, third128x296 + }; +#else + const unsigned char* bitmaps[] = + { + Bitmap128x296_1, logo128x296 //, first128x296, second128x296, third128x296 + }; +#endif + if (display.epd2.panel == GxEPD2::GDEH029A1) + { + bool m = display.mirror(true); + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + display.mirror(m); + } +} +#endif + +#ifdef _GxBitmaps176x264_H_ +template class GxGFX_Type> +void drawBitmaps176x264(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps176x264(GxGFX_Type& display) +{ + const unsigned char* bitmaps[] = + { + Bitmap176x264_1, Bitmap176x264_2 + }; + if (display.epd2.panel == GxEPD2::GDEW027W3) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps400x300_H_ +template class GxGFX_Type> +void drawBitmaps400x300(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps400x300(GxGFX_Type& display) +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap400x300_1, Bitmap400x300_2 + }; +#else + const unsigned char* bitmaps[] = {}; // not enough code space +#endif + if (display.epd2.panel == GxEPD2::GDEW042T2) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps640x384_H_ +template class GxGFX_Type> +void drawBitmaps640x384(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps640x384(GxGFX_Type& display) +{ +#if !defined(__AVR) + const unsigned char* bitmaps[] = + { + Bitmap640x384_1, Bitmap640x384_2 + }; +#else + const unsigned char* bitmaps[] = {}; // not enough code space +#endif + if (display.epd2.panel == GxEPD2::GDEW075T8) + { + for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +struct bitmap_pair +{ + const unsigned char* black; + const unsigned char* red; +}; + +#ifdef _GxBitmaps3c200x200_H_ +template class GxGFX_Type> +void drawBitmaps3c200x200(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps3c200x200(GxGFX_Type& display) +{ + bitmap_pair bitmap_pairs[] = + { + //{Bitmap3c200x200_black, Bitmap3c200x200_red}, + {WS_Bitmap3c200x200_black, WS_Bitmap3c200x200_red} + }; + if (display.epd2.panel == GxEPD2::GDEW0154Z04) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + // Bitmap3c200x200_black has 2 bits per pixel + // taken from Adafruit_GFX.cpp, modified + int16_t byteWidth = (display.epd2.WIDTH + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + for (int16_t j = 0; j < display.epd2.HEIGHT; j++) + { + for (int16_t i = 0; i < display.epd2.WIDTH; i++) + { + if (i & 3) byte <<= 2; + else + { +#if defined(__AVR) || defined(ESP8266) || defined(ESP32) + byte = pgm_read_byte(&Bitmap3c200x200_black[j * byteWidth * 2 + i / 4]); +#else + byte = Bitmap3c200x200_black[j * byteWidth * 2 + i / 4]; +#endif + } + if (!(byte & 0x80)) + { + display.drawPixel(i, j, GxEPD_BLACK); + } + } + } + display.drawInvertedBitmap(0, 0, Bitmap3c200x200_red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } + if (display.epd2.hasColor) + { + display.clearScreen(); // use default for white + int16_t x = (int16_t(display.epd2.WIDTH) - 200) / 2; + int16_t y = (int16_t(display.epd2.HEIGHT) - 200) / 2; + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.drawImage(bitmap_pairs[i].black, bitmap_pairs[i].red, x, y, 200, 200, false, false, true); + delay(2000); + } + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + int16_t x = -60; + int16_t y = -60; + for (uint16_t j = 0; j < 10; j++) + { + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmap_pairs[i].black, bitmap_pairs[i].red, x, y, 200, 200, false, false, true); + display.refresh(); + delay(2000); + x += 40; + y += 40; + if ((x >= int16_t(display.epd2.WIDTH)) || (y >= int16_t(display.epd2.HEIGHT))) break; + } + } + display.writeScreenBuffer(); // use default for white + display.writeImage(bitmap_pairs[0].black, bitmap_pairs[0].red, 0, 0, 200, 200, false, false, true); + display.writeImage(bitmap_pairs[0].black, bitmap_pairs[0].red, int16_t(display.epd2.WIDTH) - 200, int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, false, true); + display.refresh(); + delay(2000); + } +} +#endif + +#ifdef _GxBitmaps3c104x212_H_ +template class GxGFX_Type> +void drawBitmaps3c104x212(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps3c104x212(GxGFX_Type& display) +{ +#if !defined(__AVR) + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c104x212_1_black, Bitmap3c104x212_1_red}, + {Bitmap3c104x212_2_black, Bitmap3c104x212_2_red}, + {WS_Bitmap3c104x212_black, WS_Bitmap3c104x212_red} + }; +#else + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c104x212_1_black, Bitmap3c104x212_1_red}, + //{Bitmap3c104x212_2_black, Bitmap3c104x212_2_red}, + {WS_Bitmap3c104x212_black, WS_Bitmap3c104x212_red} + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW0213Z16) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + if (bitmap_pairs[i].red == WS_Bitmap3c104x212_red) + { + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + else display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps3c128x296_H_ +template class GxGFX_Type> +void drawBitmaps3c128x296(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps3c128x296(GxGFX_Type& display) +{ +#if !defined(__AVR) + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c128x296_1_black, Bitmap3c128x296_1_red}, + {Bitmap3c128x296_2_black, Bitmap3c128x296_2_red}, + {WS_Bitmap3c128x296_black, WS_Bitmap3c128x296_red} + }; +#else + bitmap_pair bitmap_pairs[] = + { + //{Bitmap3c128x296_1_black, Bitmap3c128x296_1_red}, + //{Bitmap3c128x296_2_black, Bitmap3c128x296_2_red}, + {WS_Bitmap3c128x296_black, WS_Bitmap3c128x296_red} + }; +#endif + if (display.epd2.panel == GxEPD2::GDEW029Z10) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + if (bitmap_pairs[i].red == WS_Bitmap3c128x296_red) + { + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + else display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps3c176x264_H_ +template class GxGFX_Type> +void drawBitmaps3c176x264(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps3c176x264(GxGFX_Type& display) +{ + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c176x264_black, Bitmap3c176x264_red} + }; + if (display.epd2.panel == GxEPD2::GDEW027C44) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +#ifdef _GxBitmaps3c400x300_H_ +template class GxGFX_Type> +void drawBitmaps3c400x300(GxGFX_Type& display); +template class GxGFX_Type> +void drawBitmaps3c400x300(GxGFX_Type& display) +{ +#if !defined(__AVR) + bitmap_pair bitmap_pairs[] = + { + {Bitmap3c400x300_1_black, Bitmap3c400x300_1_red}, + {Bitmap3c400x300_2_black, Bitmap3c400x300_2_red}, + {WS_Bitmap3c400x300_black, WS_Bitmap3c400x300_red} + }; +#else + bitmap_pair bitmap_pairs[] = {}; // not enough code space +#endif + if (display.epd2.panel == GxEPD2::GDEW042Z15) + { + for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) + { + display.firstPage(); + do + { + display.fillScreen(GxEPD_WHITE); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); + display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); + } + while (display.nextPage()); + delay(2000); + } + } +} +#endif + +template class GxGFX_Type> +void drawBitmaps(GxGFX_Type& display) +{ + display.setFullWindow(); + display.setRotation(0); +#ifdef _GxBitmaps128x250_H_ + drawBitmaps128x250(display); +#endif +#ifdef _GxBitmaps128x296_H_ + drawBitmaps128x296(display); +#endif +#ifdef _GxBitmaps176x264_H_ + drawBitmaps176x264(display); +#endif +#ifdef _GxBitmaps400x300_H_ + drawBitmaps400x300(display); +#endif +#ifdef _GxBitmaps640x384_H_ + drawBitmaps640x384(display); +#endif + // 3-color +#ifdef _GxBitmaps3c104x212_H_ + drawBitmaps3c104x212(display); +#endif +#ifdef _GxBitmaps3c128x296_H_ + drawBitmaps3c128x296(display); +#endif +#ifdef _GxBitmaps3c176x264_H_ + drawBitmaps3c176x264(display); +#endif +#ifdef _GxBitmaps3c400x300_H_ + drawBitmaps3c400x300(display); +#endif + // show these after the specific bitmaps +#ifdef _GxBitmaps200x200_H_ + drawBitmaps200x200(display); +#endif + // 3-color +#ifdef _GxBitmaps3c200x200_H_ + drawBitmaps3c200x200(display); +#endif +} diff --git a/library.properties b/library.properties index 9965a06..cc6c7bd 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=GxEPD2 -version=1.2.2 +version=1.2.3 author=Jean-Marc Zingg maintainer=Jean-Marc Zingg sentence=Arduino Display Library for SPI E-Paper displays from Dalian Good Display and Waveshare. diff --git a/src/GxEPD2_EPD.h b/src/GxEPD2_EPD.h index 579a05a..8a61817 100644 --- a/src/GxEPD2_EPD.h +++ b/src/GxEPD2_EPD.h @@ -44,6 +44,8 @@ class GxEPD2_EPD virtual void writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; virtual void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; + // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8 + virtual void writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; // for differential update: set current and previous buffers equal (for fast partial update to work correctly) virtual void writeScreenBufferAgain(uint8_t value = 0xFF) // init controller memory (default white) { @@ -68,6 +70,8 @@ class GxEPD2_EPD virtual void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; virtual void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; + // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8 + virtual void drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; virtual void refresh(bool partial_update_mode = false) = 0; // screen refresh from controller memory to full screen virtual void refresh(int16_t x, int16_t y, int16_t w, int16_t h) = 0; // screen refresh from controller memory, partial screen virtual void powerOff() = 0; // turns off generation of panel driving voltages, avoids screen fading over time diff --git a/src/GxEPD2_GFX.h b/src/GxEPD2_GFX.h index 60783c0..25c08e6 100644 --- a/src/GxEPD2_GFX.h +++ b/src/GxEPD2_GFX.h @@ -63,6 +63,8 @@ class GxEPD2_GFX : public Adafruit_GFX int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) = 0; virtual void writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h) = 0; // default options false + // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8 + virtual void writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; // write to controller memory, with screen refresh; x and w should be multiple of 8 virtual void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; virtual void drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, @@ -73,6 +75,8 @@ class GxEPD2_GFX : public Adafruit_GFX int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) = 0; virtual void drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, int16_t x, int16_t y, int16_t w, int16_t h) = 0; // default options false + // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8 + virtual void drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0; virtual void refresh(bool partial_update_mode = false) = 0; // screen refresh from controller memory to full screen virtual void refresh(int16_t x, int16_t y, int16_t w, int16_t h) = 0; // screen refresh from controller memory, partial screen virtual void powerOff() = 0; // turns off generation of panel driving voltages, avoids screen fading over time diff --git a/src/epd3c/GxEPD2_213c.cpp b/src/epd3c/GxEPD2_213c.cpp index f99f3cd..5134ed9 100644 --- a/src/epd3c/GxEPD2_213c.cpp +++ b/src/epd3c/GxEPD2_213c.cpp @@ -292,8 +292,10 @@ void GxEPD2_213c::refresh(int16_t x, int16_t y, int16_t w, int16_t h) w1 -= x1 - x; h1 -= y1 - y; _Init_Part(); + if (usePartialUpdateWindow) _writeCommand(0x91); // partial in _setPartialRamArea(x1, y1, w1, h1); _Update_Part(); + if (usePartialUpdateWindow) _writeCommand(0x92); // partial out } void GxEPD2_213c::powerOff() @@ -375,6 +377,8 @@ void GxEPD2_213c::_Init_Full() void GxEPD2_213c::_Init_Part() { _InitDisplay(); + _writeCommand(0X50); + _writeData(0xF7); //WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 _PowerOn(); } diff --git a/src/epd3c/GxEPD2_213c.h b/src/epd3c/GxEPD2_213c.h index 4a14c6b..6fc004f 100644 --- a/src/epd3c/GxEPD2_213c.h +++ b/src/epd3c/GxEPD2_213c.h @@ -24,6 +24,7 @@ class GxEPD2_213c : public GxEPD2_EPD static const GxEPD2::Panel panel = GxEPD2::GDEW0213Z16; static const bool hasColor = true; static const bool hasPartialUpdate = true; + static const bool usePartialUpdateWindow = true; // set false for better image static const bool hasFastPartialUpdate = false; static const uint16_t power_on_time = 40; // ms, e.g. 36991us static const uint16_t power_off_time = 30; // ms, e.g. 20754us diff --git a/src/epd3c/GxEPD2_290c.cpp b/src/epd3c/GxEPD2_290c.cpp index 317522b..cd62e8c 100644 --- a/src/epd3c/GxEPD2_290c.cpp +++ b/src/epd3c/GxEPD2_290c.cpp @@ -292,8 +292,10 @@ void GxEPD2_290c::refresh(int16_t x, int16_t y, int16_t w, int16_t h) w1 -= x1 - x; h1 -= y1 - y; _Init_Part(); + if (usePartialUpdateWindow) _writeCommand(0x91); // partial in _setPartialRamArea(x1, y1, w1, h1); _Update_Part(); + if (usePartialUpdateWindow) _writeCommand(0x92); // partial out } void GxEPD2_290c::powerOff() @@ -375,6 +377,8 @@ void GxEPD2_290c::_Init_Full() void GxEPD2_290c::_Init_Part() { _InitDisplay(); + _writeCommand(0X50); + _writeData(0xF7); //WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 _PowerOn(); } diff --git a/src/epd3c/GxEPD2_290c.h b/src/epd3c/GxEPD2_290c.h index ebfe592..26a3e99 100644 --- a/src/epd3c/GxEPD2_290c.h +++ b/src/epd3c/GxEPD2_290c.h @@ -24,6 +24,7 @@ class GxEPD2_290c : public GxEPD2_EPD static const GxEPD2::Panel panel = GxEPD2::GDEW029Z10; static const bool hasColor = true; static const bool hasPartialUpdate = true; + static const bool usePartialUpdateWindow = true; // set false for better image static const bool hasFastPartialUpdate = false; static const uint16_t power_on_time = 40; // ms, e.g. 36557us static const uint16_t power_off_time = 30; // ms, e.g. 20291us diff --git a/src/epd3c/GxEPD2_420c.cpp b/src/epd3c/GxEPD2_420c.cpp index fb2866d..33fce41 100644 --- a/src/epd3c/GxEPD2_420c.cpp +++ b/src/epd3c/GxEPD2_420c.cpp @@ -292,8 +292,10 @@ void GxEPD2_420c::refresh(int16_t x, int16_t y, int16_t w, int16_t h) w1 -= x1 - x; h1 -= y1 - y; _Init_Part(); + if (usePartialUpdateWindow) _writeCommand(0x91); // partial in _setPartialRamArea(x1, y1, w1, h1); _Update_Part(); + if (usePartialUpdateWindow) _writeCommand(0x92); // partial out } void GxEPD2_420c::powerOff() @@ -357,6 +359,13 @@ void GxEPD2_420c::_InitDisplay() _writeData(0x17); _writeCommand(0x00); _writeData(0x0f); // LUT from OTP Pixel with B/W/R. + _writeCommand(0x61); // resolution setting + _writeData (WIDTH / 256); + _writeData (WIDTH % 256); + _writeData (HEIGHT / 256); + _writeData (HEIGHT % 256); + _writeCommand(0x50); // VCOM AND DATA INTERVAL SETTING + _writeData(0xf7); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7 } void GxEPD2_420c::_Init_Full() diff --git a/src/epd3c/GxEPD2_420c.h b/src/epd3c/GxEPD2_420c.h index 0b0f9a9..82eec5e 100644 --- a/src/epd3c/GxEPD2_420c.h +++ b/src/epd3c/GxEPD2_420c.h @@ -24,6 +24,7 @@ class GxEPD2_420c : public GxEPD2_EPD static const GxEPD2::Panel panel = GxEPD2::GDEW042Z15; static const bool hasColor = true; static const bool hasPartialUpdate = true; + static const bool usePartialUpdateWindow = false; // needs be false to work static const bool hasFastPartialUpdate = false; static const uint16_t power_on_time = 40; // ms, e.g. 38006us static const uint16_t power_off_time = 30; // ms, e.g. 20292us