Просмотр исходного кода

Version 1.4.7

- added support for GDEP0150BN 1.50" b/w 200x200, e.g. LILYGO® TTGO T5 V2.4.1 1.50 inch
- added support for DEPG0213BN 2.13" b/w 128x250, e.g. LILYGO® TTGO T5 V2.3.1 2.13 inch
- added support for DEPG0266BN 2.66" b/w 152x296, e.g. LILYGO® TTGO T5 2.66 inch
- added support for DEPG0290BS 2.9"  b/w 128x296, e.g. LILYGO® TTGO T5 V2.4.1 2.9"
- added support for ES103TC1 10.3" grey levels, 1872x1404, on Waveshare e-Paper IT8951 Driver HAT
ZinggJM 4 лет назад
Родитель
Сommit
f67d08497f
41 измененных файлов с 3066 добавлено и 92 удалено
  1. 13 2
      README.md
  2. 5 0
      examples/GxEPD2_Example/GxEPD2_display_selection.h
  3. 12 4
      examples/GxEPD2_Example/GxEPD2_display_selection_new_style.h
  4. 5 0
      examples/GxEPD2_Example/GxEPD2_selection_check.h
  5. 5 0
      examples/GxEPD2_GFX_Example/GxEPD2_display_selection.h
  6. 12 4
      examples/GxEPD2_GFX_Example/GxEPD2_display_selection_new_style.h
  7. 5 0
      examples/GxEPD2_GFX_Example/GxEPD2_selection_check.h
  8. 5 0
      examples/GxEPD2_HelloWorld/GxEPD2_display_selection.h
  9. 12 4
      examples/GxEPD2_HelloWorld/GxEPD2_display_selection_new_style.h
  10. 5 0
      examples/GxEPD2_HelloWorld/GxEPD2_selection_check.h
  11. 12 4
      examples/GxEPD2_MinimumExample/GxEPD2_display_selection_new_style.h
  12. 5 0
      examples/GxEPD2_MinimumExample/GxEPD2_selection_check.h
  13. 12 4
      examples/GxEPD2_NotPagedExample/GxEPD2_display_selection_new_style.h
  14. 5 0
      examples/GxEPD2_NotPagedExample/GxEPD2_selection_check.h
  15. 12 4
      examples/GxEPD2_PagedDisplayUsingCallback/GxEPD2_display_selection_new_style.h
  16. 5 0
      examples/GxEPD2_PagedDisplayUsingCallback/GxEPD2_selection_check.h
  17. 12 4
      examples/GxEPD2_RotaryUsingBusyCallback/GxEPD2_display_selection_new_style.h
  18. 5 0
      examples/GxEPD2_RotaryUsingBusyCallback/GxEPD2_selection_check.h
  19. 12 4
      examples/GxEPD2_SD_Example/GxEPD2_display_selection_new_style.h
  20. 5 0
      examples/GxEPD2_SD_Example/GxEPD2_selection_check.h
  21. 12 4
      examples/GxEPD2_SerialFlash_Example/GxEPD2_display_selection_new_style.h
  22. 5 0
      examples/GxEPD2_SerialFlash_Example/GxEPD2_selection_check.h
  23. 12 4
      examples/GxEPD2_Spiffs_Example/GxEPD2_display_selection_new_style.h
  24. 5 0
      examples/GxEPD2_Spiffs_Example/GxEPD2_selection_check.h
  25. 12 4
      examples/GxEPD2_U8G2_Fonts_Example/GxEPD2_display_selection_new_style.h
  26. 5 0
      examples/GxEPD2_U8G2_Fonts_Example/GxEPD2_selection_check.h
  27. 63 45
      examples/GxEPD2_WiFi_Example/GxEPD2_WiFi_Example.ino
  28. 1 1
      library.properties
  29. 5 0
      src/GxEPD2.h
  30. 5 0
      src/GxEPD2_BW.h
  31. 4 0
      src/GxEPD2_EPD.cpp
  32. 405 0
      src/epd/GxEPD2_150_BN.cpp
  33. 85 0
      src/epd/GxEPD2_150_BN.h
  34. 410 0
      src/epd/GxEPD2_213_BN.cpp
  35. 84 0
      src/epd/GxEPD2_213_BN.h
  36. 413 0
      src/epd/GxEPD2_266_BN.cpp
  37. 85 0
      src/epd/GxEPD2_266_BN.h
  38. 413 0
      src/epd/GxEPD2_290_BS.cpp
  39. 85 0
      src/epd/GxEPD2_290_BS.h
  40. 680 0
      src/it8951/GxEPD2_it103_1872x1404.cpp
  41. 113 0
      src/it8951/GxEPD2_it103_1872x1404.h

+ 13 - 2
README.md

@@ -53,6 +53,7 @@
 
 ### Supported SPI e-paper panels from Good Display:
 - GDEW0102T4     1.02" b/w
+- GDEP0150BN     1.50" b/w 200x200, e.g. LILYGO® TTGO T5 V2.4.1 1.50 inch
 - GDEP015OC1     1.54" b/w
 - GDEH0154D67    1.54" b/w, replacement for GDEP015OC1
 - GDEW0154T8     1.54" b/w 152x152
@@ -70,6 +71,7 @@
 - GDEW0213Z16    2.13" b/w/r
 - GDEW0213Z19    2.13" b/w/r
 - GDEY0213Z98    2.13" b/w/r 122x250
+- DEPG0213BN     2.13" b/w 128x250, e.g. LILYGO® TTGO T5 V2.3.1 2.13 inch
 - GDEH029A1      2.9" b/w
 - GDEW029T5      2.9" b/w
 - GDEW029T5D     2.9" b/w
@@ -79,8 +81,10 @@
 - GDEW029Z10     2.9" b/w/r
 - GDEW029Z13     2.9" b/w/r
 - GDEM029C90     2.9" b/w/y
+- DEPG0290BS     2.9" b/w 128x296, e.g. LILYGO® TTGO T5 V2.4.1 2.9"
 - GDEW026T0      2.6" b/w
 - GDEW026M01     2.6" b/w DES
+- DEPG0266BN     2.66" b/w 152x296, e.g. LILYGO® TTGO T5 2.66 inch
 - GDEY0266Z90    2.66" b/w/r 152x296
 - GDEW027C44     2.7" b/w/r
 - GDEW027W3      2.7" b/w
@@ -106,15 +110,22 @@
 - ED060SCT        6" grey levels, on Waveshare e-Paper IT8951 Driver HAT
 - ED060KC1        6" grey levels, 1448x1072, on Waveshare e-Paper IT8951 Driver HAT
 - ED078KC2        7.8" grey levels, 1872x1404, on Waveshare e-Paper IT8951 Driver HAT
+- ES103TC1       10.3" grey levels, 1872x1404, on Waveshare e-Paper IT8951 Driver HAT
 
 ### I can and will only support e-paper panels I have!
 - promotion panels from suppliers are welcome, to add support to GxEPD2
 - donation panels from users are welcome, to add support to GxEPD2
 
-### Version 1.4.6
+### Version 1.4.7
+- added support for GDEP0150BN 1.50" b/w 200x200, e.g. LILYGO® TTGO T5 V2.4.1 1.50 inch
+- added support for DEPG0213BN 2.13" b/w 128x250, e.g. LILYGO® TTGO T5 V2.3.1 2.13 inch
+- added support for DEPG0266BN 2.66" b/w 152x296, e.g. LILYGO® TTGO T5 2.66 inch
+- added support for DEPG0290BS 2.9"  b/w 128x296, e.g. LILYGO® TTGO T5 V2.4.1 2.9"
+- added support for ES103TC1 10.3" grey levels, 1872x1404, on Waveshare e-Paper IT8951 Driver HAT
+#### Version 1.4.6
 - added support for GDEY0266Z90 2.66" b/w/r 152x296
 - added support for GDEW0583Z83 5.83" b/w/r 648x460
-### Version 1.4.5
+#### Version 1.4.5
 - added support for GDEY0213Z98 2.13" b/w/r 122x250
 - tested with LOLIN 2.13" Tri-Color eInk / ePaper 250x122 Display Shield
 - https://www.aliexpress.com/item/1005003020667903.html

+ 5 - 0
examples/GxEPD2_Example/GxEPD2_display_selection.h

@@ -139,6 +139,7 @@
 #if defined(ESP32)
 // select one and adapt to your mapping, can use full buffer size (full HEIGHT)
 //GxEPD2_BW<GxEPD2_102, GxEPD2_102::HEIGHT> display(GxEPD2_102(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0102T4
+//GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT> display(GxEPD2_150_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //GxEPD2_BW<GxEPD2_154, GxEPD2_154::HEIGHT> display(GxEPD2_154(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEP015OC1 no longer available
 //GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH0154D67
 //GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(GxEPD2_154_T8(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0154T8 152x152
@@ -151,6 +152,7 @@
 //GxEPD2_BW<GxEPD2_213_flex, GxEPD2_213_flex::HEIGHT> display(GxEPD2_213_flex(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213I5F
 //GxEPD2_BW<GxEPD2_213_M21, GxEPD2_213_M21::HEIGHT> display(GxEPD2_213_M21(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213M21
 //GxEPD2_BW<GxEPD2_213_T5D, GxEPD2_213_T5D::HEIGHT> display(GxEPD2_213_T5D(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213T5D
+//GxEPD2_BW<GxEPD2_213_BN, GxEPD2_213_BN::HEIGHT> display(GxEPD2_213_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(GxEPD2_290(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH029A1
 //GxEPD2_BW<GxEPD2_290_T5, GxEPD2_290_T5::HEIGHT> display(GxEPD2_290_T5(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029T5
 //GxEPD2_BW<GxEPD2_290_T5D, GxEPD2_290_T5D::HEIGHT> display(GxEPD2_290_T5D(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029T5D
@@ -160,6 +162,8 @@
 //GxEPD2_BW<GxEPD2_290_M06, GxEPD2_290_M06::HEIGHT> display(GxEPD2_290_M06(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029M06
 //GxEPD2_BW<GxEPD2_260, GxEPD2_260::HEIGHT> display(GxEPD2_260(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW026T0
 //GxEPD2_BW<GxEPD2_260_M01, GxEPD2_260_M01::HEIGHT> display(GxEPD2_260_M01(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW026M01
+//GxEPD2_BW<GxEPD2_266_BN, GxEPD2_266_BN::HEIGHT> display(GxEPD2_266_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.4.1
+//GxEPD2_BW<GxEPD2_266_BN, GxEPD2_266_BN::HEIGHT> display(GxEPD2_266_BN(/*CS=5*/ SS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66 / T92_V1.0
 //GxEPD2_BW<GxEPD2_270, GxEPD2_270::HEIGHT> display(GxEPD2_270(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW027W3
 //GxEPD2_BW<GxEPD2_371, GxEPD2_371::HEIGHT> display(GxEPD2_371(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0371W7
 //GxEPD2_BW<GxEPD2_370_TC1, GxEPD2_370_TC1::HEIGHT> display(GxEPD2_370_TC1(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // ED037TC1, Waveshare 3.7"
@@ -198,6 +202,7 @@
 //GxEPD2_BW<GxEPD2_it60, GxEPD2_it60::HEIGHT> display(GxEPD2_it60(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 //GxEPD2_BW < GxEPD2_it60_1448x1072, GxEPD2_it60_1448x1072::HEIGHT / 4 > display(GxEPD2_it60_1448x1072(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 //GxEPD2_BW < GxEPD2_it78_1872x1404, GxEPD2_it78_1872x1404::HEIGHT / 8 > display(GxEPD2_it78_1872x1404(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+//GxEPD2_BW < GxEPD2_it103_1872x1404, GxEPD2_it103_1872x1404::HEIGHT / 8 > display(GxEPD2_it103_1872x1404(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3
 // general constructor for use with all parameters, e.g. for Waveshare ESP32 driver board mounted on connection board

+ 12 - 4
examples/GxEPD2_Example/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_Example/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 5 - 0
examples/GxEPD2_GFX_Example/GxEPD2_display_selection.h

@@ -139,6 +139,7 @@
 #if defined(ESP32)
 // select one and adapt to your mapping, can use full buffer size (full HEIGHT)
 //GxEPD2_BW<GxEPD2_102, GxEPD2_102::HEIGHT> display(GxEPD2_102(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0102T4
+//GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT> display(GxEPD2_150_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //GxEPD2_BW<GxEPD2_154, GxEPD2_154::HEIGHT> display(GxEPD2_154(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEP015OC1 no longer available
 //GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH0154D67
 //GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(GxEPD2_154_T8(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0154T8 152x152
@@ -151,6 +152,7 @@
 //GxEPD2_BW<GxEPD2_213_flex, GxEPD2_213_flex::HEIGHT> display(GxEPD2_213_flex(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213I5F
 //GxEPD2_BW<GxEPD2_213_M21, GxEPD2_213_M21::HEIGHT> display(GxEPD2_213_M21(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213M21
 //GxEPD2_BW<GxEPD2_213_T5D, GxEPD2_213_T5D::HEIGHT> display(GxEPD2_213_T5D(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213T5D
+//GxEPD2_BW<GxEPD2_213_BN, GxEPD2_213_BN::HEIGHT> display(GxEPD2_213_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(GxEPD2_290(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH029A1
 //GxEPD2_BW<GxEPD2_290_T5, GxEPD2_290_T5::HEIGHT> display(GxEPD2_290_T5(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029T5
 //GxEPD2_BW<GxEPD2_290_T5D, GxEPD2_290_T5D::HEIGHT> display(GxEPD2_290_T5D(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029T5D
@@ -160,6 +162,8 @@
 //GxEPD2_BW<GxEPD2_290_M06, GxEPD2_290_M06::HEIGHT> display(GxEPD2_290_M06(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029M06
 //GxEPD2_BW<GxEPD2_260, GxEPD2_260::HEIGHT> display(GxEPD2_260(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW026T0
 //GxEPD2_BW<GxEPD2_260_M01, GxEPD2_260_M01::HEIGHT> display(GxEPD2_260_M01(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW026M01
+//GxEPD2_BW<GxEPD2_266_BN, GxEPD2_266_BN::HEIGHT> display(GxEPD2_266_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.4.1
+//GxEPD2_BW<GxEPD2_266_BN, GxEPD2_266_BN::HEIGHT> display(GxEPD2_266_BN(/*CS=5*/ SS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66 / T92_V1.0
 //GxEPD2_BW<GxEPD2_270, GxEPD2_270::HEIGHT> display(GxEPD2_270(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW027W3
 //GxEPD2_BW<GxEPD2_371, GxEPD2_371::HEIGHT> display(GxEPD2_371(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0371W7
 //GxEPD2_BW<GxEPD2_370_TC1, GxEPD2_370_TC1::HEIGHT> display(GxEPD2_370_TC1(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // ED037TC1, Waveshare 3.7"
@@ -198,6 +202,7 @@
 //GxEPD2_BW<GxEPD2_it60, GxEPD2_it60::HEIGHT> display(GxEPD2_it60(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 //GxEPD2_BW < GxEPD2_it60_1448x1072, GxEPD2_it60_1448x1072::HEIGHT / 4 > display(GxEPD2_it60_1448x1072(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 //GxEPD2_BW < GxEPD2_it78_1872x1404, GxEPD2_it78_1872x1404::HEIGHT / 8 > display(GxEPD2_it78_1872x1404(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+//GxEPD2_BW < GxEPD2_it103_1872x1404, GxEPD2_it103_1872x1404::HEIGHT / 8 > display(GxEPD2_it103_1872x1404(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3
 // general constructor for use with all parameters, e.g. for Waveshare ESP32 driver board mounted on connection board

+ 12 - 4
examples/GxEPD2_GFX_Example/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_GFX_Example/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 5 - 0
examples/GxEPD2_HelloWorld/GxEPD2_display_selection.h

@@ -139,6 +139,7 @@
 #if defined(ESP32)
 // select one and adapt to your mapping, can use full buffer size (full HEIGHT)
 //GxEPD2_BW<GxEPD2_102, GxEPD2_102::HEIGHT> display(GxEPD2_102(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0102T4
+//GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT> display(GxEPD2_150_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //GxEPD2_BW<GxEPD2_154, GxEPD2_154::HEIGHT> display(GxEPD2_154(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEP015OC1 no longer available
 //GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH0154D67
 //GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(GxEPD2_154_T8(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0154T8 152x152
@@ -151,6 +152,7 @@
 //GxEPD2_BW<GxEPD2_213_flex, GxEPD2_213_flex::HEIGHT> display(GxEPD2_213_flex(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213I5F
 //GxEPD2_BW<GxEPD2_213_M21, GxEPD2_213_M21::HEIGHT> display(GxEPD2_213_M21(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213M21
 //GxEPD2_BW<GxEPD2_213_T5D, GxEPD2_213_T5D::HEIGHT> display(GxEPD2_213_T5D(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0213T5D
+//GxEPD2_BW<GxEPD2_213_BN, GxEPD2_213_BN::HEIGHT> display(GxEPD2_213_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(GxEPD2_290(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEH029A1
 //GxEPD2_BW<GxEPD2_290_T5, GxEPD2_290_T5::HEIGHT> display(GxEPD2_290_T5(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029T5
 //GxEPD2_BW<GxEPD2_290_T5D, GxEPD2_290_T5D::HEIGHT> display(GxEPD2_290_T5D(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029T5D
@@ -160,6 +162,8 @@
 //GxEPD2_BW<GxEPD2_290_M06, GxEPD2_290_M06::HEIGHT> display(GxEPD2_290_M06(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW029M06
 //GxEPD2_BW<GxEPD2_260, GxEPD2_260::HEIGHT> display(GxEPD2_260(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW026T0
 //GxEPD2_BW<GxEPD2_260_M01, GxEPD2_260_M01::HEIGHT> display(GxEPD2_260_M01(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW026M01
+//GxEPD2_BW<GxEPD2_266_BN, GxEPD2_266_BN::HEIGHT> display(GxEPD2_266_BN(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.4.1
+//GxEPD2_BW<GxEPD2_266_BN, GxEPD2_266_BN::HEIGHT> display(GxEPD2_266_BN(/*CS=5*/ SS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66 / T92_V1.0
 //GxEPD2_BW<GxEPD2_270, GxEPD2_270::HEIGHT> display(GxEPD2_270(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW027W3
 //GxEPD2_BW<GxEPD2_371, GxEPD2_371::HEIGHT> display(GxEPD2_371(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // GDEW0371W7
 //GxEPD2_BW<GxEPD2_370_TC1, GxEPD2_370_TC1::HEIGHT> display(GxEPD2_370_TC1(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // ED037TC1, Waveshare 3.7"
@@ -198,6 +202,7 @@
 //GxEPD2_BW<GxEPD2_it60, GxEPD2_it60::HEIGHT> display(GxEPD2_it60(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 //GxEPD2_BW < GxEPD2_it60_1448x1072, GxEPD2_it60_1448x1072::HEIGHT / 4 > display(GxEPD2_it60_1448x1072(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 //GxEPD2_BW < GxEPD2_it78_1872x1404, GxEPD2_it78_1872x1404::HEIGHT / 8 > display(GxEPD2_it78_1872x1404(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+//GxEPD2_BW < GxEPD2_it103_1872x1404, GxEPD2_it103_1872x1404::HEIGHT / 8 > display(GxEPD2_it103_1872x1404(/*CS=5*/ SS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
 
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3
 // general constructor for use with all parameters, e.g. for Waveshare ESP32 driver board mounted on connection board

+ 12 - 4
examples/GxEPD2_HelloWorld/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_HelloWorld/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_MinimumExample/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_MinimumExample/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_NotPagedExample/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_NotPagedExample/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_PagedDisplayUsingCallback/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_PagedDisplayUsingCallback/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_RotaryUsingBusyCallback/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_RotaryUsingBusyCallback/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_SD_Example/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_SD_Example/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_SerialFlash_Example/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_SerialFlash_Example/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_Spiffs_Example/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_Spiffs_Example/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 12 - 4
examples/GxEPD2_U8G2_Fonts_Example/GxEPD2_display_selection_new_style.h

@@ -13,6 +13,8 @@
 // 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
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
@@ -20,6 +22,7 @@
 
 // select the display driver class (only one) for your  panel
 //#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
 //#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
@@ -32,15 +35,18 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
 //#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
 //#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
 //#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
@@ -76,6 +82,7 @@
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -128,11 +135,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-//#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 5 - 0
examples/GxEPD2_U8G2_Fonts_Example/GxEPD2_selection_check.h

@@ -14,6 +14,7 @@
 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0
 
 #define GxEPD2_102_IS_BW true
+#define GxEPD2_150_BN_IS_BW true
 #define GxEPD2_154_IS_BW true
 #define GxEPD2_154_D67_IS_BW true
 #define GxEPD2_154_T8_IS_BW true
@@ -26,15 +27,18 @@
 #define GxEPD2_213_flex_IS_BW true
 #define GxEPD2_213_M21_IS_BW true
 #define GxEPD2_213_T5D_IS_BW true
+#define GxEPD2_213_BN_IS_BW true
 #define GxEPD2_290_IS_BW true
 #define GxEPD2_290_T5_IS_BW true
 #define GxEPD2_290_T5D_IS_BW true
 #define GxEPD2_290_I6FD_IS_BW true
 #define GxEPD2_290_T94_IS_BW true
 #define GxEPD2_290_T94_V2_IS_BW true
+#define GxEPD2_290_BS_IS_BW true
 #define GxEPD2_290_M06_IS_BW true
 #define GxEPD2_260_IS_BW true
 #define GxEPD2_260_M01_IS_BW true
+#define GxEPD2_266_BN_IS_BW true
 #define GxEPD2_270_IS_BW true
 #define GxEPD2_371_IS_BW true
 #define GxEPD2_370_TC1_IS_BW true
@@ -49,6 +53,7 @@
 #define GxEPD2_it60_IS_BW true
 #define GxEPD2_it60_1448x1072_IS_BW true
 #define GxEPD2_it78_1872x1404_IS_BW true
+#define GxEPD2_it103_1872x1404_IS_BW true
 // 3-color e-papers
 #define GxEPD2_154c_IS_3C true
 #define GxEPD2_154_Z90c_IS_3C true

+ 63 - 45
examples/GxEPD2_WiFi_Example/GxEPD2_WiFi_Example.ino

@@ -32,59 +32,76 @@
 #include <GxEPD2_3C.h>
 #include <GxEPD2_7C.h>
 
+// NOTE: you may need to adapt or select for your wiring in the processor specific conditional compile sections below
+
 // select the display class (only one), matching the kind of display panel
 #define GxEPD2_DISPLAY_CLASS GxEPD2_BW
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_3C
 //#define GxEPD2_DISPLAY_CLASS GxEPD2_7C
 
-/// select the display driver class (only one) for your  panel
-//#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, no longer available
-//#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200
-//#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152
-//#define GxEPD2_DRIVER_CLASS GxEPD2_154_M09 // GDEW0154M09 200x200
-//#define GxEPD2_DRIVER_CLASS GxEPD2_154_M10 // GDEW0154M10 152x152
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213     // GDE0213B1   128x250, phased out
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B72 // GDEH0213B72 128x250
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B73 // GDEH0213B73 128x250
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264
-//#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416
-//#define GxEPD2_DRIVER_CLASS GxEPD2_420     // GDEW042T2   400x300
-//#define GxEPD2_DRIVER_CLASS GxEPD2_420_M01 // GDEW042M01  400x300
-//#define GxEPD2_DRIVER_CLASS GxEPD2_583     // GDEW0583T7  600x448
-//#define GxEPD2_DRIVER_CLASS GxEPD2_583_T8  // GDEW0583T8  648x480
-//#define GxEPD2_DRIVER_CLASS GxEPD2_750     // GDEW075T8   640x384
-//#define GxEPD2_DRIVER_CLASS GxEPD2_750_T7  // GDEW075T7   800x480
+// select the display driver class (only one) for your  panel
+//#define GxEPD2_DRIVER_CLASS GxEPD2_102     // GxEPD2_102   80x128, UC8175
+//#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN // GDEP0150BN 200x200, SSD1681, TTGO T5 V2.4.1
+//#define GxEPD2_DRIVER_CLASS GxEPD2_154     // GDEP015OC1  200x200, IL3829, no longer available
+//#define GxEPD2_DRIVER_CLASS GxEPD2_154_D67 // GDEH0154D67 200x200, SSD1681
+//#define GxEPD2_DRIVER_CLASS GxEPD2_154_T8  // GDEW0154T8  152x152, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_154_M09 // GDEW0154M09 200x200, JD79653A
+//#define GxEPD2_DRIVER_CLASS GxEPD2_154_M10 // GDEW0154M10 152x152, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213     // GDE0213B1   128x250, IL3895, phased out
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B72 // GDEH0213B72 128x250, SSD1675A (IL3897)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B73 // GDEH0213B73 128x250, SSD1675B
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_B74 // GDEM0213B74 128x250, SSD1680
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_flex // GDEW0213I5F 104x212, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_M21 // GDEW0213M21 104x212, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_T5D // GDEW0213T5D 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_BN // DEPG0213BN  128x250, SSD1680, TTGO T5 V2.4.1, V2.3.1
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290     // GDEH029A1   128x296, SSD1608 (IL3820)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5  // GDEW029T5   128x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T5D // GDEW029T5D  128x296, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_I6FD // GDEW029I6FD  128x296, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94 // GDEM029T94  128x296, SSD1680
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_T94_V2 // GDEM029T94  128x296, SSD1680, Waveshare 2.9" V2 variant
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_BS // DEPG0290BS  128x296, SSD1680
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_M06 // GDEW029M06  128x296, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_260     // GDEW026T0   152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_260_M01 // GDEW026M01  152x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266_BN // DEPG0266BN  152x296, SSD1680, TTGO T5 V2.66, TTGO T5 V2.4.1
+//#define GxEPD2_DRIVER_CLASS GxEPD2_270     // GDEW027W3   176x264, EK79652 (IL91874)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_371     // GDEW0371W7  240x416, UC8171 (IL0324)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_370_TC1 // ED037TC1  280x480, SSD1677, Waveshare 3.7"
+//#define GxEPD2_DRIVER_CLASS GxEPD2_420     // GDEW042T2   400x300, UC8176 (IL0398)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_420_M01 // GDEW042M01  400x300, UC8176 (IL0398)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_583     // GDEW0583T7  600x448, UC8179 (IL0371)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_583_T8  // GDEW0583T8  648x480, GD7965
+//#define GxEPD2_DRIVER_CLASS GxEPD2_750     // GDEW075T8   640x384, UC8179 (IL0371)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_750_T7  // GDEW075T7   800x480, GD7965
 //#define GxEPD2_DRIVER_CLASS GxEPD2_1160_T91 // GDEH116T91 960x640, SSD1677
+//#define GxEPD2_DRIVER_CLASS GxEPD2_1248     // GDEW1248T3  1304x984, UC8179
 // 3-color e-papers
-//#define GxEPD2_DRIVER_CLASS GxEPD2_154c     // GDEW0154Z04 200x200, no longer available
-//#define GxEPD2_DRIVER_CLASS GxEPD2_154_Z90c // GDEH0154Z90 200x200
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213c     // GDEW0213Z16 104x212
-//#define GxEPD2_DRIVER_CLASS GxEPD2_213_Z19c // GDEW0213Z19 104x212
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290c     // GDEW029Z10  128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290_Z13c // GDEH029Z13  128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_290_C90c // GDEM029C90  128x296
-//#define GxEPD2_DRIVER_CLASS GxEPD2_270c     // GDEW027C44  176x264
-//#define GxEPD2_DRIVER_CLASS GxEPD2_420c     // GDEW042Z15  400x300
-//#define GxEPD2_DRIVER_CLASS GxEPD2_583c     // GDEW0583Z21 600x448
-//#define GxEPD2_DRIVER_CLASS GxEPD2_750c     // GDEW075Z09  600x384
-//#define GxEPD2_DRIVER_CLASS GxEPD2_750c_Z08 // GDEW075Z08  800x480
-//#define GxEPD2_DRIVER_CLASS GxEPD2_750c_Z90 // GDEH075Z90  880x528
-//#define GxEPD2_DRIVER_CLASS GxEPD2_1248     // GDEW1248T3  1303x984
+//#define GxEPD2_DRIVER_CLASS GxEPD2_154c     // GDEW0154Z04 200x200, IL0376F, no longer available
+//#define GxEPD2_DRIVER_CLASS GxEPD2_154_Z90c // GDEH0154Z90 200x200, SSD1681
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213c     // GDEW0213Z16 104x212, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_Z19c // GDEW0213Z19 104x212, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_213_Z98c // GDEY0213Z98 122x250, SSD1680
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290c     // GDEW029Z10  128x296, UC8151 (IL0373)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_Z13c // GDEH029Z13  128x296, UC8151D
+//#define GxEPD2_DRIVER_CLASS GxEPD2_290_C90c // GDEM029C90  128x296, SSD1680
+//#define GxEPD2_DRIVER_CLASS GxEPD2_266c     // GDEY0266Z90 152x296, SSD1680
+//#define GxEPD2_DRIVER_CLASS GxEPD2_270c     // GDEW027C44  176x264, IL91874
+//#define GxEPD2_DRIVER_CLASS GxEPD2_420c     // GDEW042Z15  400x300, UC8176 (IL0398)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_420c_Z21 // GDEQ042Z21  400x300, UC8276
+//#define GxEPD2_DRIVER_CLASS GxEPD2_583c     // GDEW0583Z21 600x448, UC8179 (IL0371)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_583c_Z83 // GDEW0583Z83 648x480, GD7965
+//#define GxEPD2_DRIVER_CLASS GxEPD2_750c     // GDEW075Z09  640x384, UC8179 (IL0371)
+//#define GxEPD2_DRIVER_CLASS GxEPD2_750c_Z08 // GDEW075Z08  800x480, GD7965
+//#define GxEPD2_DRIVER_CLASS GxEPD2_750c_Z90 // GDEH075Z90  880x528, SSD1677
 // 7-color e-paper
 //#define GxEPD2_DRIVER_CLASS GxEPD2_565c // Waveshare 5.65" 7-color (3C graphics)
 // grey levels parallel IF e-papers on Waveshare e-Paper IT8951 Driver HAT
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60           // ED060SCT 800x600
 //#define GxEPD2_DRIVER_CLASS GxEPD2_it60_1448x1072 // ED060KC1 1448x1072
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it78_1872x1404 // ED078KC2 1872x1404
+//#define GxEPD2_DRIVER_CLASS GxEPD2_it103_1872x1404 // ES103TC1 1872x1404
 
 // SS is usually used for CS. define here for easy change
 #ifndef EPD_CS
@@ -131,11 +148,12 @@ GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> displ
 // adapt the constructor parameters to your wiring
 #if !IS_GxEPD2_1248(GxEPD2_DRIVER_CLASS)
 #if defined(ARDUINO_LOLIN_D32_PRO)
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15));
-#elif defined(ARDUINO_ESP32_DEV) // e.g. TTGO T8 ESP32-WROVER
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 0, /*RST=*/ 2, /*BUSY=*/ 15)); // my LOLIN_D32_PRO proto board
 #else
-GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4));
+GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // my suggested wiring and proto board
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ 5, /*DC=*/ 17, /*RST=*/ 16, /*BUSY=*/ 4)); // LILYGO_T5_V2.4.1
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 19, /*RST=*/ 4, /*BUSY=*/ 34)); // LILYGO® TTGO T5 2.66
+//GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, MAX_HEIGHT(GxEPD2_DRIVER_CLASS)> display(GxEPD2_DRIVER_CLASS(/*CS=5*/ EPD_CS, /*DC=*/ 2, /*RST=*/ 0, /*BUSY=*/ 4)); // e.g. TTGO T8 ESP32-WROVER
 #endif
 #else // GxEPD2_1248
 // Waveshare 12.48 b/w SPI display board and frame or Good Display 12.48 b/w panel GDEW1248T3

+ 1 - 1
library.properties

@@ -1,5 +1,5 @@
 name=GxEPD2
-version=1.4.6
+version=1.4.7
 author=Jean-Marc Zingg
 maintainer=Jean-Marc Zingg
 sentence=Arduino Display Library for SPI E-Paper displays from Dalian Good Display and Waveshare. 

+ 5 - 0
src/GxEPD2.h

@@ -37,6 +37,7 @@ class GxEPD2
     {
       GDEW0102T4, Waveshare_1_02_bw = GDEW0102T4,
       GDEP015OC1, Waveshare_1_54_bw = GDEP015OC1,
+      GDEP0150BN,
       GDEH0154D67, Waveshare_1_54_bw_D67 = GDEH0154D67,
       GDEW0154T8,
       GDEW0154M09,
@@ -48,14 +49,17 @@ class GxEPD2
       GDEW0213I5F, Waveshare_2_13_flex = GDEW0213I5F,
       GDEW0213M21,
       GDEW0213T5D,
+      DEPG0213BN,
       GDEW026T0,  Waveshare_2_6_bw = GDEW026T0,
       GDEW026M01,
+      DEPG0266BN,
       GDEH029A1,  Waveshare_2_9_bw = GDEH029A1,
       GDEW029T5,  Waveshare_2_9_bw_T5 = GDEW029T5,
       GDEW029T5D,
       GDEW029I6FD,
       GDEW029M06,
       GDEM029T94,
+      DEPG0290BS,
       GDEW027W3,  Waveshare_2_7_bw = GDEW027W3,
       ED037TC1,
       GDEW0371W7, Waveshare_3_7_bw = GDEW0371W7,
@@ -70,6 +74,7 @@ class GxEPD2
       ED060SCT, // on Waveshare IT8951 Driver HAT
       ED060KC1, // on Waveshare IT8951 Driver HAT 1448x1072
       ED078KC2, // on Waveshare IT8951 Driver HAT 1872x1404
+      ES103TC1, // on Waveshare IT8951 Driver HAT 1872x1404
       // 3-color
       GDEW0154Z04, Waveshare_1_54_bwr = GDEW0154Z04,
       GDEH0154Z90, Waveshare_1_54_bwr_Z90 = GDEH0154Z90,

+ 5 - 0
src/GxEPD2_BW.h

@@ -32,6 +32,7 @@
 
 #include "GxEPD2_EPD.h"
 #include "epd/GxEPD2_102.h"
+#include "epd/GxEPD2_150_BN.h"
 #include "epd/GxEPD2_154.h"
 #include "epd/GxEPD2_154_D67.h"
 #include "epd/GxEPD2_154_T8.h"
@@ -44,7 +45,9 @@
 #include "epd/GxEPD2_213_flex.h"
 #include "epd/GxEPD2_213_M21.h"
 #include "epd/GxEPD2_213_T5D.h"
+#include "epd/GxEPD2_213_BN.h"
 #include "epd/GxEPD2_260.h"
+#include "epd/GxEPD2_266_BN.h"
 #include "epd/GxEPD2_260_M01.h"
 #include "epd/GxEPD2_290.h"
 #include "epd/GxEPD2_290_T5.h"
@@ -53,6 +56,7 @@
 #include "epd/GxEPD2_290_M06.h"
 #include "epd/GxEPD2_290_T94.h"
 #include "epd/GxEPD2_290_T94_V2.h"
+#include "epd/GxEPD2_290_BS.h"
 #include "epd/GxEPD2_270.h"
 #include "epd/GxEPD2_371.h"
 #include "epd/GxEPD2_370_TC1.h"
@@ -67,6 +71,7 @@
 #include "it8951/GxEPD2_it60.h"
 #include "it8951/GxEPD2_it60_1448x1072.h"
 #include "it8951/GxEPD2_it78_1872x1404.h"
+#include "it8951/GxEPD2_it103_1872x1404.h"
 
 template<typename GxEPD2_Type, const uint16_t page_height>
 class GxEPD2_BW : public GxEPD2_GFX_BASE_CLASS

+ 4 - 0
src/GxEPD2_EPD.cpp

@@ -72,6 +72,10 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset
   {
     pinMode(_busy, INPUT);
   }
+  if (_dc == MISO) // may be overridden, TTGO T5 V2.66
+  {
+    pinMode(_dc, OUTPUT);
+  }
 }
 
 void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* busy_callback_parameter)

+ 405 - 0
src/epd/GxEPD2_150_BN.cpp

@@ -0,0 +1,405 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// based on Demo Example from Good Display, available here: http://www.e-paper-display.com/download_detail/downloadsId=806.html
+// Panel: GDEP0150BN : https://www.dke.top/products/dke-154-inch-small-display-modules-epd152x152-electronic-e-ink-paper-displays
+// Controller : SSD1681 : http://www.e-paper-display.com/download_detail/downloadsId=825.html
+// Display: LILYGO® TTGO T5 V2.4.1 1.50 inch : https://www.aliexpress.com/item/4000384679772.html
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#include "GxEPD2_150_BN.h"
+
+GxEPD2_150_BN::GxEPD2_150_BN(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
+  GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
+{
+}
+
+void GxEPD2_150_BN::clearScreen(uint8_t value)
+{
+  writeScreenBuffer(value);
+  refresh(true);
+  writeScreenBufferAgain(value);
+}
+
+void GxEPD2_150_BN::writeScreenBuffer(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  if (_initial_write) _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+  _initial_write = false; // initial full screen buffer clean done
+}
+
+void GxEPD2_150_BN::writeScreenBufferAgain(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+}
+
+void GxEPD2_150_BN::_writeScreenBuffer(uint8_t command, uint8_t value)
+{
+  _writeCommand(command);
+  for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
+  {
+    _writeData(value);
+  }
+}
+
+void GxEPD2_150_BN::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_150_BN::writeImageForFullRefresh(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm);
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_150_BN::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_150_BN::_writeImage(uint8_t command, const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
+  x -= x % 8; // byte boundary
+  w = wb * 8; // byte boundary
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb, h of bitmap for index!
+      int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_150_BN::writeImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_150_BN::writeImagePartAgain(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x26, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_150_BN::_writeImagePart(uint8_t command, const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
+  if ((x_part < 0) || (x_part >= w_bitmap)) return;
+  if ((y_part < 0) || (y_part >= h_bitmap)) return;
+  int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
+  x_part -= x_part % 8; // byte boundary
+  w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
+  h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
+  x -= x % 8; // byte boundary
+  w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb_bitmap, h_bitmap of bitmap for index!
+      int16_t idx = mirror_y ? x_part / 8 + j + dx / 8 + ((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + (y_part + i + dy) * wb_bitmap;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_150_BN::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_150_BN::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_150_BN::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_150_BN::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_150_BN::drawImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_150_BN::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_150_BN::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_150_BN::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_150_BN::refresh(bool partial_update_mode)
+{
+  if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
+  else
+  {
+    if (_using_partial_mode) _Init_Full();
+    _Update_Full();
+    _initial_refresh = false; // initial full update done
+  }
+}
+
+void GxEPD2_150_BN::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
+{
+  if (_initial_refresh) return refresh(false); // initial update needs be full update
+  // intersection with screen
+  int16_t w1 = x < 0 ? w + x : w; // reduce
+  int16_t h1 = y < 0 ? h + y : h; // reduce
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
+  h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
+  if ((w1 <= 0) || (h1 <= 0)) return; 
+  // make x1, w1 multiple of 8
+  w1 += x1 % 8;
+  if (w1 % 8 > 0) w1 += 8 - w1 % 8;
+  x1 -= x1 % 8;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _Update_Part();
+}
+
+void GxEPD2_150_BN::powerOff()
+{
+  _PowerOff();
+}
+
+void GxEPD2_150_BN::hibernate()
+{
+  _PowerOff();
+  if (_rst >= 0)
+  {
+    _writeCommand(0x10); // deep sleep mode
+    _writeData(0x1);     // enter deep sleep
+    _hibernating = true;
+  }
+}
+
+void GxEPD2_150_BN::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
+{
+  _writeCommand(0x11); // set ram entry mode
+  _writeData(0x03);    // x increase, y increase : normal mode
+  _writeCommand(0x44);
+  _writeData(x / 8);
+  _writeData((x + w - 1) / 8);
+  _writeCommand(0x45);
+  _writeData(y % 256);
+  _writeData(y / 256);
+  _writeData((y + h - 1) % 256);
+  _writeData((y + h - 1) / 256);
+  _writeCommand(0x4e);
+  _writeData(x / 8);
+  _writeCommand(0x4f);
+  _writeData(y % 256);
+  _writeData(y / 256);
+}
+
+void GxEPD2_150_BN::_PowerOn()
+{
+  if (!_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0xf8);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOn", power_on_time);
+  }
+  _power_is_on = true;
+}
+
+void GxEPD2_150_BN::_PowerOff()
+{
+  if (_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0x83);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOff", power_off_time);
+  }
+  _power_is_on = false;
+  _using_partial_mode = false;
+}
+
+void GxEPD2_150_BN::_InitDisplay()
+{
+  if (_hibernating) _reset();
+  delay(10); // 10ms according to specs
+  _writeCommand(0x12); // soft reset
+  delay(10); // 10ms according to specs
+  _writeCommand(0x01); // Driver output control
+  _writeData(0xC7);
+  _writeData(0x00);
+  _writeData(0x00);
+  _writeCommand(0x3C); // BorderWavefrom
+  _writeData(0x05);
+  _writeCommand(0x18); // Read built-in temperature sensor
+  _writeData(0x80);
+  _setPartialRamArea(0, 0, WIDTH, HEIGHT);
+}
+
+const unsigned char GxEPD2_150_BN::lut_partial[] PROGMEM =
+{
+    0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+    0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00,
+};
+
+void GxEPD2_150_BN::_Init_Full()
+{
+  _InitDisplay();
+  _PowerOn();
+  _using_partial_mode = false;
+}
+
+void GxEPD2_150_BN::_Init_Part()
+{
+  _InitDisplay();
+  _writeCommand(0x32);
+  _writeDataPGM(lut_partial, sizeof(lut_partial));
+  _PowerOn();
+  _using_partial_mode = true;
+}
+
+void GxEPD2_150_BN::_Update_Full()
+{
+  _writeCommand(0x22);
+  _writeData(0xf4);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Full", full_refresh_time);
+}
+
+void GxEPD2_150_BN::_Update_Part()
+{
+  _writeCommand(0x22);
+  _writeData(0xfc);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Part", partial_refresh_time);
+}

+ 85 - 0
src/epd/GxEPD2_150_BN.h

@@ -0,0 +1,85 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// based on Demo Example from Good Display, available here: http://www.e-paper-display.com/download_detail/downloadsId=806.html
+// Panel: GDEP0150BN : https://www.dke.top/products/dke-154-inch-small-display-modules-epd152x152-electronic-e-ink-paper-displays
+// Controller : SSD1681 : http://www.e-paper-display.com/download_detail/downloadsId=825.html
+// Display: LILYGO® TTGO T5 V2.4.1 1.50 inch : https://www.aliexpress.com/item/4000384679772.html
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#ifndef _GxEPD2_150_BN_H_
+#define _GxEPD2_150_BN_H_
+
+#include "../GxEPD2_EPD.h"
+
+class GxEPD2_150_BN : public GxEPD2_EPD
+{
+  public:
+    // attributes
+    static const uint16_t WIDTH = 200;
+    static const uint16_t HEIGHT = 200;
+    static const GxEPD2::Panel panel = GxEPD2::GDEP0150BN;
+    static const bool hasColor = false;
+    static const bool hasPartialUpdate = true;
+    static const bool hasFastPartialUpdate = true;
+    static const uint16_t power_on_time = 100; // ms, e.g. 94000us
+    static const uint16_t power_off_time = 150; // ms, e.g. 140000us
+    static const uint16_t full_refresh_time = 4000; // ms, e.g. 3825000us
+    static const uint16_t partial_refresh_time = 800; // ms, e.g. 736000us
+    // constructor
+    GxEPD2_150_BN(int16_t cs, int16_t dc, int16_t rst, int16_t busy);
+    // methods (virtual)
+    //  Support for Bitmaps (Sprites) to Controller Buffer and to Screen
+    void clearScreen(uint8_t value = 0xFF); // init controller memory and screen (default white)
+    void writeScreenBuffer(uint8_t value = 0xFF); // init controller memory (default white)
+    void writeScreenBufferAgain(uint8_t value = 0xFF); // init previous buffer controller memory (default white)
+    // write to controller memory, without screen refresh; x and w should be multiple of 8
+    void writeImage(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);
+    void writeImageForFullRefresh(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);
+    void writeImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // for differential update: set current and previous buffers equal (for fast partial update to work correctly)
+    void writeImageAgain(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);
+    void writeImagePartAgain(const uint8_t bitmap[], 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);
+    // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8
+    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);
+    // write to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void drawImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void refresh(bool partial_update_mode = false); // screen refresh from controller memory to full screen
+    void refresh(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, partial screen
+    void powerOff(); // turns off generation of panel driving voltages, avoids screen fading over time
+    void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)
+  private:
+    void _writeScreenBuffer(uint8_t command, uint8_t value);
+    void _writeImage(uint8_t command, 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);
+    void _writeImagePart(uint8_t command, const uint8_t bitmap[], 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);
+    void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
+    void _PowerOn();
+    void _PowerOff();
+    void _InitDisplay();
+    void _Init_Full();
+    void _Init_Part();
+    void _Update_Full();
+    void _Update_Part();
+  private:
+    static const unsigned char lut_partial[];
+};
+
+#endif

+ 410 - 0
src/epd/GxEPD2_213_BN.cpp

@@ -0,0 +1,410 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// Panel: DEPG0213BN : https://www.dke.top/products/213-eiink-display
+// Controller : SSD1680 : https://www.good-display.com/companyfile/101.html
+// Display: LILYGO® T5 V2.3.1 2.13 inch : https://www.aliexpress.com/item/32869729970.html
+//
+// Author: Jean-Marc Zingg/
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#include "GxEPD2_213_BN.h"
+
+GxEPD2_213_BN::GxEPD2_213_BN(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
+  GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
+{
+}
+
+void GxEPD2_213_BN::clearScreen(uint8_t value)
+{
+  writeScreenBuffer(value);
+  refresh(true);
+  writeScreenBufferAgain(value);
+}
+
+void GxEPD2_213_BN::writeScreenBuffer(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  if (_initial_write) _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+  _initial_write = false; // initial full screen buffer clean done
+}
+
+void GxEPD2_213_BN::writeScreenBufferAgain(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+}
+
+void GxEPD2_213_BN::_writeScreenBuffer(uint8_t command, uint8_t value)
+{
+  _writeCommand(command);
+  for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
+  {
+    _writeData(value);
+  }
+}
+
+void GxEPD2_213_BN::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_213_BN::writeImageForFullRefresh(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+
+void GxEPD2_213_BN::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_213_BN::_writeImage(uint8_t command, const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
+  x -= x % 8; // byte boundary
+  w = wb * 8; // byte boundary
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb, h of bitmap for index!
+      int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_213_BN::writeImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_213_BN::writeImagePartAgain(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x26, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_213_BN::_writeImagePart(uint8_t command, const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
+  if ((x_part < 0) || (x_part >= w_bitmap)) return;
+  if ((y_part < 0) || (y_part >= h_bitmap)) return;
+  int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
+  x_part -= x_part % 8; // byte boundary
+  w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
+  h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
+  x -= x % 8; // byte boundary
+  w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb_bitmap, h_bitmap of bitmap for index!
+      int16_t idx = mirror_y ? x_part / 8 + j + dx / 8 + ((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + (y_part + i + dy) * wb_bitmap;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_213_BN::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_213_BN::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_213_BN::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_213_BN::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_213_BN::drawImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_213_BN::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_213_BN::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_213_BN::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_213_BN::refresh(bool partial_update_mode)
+{
+  if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
+  else
+  {
+    if (_using_partial_mode) _Init_Full();
+    _Update_Full();
+    _initial_refresh = false; // initial full update done
+  }
+}
+
+void GxEPD2_213_BN::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
+{
+  if (_initial_refresh) return refresh(false); // initial update needs be full update
+  // intersection with screen
+  int16_t w1 = x < 0 ? w + x : w; // reduce
+  int16_t h1 = y < 0 ? h + y : h; // reduce
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
+  h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
+  if ((w1 <= 0) || (h1 <= 0)) return; 
+  // make x1, w1 multiple of 8
+  w1 += x1 % 8;
+  if (w1 % 8 > 0) w1 += 8 - w1 % 8;
+  x1 -= x1 % 8;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _Update_Part();
+}
+
+void GxEPD2_213_BN::powerOff()
+{
+  _PowerOff();
+}
+
+void GxEPD2_213_BN::hibernate()
+{
+  _PowerOff();
+  if (_rst >= 0)
+  {
+    _writeCommand(0x10); // deep sleep mode
+    _writeData(0x1);     // enter deep sleep
+    _hibernating = true;
+  }
+}
+
+void GxEPD2_213_BN::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
+{
+  _writeCommand(0x11); // set ram entry mode
+  _writeData(0x03);    // x increase, y increase : normal mode
+  _writeCommand(0x44);
+  _writeData(x / 8);
+  _writeData((x + w - 1) / 8);
+  _writeCommand(0x45);
+  _writeData(y % 256);
+  _writeData(y / 256);
+  _writeData((y + h - 1) % 256);
+  _writeData((y + h - 1) / 256);
+  _writeCommand(0x4e);
+  _writeData(x / 8);
+  _writeCommand(0x4f);
+  _writeData(y % 256);
+  _writeData(y / 256);
+}
+
+void GxEPD2_213_BN::_PowerOn()
+{
+  if (!_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0xf8);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOn", power_on_time);
+  }
+  _power_is_on = true;
+}
+
+void GxEPD2_213_BN::_PowerOff()
+{
+  if (_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0x83);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOff", power_off_time);
+  }
+  _power_is_on = false;
+  _using_partial_mode = false;
+}
+
+void GxEPD2_213_BN::_InitDisplay()
+{
+  if (_hibernating) _reset();
+  delay(10); // 10ms according to specs
+  _writeCommand(0x12);  //SWRESET
+  delay(10); // 10ms according to specs
+  _writeCommand(0x01); //Driver output control
+  _writeData(0x27);
+  _writeData(0x01);
+  _writeData(0x00);
+  _writeCommand(0x11); //data entry mode
+  _writeData(0x03);
+  _writeCommand(0x3C); //BorderWavefrom
+  _writeData(0x05);
+  _writeCommand(0x21); //  Display update control
+  _writeData(0x00);
+  _writeData(0x80);
+  _writeCommand(0x18); //Read built-in temperature sensor
+  _writeData(0x80);
+  _setPartialRamArea(0, 0, WIDTH, HEIGHT);
+}
+
+const unsigned char GxEPD2_213_BN::lut_partial[] PROGMEM =
+{
+  0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
+  0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
+};
+
+void GxEPD2_213_BN::_Init_Full()
+{
+  _InitDisplay();
+  _PowerOn();
+  _using_partial_mode = false;
+}
+
+void GxEPD2_213_BN::_Init_Part()
+{
+  _InitDisplay();
+  _writeCommand(0x32);
+  _writeDataPGM(lut_partial, sizeof(lut_partial));
+  _PowerOn();
+  _using_partial_mode = true;
+}
+
+void GxEPD2_213_BN::_Update_Full()
+{
+  _writeCommand(0x22);
+  _writeData(0xf4);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Full", full_refresh_time);
+}
+
+void GxEPD2_213_BN::_Update_Part()
+{
+  _writeCommand(0x22);
+  _writeData(0xcc);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Part", partial_refresh_time);
+}

+ 84 - 0
src/epd/GxEPD2_213_BN.h

@@ -0,0 +1,84 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// Panel: DEPG0213BN : https://www.dke.top/products/213-eiink-display
+// Controller : SSD1680 : https://www.good-display.com/companyfile/101.html
+// Display: LILYGO® T5 V2.3.1 2.13 inch : https://www.aliexpress.com/item/32869729970.html
+//
+// Author: Jean-Marc Zingg/
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#ifndef _GxEPD2_213_BN_H_
+#define _GxEPD2_213_BN_H_
+
+#include "../GxEPD2_EPD.h"
+
+class GxEPD2_213_BN : public GxEPD2_EPD
+{
+  public:
+    // attributes
+    static const uint16_t WIDTH = 128;
+    static const uint16_t HEIGHT = 250;
+    static const GxEPD2::Panel panel = GxEPD2::DEPG0213BN;
+    static const bool hasColor = false;
+    static const bool hasPartialUpdate = true;
+    static const bool hasFastPartialUpdate = true;
+    static const uint16_t power_on_time = 100; // ms, e.g. 95868us
+    static const uint16_t power_off_time = 250; // ms, e.g. 140350us
+    static const uint16_t full_refresh_time = 4100; // ms, e.g. 4011934us
+    static const uint16_t partial_refresh_time = 750; // ms, e.g. 736721us
+    // constructor
+    GxEPD2_213_BN(int16_t cs, int16_t dc, int16_t rst, int16_t busy);
+    // methods (virtual)
+    //  Support for Bitmaps (Sprites) to Controller Buffer and to Screen
+    void clearScreen(uint8_t value = 0xFF); // init controller memory and screen (default white)
+    void writeScreenBuffer(uint8_t value = 0xFF); // init controller memory (default white)
+    void writeScreenBufferAgain(uint8_t value = 0xFF); // init previous buffer controller memory (default white)
+    // write to controller memory, without screen refresh; x and w should be multiple of 8
+    void writeImage(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);
+    void writeImageForFullRefresh(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);
+    void writeImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // for differential update: set current and previous buffers equal (for fast partial update to work correctly)
+    void writeImageAgain(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);
+    void writeImagePartAgain(const uint8_t bitmap[], 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);
+    // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8
+    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);
+    // write to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void drawImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void refresh(bool partial_update_mode = false); // screen refresh from controller memory to full screen
+    void refresh(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, partial screen
+    void powerOff(); // turns off generation of panel driving voltages, avoids screen fading over time
+    void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)
+  private:
+    void _writeScreenBuffer(uint8_t command, uint8_t value);
+    void _writeImage(uint8_t command, 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);
+    void _writeImagePart(uint8_t command, const uint8_t bitmap[], 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);
+    void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
+    void _PowerOn();
+    void _PowerOff();
+    void _InitDisplay();
+    void _Init_Full();
+    void _Init_Part();
+    void _Update_Full();
+    void _Update_Part();
+  private:
+    static const unsigned char lut_partial[];
+};
+
+#endif

+ 413 - 0
src/epd/GxEPD2_266_BN.cpp

@@ -0,0 +1,413 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// based on Demo Example from Good Display, available here: http://www.e-paper-display.com/download_detail/downloadsId=806.html
+// Panel: DEPG0266BN : maybe https://www.dke.top/products/266-e-paper-display
+// Controller : SSD1680 : https://www.good-display.com/companyfile/101.html
+// Display: LILYGO® TTGO T5 2.66 inch E-paper Display : https://www.aliexpress.com/item/1005002474854718.html
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+//
+// note: this is a driver class variant for the Waveshare V2 board with controller without partial update wft in OTP
+
+#include "GxEPD2_266_BN.h"
+
+GxEPD2_266_BN::GxEPD2_266_BN(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
+  GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
+{
+}
+
+void GxEPD2_266_BN::clearScreen(uint8_t value)
+{
+  writeScreenBuffer(value);
+  refresh(true);
+  writeScreenBufferAgain(value);
+}
+
+void GxEPD2_266_BN::writeScreenBuffer(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  if (_initial_write) _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+  _initial_write = false; // initial full screen buffer clean done
+}
+
+void GxEPD2_266_BN::writeScreenBufferAgain(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+}
+
+void GxEPD2_266_BN::_writeScreenBuffer(uint8_t command, uint8_t value)
+{
+  _writeCommand(command);
+  for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
+  {
+    _writeData(value);
+  }
+}
+
+void GxEPD2_266_BN::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_266_BN::writeImageForFullRefresh(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+
+void GxEPD2_266_BN::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_266_BN::_writeImage(uint8_t command, const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
+  x -= x % 8; // byte boundary
+  w = wb * 8; // byte boundary
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb, h of bitmap for index!
+      int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_266_BN::writeImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_266_BN::writeImagePartAgain(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x26, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_266_BN::_writeImagePart(uint8_t command, const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
+  if ((x_part < 0) || (x_part >= w_bitmap)) return;
+  if ((y_part < 0) || (y_part >= h_bitmap)) return;
+  int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
+  x_part -= x_part % 8; // byte boundary
+  w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
+  h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
+  x -= x % 8; // byte boundary
+  w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb_bitmap, h_bitmap of bitmap for index!
+      int16_t idx = mirror_y ? x_part / 8 + j + dx / 8 + ((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + (y_part + i + dy) * wb_bitmap;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_266_BN::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_266_BN::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_266_BN::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_266_BN::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_266_BN::drawImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_266_BN::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_266_BN::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_266_BN::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_266_BN::refresh(bool partial_update_mode)
+{
+  if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
+  else
+  {
+    if (_using_partial_mode) _Init_Full();
+    _Update_Full();
+    _initial_refresh = false; // initial full update done
+  }
+}
+
+void GxEPD2_266_BN::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
+{
+  if (_initial_refresh) return refresh(false); // initial update needs be full update
+  // intersection with screen
+  int16_t w1 = x < 0 ? w + x : w; // reduce
+  int16_t h1 = y < 0 ? h + y : h; // reduce
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
+  h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  // make x1, w1 multiple of 8
+  w1 += x1 % 8;
+  if (w1 % 8 > 0) w1 += 8 - w1 % 8;
+  x1 -= x1 % 8;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _Update_Part();
+}
+
+void GxEPD2_266_BN::powerOff()
+{
+  _PowerOff();
+}
+
+void GxEPD2_266_BN::hibernate()
+{
+  _PowerOff();
+  if (_rst >= 0)
+  {
+    _writeCommand(0x10); // deep sleep mode
+    _writeData(0x1);     // enter deep sleep
+    _hibernating = true;
+  }
+}
+
+void GxEPD2_266_BN::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
+{
+  _writeCommand(0x11); // set ram entry mode
+  _writeData(0x03);    // x increase, y increase : normal mode
+  _writeCommand(0x44);
+  _writeData(x / 8);
+  _writeData((x + w - 1) / 8);
+  _writeCommand(0x45);
+  _writeData(y % 256);
+  _writeData(y / 256);
+  _writeData((y + h - 1) % 256);
+  _writeData((y + h - 1) / 256);
+  _writeCommand(0x4e);
+  _writeData(x / 8);
+  _writeCommand(0x4f);
+  _writeData(y % 256);
+  _writeData(y / 256);
+}
+
+void GxEPD2_266_BN::_PowerOn()
+{
+  if (!_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0xf8);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOn", power_on_time);
+  }
+  _power_is_on = true;
+}
+
+void GxEPD2_266_BN::_PowerOff()
+{
+  if (_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0x83);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOff", power_off_time);
+  }
+  _power_is_on = false;
+  _using_partial_mode = false;
+}
+
+void GxEPD2_266_BN::_InitDisplay()
+{
+  if (_hibernating) _reset();
+  delay(10); // 10ms according to specs
+  _writeCommand(0x12);  //SWRESET
+  delay(10); // 10ms according to specs
+  _writeCommand(0x01); //Driver output control
+  _writeData(0x27);
+  _writeData(0x01);
+  _writeData(0x00);
+  _writeCommand(0x11); //data entry mode
+  _writeData(0x03);
+  _writeCommand(0x3C); //BorderWavefrom
+  _writeData(0x05);
+  _writeCommand(0x21); //  Display update control
+  _writeData(0x00);
+  _writeData(0x80);
+  _writeCommand(0x18); //Read built-in temperature sensor
+  _writeData(0x80);
+  _setPartialRamArea(0, 0, WIDTH, HEIGHT);
+}
+
+const unsigned char GxEPD2_266_BN::lut_partial[] PROGMEM =
+{
+  0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
+  0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
+};
+
+void GxEPD2_266_BN::_Init_Full()
+{
+  _InitDisplay();
+  _PowerOn();
+  _using_partial_mode = false;
+}
+
+void GxEPD2_266_BN::_Init_Part()
+{
+  _InitDisplay();
+  _writeCommand(0x32);
+  _writeDataPGM(lut_partial, sizeof(lut_partial));
+  _PowerOn();
+  _using_partial_mode = true;
+}
+
+void GxEPD2_266_BN::_Update_Full()
+{
+  _writeCommand(0x22);
+  _writeData(0xf4);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Full", full_refresh_time);
+}
+
+void GxEPD2_266_BN::_Update_Part()
+{
+  _writeCommand(0x22);
+  _writeData(0xcc);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Part", partial_refresh_time);
+}

+ 85 - 0
src/epd/GxEPD2_266_BN.h

@@ -0,0 +1,85 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// based on Demo Example from Good Display, available here: http://www.e-paper-display.com/download_detail/downloadsId=806.html
+// Panel: DEPG0266BN : maybe https://www.dke.top/products/266-e-paper-display
+// Controller : SSD1680 : https://www.good-display.com/companyfile/101.html
+// Display: LILYGO® TTGO T5 2.66 inch E-paper Display : https://www.aliexpress.com/item/1005002474854718.html
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#ifndef _GxEPD2_266_BN_H_
+#define _GxEPD2_266_BN_H_
+
+#include "../GxEPD2_EPD.h"
+
+class GxEPD2_266_BN : public GxEPD2_EPD
+{
+  public:
+    // attributes
+    static const uint16_t WIDTH = 152;
+    static const uint16_t HEIGHT = 296;
+    static const GxEPD2::Panel panel = GxEPD2::DEPG0266BN;
+    static const bool hasColor = false;
+    static const bool hasPartialUpdate = true;
+    static const bool hasFastPartialUpdate = true;
+    static const uint16_t power_on_time = 100; // ms, e.g. 95000us
+    static const uint16_t power_off_time = 150; // ms, e.g. 141000us
+    static const uint16_t full_refresh_time = 4000; // ms, e.g. 3854000us
+    static const uint16_t partial_refresh_time = 800; // ms, e.g. 738000us
+    // constructor
+    GxEPD2_266_BN(int16_t cs, int16_t dc, int16_t rst, int16_t busy);
+    // methods (virtual)
+    //  Support for Bitmaps (Sprites) to Controller Buffer and to Screen
+    void clearScreen(uint8_t value = 0xFF); // init controller memory and screen (default white)
+    void writeScreenBuffer(uint8_t value = 0xFF); // init controller memory (default white)
+    void writeScreenBufferAgain(uint8_t value = 0xFF); // init previous buffer controller memory (default white)
+    // write to controller memory, without screen refresh; x and w should be multiple of 8
+    void writeImage(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);
+    void writeImageForFullRefresh(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);
+    void writeImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // for differential update: set current and previous buffers equal (for fast partial update to work correctly)
+    void writeImageAgain(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);
+    void writeImagePartAgain(const uint8_t bitmap[], 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);
+    // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8
+    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);
+    // write to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void drawImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void refresh(bool partial_update_mode = false); // screen refresh from controller memory to full screen
+    void refresh(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, partial screen
+    void powerOff(); // turns off generation of panel driving voltages, avoids screen fading over time
+    void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)
+  private:
+    void _writeScreenBuffer(uint8_t command, uint8_t value);
+    void _writeImage(uint8_t command, 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);
+    void _writeImagePart(uint8_t command, const uint8_t bitmap[], 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);
+    void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
+    void _PowerOn();
+    void _PowerOff();
+    void _InitDisplay();
+    void _Init_Full();
+    void _Init_Part();
+    void _Update_Full();
+    void _Update_Part();
+  private:
+    static const unsigned char lut_partial[];
+};
+
+#endif

+ 413 - 0
src/epd/GxEPD2_290_BS.cpp

@@ -0,0 +1,413 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// based on Demo Example from Good Display, available here: http://www.e-paper-display.com/download_detail/downloadsId=806.html
+// Panel: DEPG0290BS : https://www.dke.top/products/dke-small-e-ink-paper-display-29-inch-296x128-for-esl
+// Controller : SSD1680 : https://www.good-display.com/companyfile/101.html
+// Display: LILYGO® TTGO T5 V2.4.1 2.9" b/w : https://www.aliexpress.com/item/4000384679772.html
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+//
+// note: this is a driver class variant for the Waveshare V2 board with controller without partial update wft in OTP
+
+#include "GxEPD2_290_BS.h"
+
+GxEPD2_290_BS::GxEPD2_290_BS(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
+  GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
+{
+}
+
+void GxEPD2_290_BS::clearScreen(uint8_t value)
+{
+  writeScreenBuffer(value);
+  refresh(true);
+  writeScreenBufferAgain(value);
+}
+
+void GxEPD2_290_BS::writeScreenBuffer(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  if (_initial_write) _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+  _initial_write = false; // initial full screen buffer clean done
+}
+
+void GxEPD2_290_BS::writeScreenBufferAgain(uint8_t value)
+{
+  if (!_using_partial_mode) _Init_Part();
+  _writeScreenBuffer(0x26, value); // set previous
+  _writeScreenBuffer(0x24, value); // set current
+}
+
+void GxEPD2_290_BS::_writeScreenBuffer(uint8_t command, uint8_t value)
+{
+  _writeCommand(command);
+  for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
+  {
+    _writeData(value);
+  }
+}
+
+void GxEPD2_290_BS::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_290_BS::writeImageForFullRefresh(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+
+void GxEPD2_290_BS::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_290_BS::_writeImage(uint8_t command, const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
+  x -= x % 8; // byte boundary
+  w = wb * 8; // byte boundary
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb, h of bitmap for index!
+      int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_290_BS::writeImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_290_BS::writeImagePartAgain(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  _writeImagePart(0x26, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous
+  _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); // set current
+}
+
+void GxEPD2_290_BS::_writeImagePart(uint8_t command, const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
+  if ((x_part < 0) || (x_part >= w_bitmap)) return;
+  if ((y_part < 0) || (y_part >= h_bitmap)) return;
+  int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
+  x_part -= x_part % 8; // byte boundary
+  w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
+  h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
+  x -= x % 8; // byte boundary
+  w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _writeCommand(command);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb_bitmap, h_bitmap of bitmap for index!
+      int16_t idx = mirror_y ? x_part / 8 + j + dx / 8 + ((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + (y_part + i + dy) * wb_bitmap;
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _writeData(data);
+    }
+  }
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_290_BS::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_290_BS::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_290_BS::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_290_BS::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_290_BS::drawImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  refresh(x, y, w, h);
+  writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+}
+
+void GxEPD2_290_BS::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_290_BS::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_290_BS::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_290_BS::refresh(bool partial_update_mode)
+{
+  if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
+  else
+  {
+    if (_using_partial_mode) _Init_Full();
+    _Update_Full();
+    _initial_refresh = false; // initial full update done
+  }
+}
+
+void GxEPD2_290_BS::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
+{
+  if (_initial_refresh) return refresh(false); // initial update needs be full update
+  // intersection with screen
+  int16_t w1 = x < 0 ? w + x : w; // reduce
+  int16_t h1 = y < 0 ? h + y : h; // reduce
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
+  h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
+  if ((w1 <= 0) || (h1 <= 0)) return; 
+  // make x1, w1 multiple of 8
+  w1 += x1 % 8;
+  if (w1 % 8 > 0) w1 += 8 - w1 % 8;
+  x1 -= x1 % 8;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  _Update_Part();
+}
+
+void GxEPD2_290_BS::powerOff()
+{
+  _PowerOff();
+}
+
+void GxEPD2_290_BS::hibernate()
+{
+  _PowerOff();
+  if (_rst >= 0)
+  {
+    _writeCommand(0x10); // deep sleep mode
+    _writeData(0x1);     // enter deep sleep
+    _hibernating = true;
+  }
+}
+
+void GxEPD2_290_BS::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
+{
+  _writeCommand(0x11); // set ram entry mode
+  _writeData(0x03);    // x increase, y increase : normal mode
+  _writeCommand(0x44);
+  _writeData(x / 8);
+  _writeData((x + w - 1) / 8);
+  _writeCommand(0x45);
+  _writeData(y % 256);
+  _writeData(y / 256);
+  _writeData((y + h - 1) % 256);
+  _writeData((y + h - 1) / 256);
+  _writeCommand(0x4e);
+  _writeData(x / 8);
+  _writeCommand(0x4f);
+  _writeData(y % 256);
+  _writeData(y / 256);
+}
+
+void GxEPD2_290_BS::_PowerOn()
+{
+  if (!_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0xf8);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOn", power_on_time);
+  }
+  _power_is_on = true;
+}
+
+void GxEPD2_290_BS::_PowerOff()
+{
+  if (_power_is_on)
+  {
+    _writeCommand(0x22);
+    _writeData(0x83);
+    _writeCommand(0x20);
+    _waitWhileBusy("_PowerOff", power_off_time);
+  }
+  _power_is_on = false;
+  _using_partial_mode = false;
+}
+
+void GxEPD2_290_BS::_InitDisplay()
+{
+  if (_hibernating) _reset();
+  delay(10); // 10ms according to specs
+  _writeCommand(0x12);  //SWRESET
+  delay(10); // 10ms according to specs
+  _writeCommand(0x01); //Driver output control
+  _writeData(0x27);
+  _writeData(0x01);
+  _writeData(0x00);
+  _writeCommand(0x11); //data entry mode
+  _writeData(0x03);
+  _writeCommand(0x3C); //BorderWavefrom
+  _writeData(0x05);
+  _writeCommand(0x21); //  Display update control
+  _writeData(0x00);
+  _writeData(0x80);
+  _writeCommand(0x18); //Read built-in temperature sensor
+  _writeData(0x80);
+  _setPartialRamArea(0, 0, WIDTH, HEIGHT);
+}
+
+const unsigned char GxEPD2_290_BS::lut_partial[] PROGMEM =
+{
+  0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0A, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2,
+  0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+  0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
+};
+
+void GxEPD2_290_BS::_Init_Full()
+{
+  _InitDisplay();
+  _PowerOn();
+  _using_partial_mode = false;
+}
+
+void GxEPD2_290_BS::_Init_Part()
+{
+  _InitDisplay();
+  _writeCommand(0x32);
+  _writeDataPGM(lut_partial, sizeof(lut_partial));
+  _PowerOn();
+  _using_partial_mode = true;
+}
+
+void GxEPD2_290_BS::_Update_Full()
+{
+  _writeCommand(0x22);
+  _writeData(0xf4);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Full", full_refresh_time);
+}
+
+void GxEPD2_290_BS::_Update_Part()
+{
+  _writeCommand(0x22);
+  _writeData(0xcc);
+  _writeCommand(0x20);
+  _waitWhileBusy("_Update_Part", partial_refresh_time);
+}

+ 85 - 0
src/epd/GxEPD2_290_BS.h

@@ -0,0 +1,85 @@
+// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
+// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
+//
+// based on Demo Example from Good Display, available here: http://www.e-paper-display.com/download_detail/downloadsId=806.html
+// Panel: DEPG0290BS : https://www.dke.top/products/dke-small-e-ink-paper-display-29-inch-296x128-for-esl
+// Controller : SSD1680 : https://www.good-display.com/companyfile/101.html
+// Display: LILYGO® TTGO T5 V2.4.1 2.9" b/w : https://www.aliexpress.com/item/4000384679772.html
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#ifndef _GxEPD2_290_BS_H_
+#define _GxEPD2_290_BS_H_
+
+#include "../GxEPD2_EPD.h"
+
+class GxEPD2_290_BS : public GxEPD2_EPD
+{
+  public:
+    // attributes
+    static const uint16_t WIDTH = 128;
+    static const uint16_t HEIGHT = 296;
+    static const GxEPD2::Panel panel = GxEPD2::DEPG0290BS;
+    static const bool hasColor = false;
+    static const bool hasPartialUpdate = true;
+    static const bool hasFastPartialUpdate = true;
+    static const uint16_t power_on_time = 100; // ms, e.g. 95000us
+    static const uint16_t power_off_time = 150; // ms, e.g. 141000us
+    static const uint16_t full_refresh_time = 4000; // ms, e.g. 3839000us
+    static const uint16_t partial_refresh_time = 750; // ms, e.g. 735000us
+    // constructor
+    GxEPD2_290_BS(int16_t cs, int16_t dc, int16_t rst, int16_t busy);
+    // methods (virtual)
+    //  Support for Bitmaps (Sprites) to Controller Buffer and to Screen
+    void clearScreen(uint8_t value = 0xFF); // init controller memory and screen (default white)
+    void writeScreenBuffer(uint8_t value = 0xFF); // init controller memory (default white)
+    void writeScreenBufferAgain(uint8_t value = 0xFF); // init previous buffer controller memory (default white)
+    // write to controller memory, without screen refresh; x and w should be multiple of 8
+    void writeImage(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);
+    void writeImageForFullRefresh(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);
+    void writeImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // for differential update: set current and previous buffers equal (for fast partial update to work correctly)
+    void writeImageAgain(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);
+    void writeImagePartAgain(const uint8_t bitmap[], 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);
+    // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8
+    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);
+    // write to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void drawImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void refresh(bool partial_update_mode = false); // screen refresh from controller memory to full screen
+    void refresh(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, partial screen
+    void powerOff(); // turns off generation of panel driving voltages, avoids screen fading over time
+    void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)
+  private:
+    void _writeScreenBuffer(uint8_t command, uint8_t value);
+    void _writeImage(uint8_t command, 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);
+    void _writeImagePart(uint8_t command, const uint8_t bitmap[], 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);
+    void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
+    void _PowerOn();
+    void _PowerOff();
+    void _InitDisplay();
+    void _Init_Full();
+    void _Init_Part();
+    void _Update_Full();
+    void _Update_Part();
+  private:
+    static const unsigned char lut_partial[];
+};
+
+#endif

+ 680 - 0
src/it8951/GxEPD2_it103_1872x1404.cpp

@@ -0,0 +1,680 @@
+// Display Library 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!
+//
+// GxEPD2_it103_1872x1404 class is based on Demo Example from Waveshare for Raspberry PI https://github.com/waveshare/IT8951/archive/master.zip
+// Controller: IT8951 : https://www.waveshare.com/w/upload/1/18/IT8951_D_V0.2.4.3_20170728.pdf
+//
+// The GxEPD2_it103_1872x1404 driver class supports the Waveshare e-Paper IT8951 Driver HAT connected with SPI for the ES103TC1 10.3" e-paper panel (parallel IF)
+// https://www.waveshare.com/product/displays/e-paper/epaper-1/10.3inch-e-paper-d.htm
+// This Driver HAT requires 5V power supply but works with 3.3V data lines; requires both MOSI and MISO SPI lines.
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#include "GxEPD2_it103_1872x1404.h"
+
+//#define VCOM  1500 //mV e.g. -1.53 = 1530 = 0x5FA
+#define VCOM  2330 //mV -2.33V as of sticker on my panel
+
+//Built in I80 Command Code
+#define IT8951_TCON_SYS_RUN      0x0001
+#define IT8951_TCON_STANDBY      0x0002
+#define IT8951_TCON_SLEEP        0x0003
+#define IT8951_TCON_REG_RD       0x0010
+#define IT8951_TCON_REG_WR       0x0011
+#define IT8951_TCON_LD_IMG       0x0020
+#define IT8951_TCON_LD_IMG_AREA  0x0021
+#define IT8951_TCON_LD_IMG_END   0x0022
+
+//I80 User defined command code
+#define USDEF_I80_CMD_DPY_AREA     0x0034
+#define USDEF_I80_CMD_GET_DEV_INFO 0x0302
+#define USDEF_I80_CMD_DPY_BUF_AREA 0x0037
+#define USDEF_I80_CMD_VCOM       0x0039
+
+//Rotate mode
+#define IT8951_ROTATE_0     0
+#define IT8951_ROTATE_90    1
+#define IT8951_ROTATE_180   2
+#define IT8951_ROTATE_270   3
+
+//Pixel mode , BPP - Bit per Pixel
+#define IT8951_2BPP   0
+#define IT8951_3BPP   1
+#define IT8951_4BPP   2
+#define IT8951_8BPP   3
+
+//Endian Type
+#define IT8951_LDIMG_L_ENDIAN   0
+#define IT8951_LDIMG_B_ENDIAN   1
+
+#define SYS_REG_BASE 0x0000
+#define I80CPCR (SYS_REG_BASE + 0x04)
+#define MCSR_BASE_ADDR 0x0200
+#define LISAR (MCSR_BASE_ADDR + 0x0008)
+
+GxEPD2_it103_1872x1404::GxEPD2_it103_1872x1404(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
+  GxEPD2_EPD(cs, dc, rst, busy, LOW, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
+  _spi_settings(24000000, MSBFIRST, SPI_MODE0),
+  _spi_settings_for_read(1000000, MSBFIRST, SPI_MODE0)
+{
+}
+
+void GxEPD2_it103_1872x1404::init(uint32_t serial_diag_bitrate)
+{
+  init(serial_diag_bitrate, true, 20, false);
+}
+
+void GxEPD2_it103_1872x1404::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode)
+{
+  GxEPD2_EPD::init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
+
+  // we need a long reset pulse
+  if (_rst >= 0)
+  {
+    digitalWrite(_rst, LOW);
+    delay(200);
+    digitalWrite(_rst, HIGH);
+    delay(200);
+    _waitWhileBusy("init reset_to_ready", reset_to_ready_time);
+  }
+
+  _writeCommand16(USDEF_I80_CMD_GET_DEV_INFO);
+  _waitWhileBusy("GetIT8951SystemInfo", power_on_time);
+  _readData16((uint16_t*)&IT8951DevInfo, sizeof(IT8951DevInfo) / 2);
+  if (_diag_enabled)
+  {
+    //Show Device information of IT8951
+    printf("Panel(W,H) = (%d,%d)\r\n",
+           IT8951DevInfo.usPanelW, IT8951DevInfo.usPanelH );
+    printf("Image Buffer Address = %lX\r\n",
+           uint32_t(IT8951DevInfo.usImgBufAddrL) | (uint32_t(IT8951DevInfo.usImgBufAddrH) << 16));
+    //Show Firmware and LUT Version
+    printf("FW Version = %s\r\n", (uint8_t*)IT8951DevInfo.usFWVersion);
+    printf("LUT Version = %s\r\n", (uint8_t*)IT8951DevInfo.usLUTVersion);
+  }
+  //Set to Enable I80 Packed mode
+  _IT8951WriteReg(I80CPCR, 0x0001);
+  if (VCOM != _IT8951GetVCOM())
+  {
+    _IT8951SetVCOM(VCOM);
+    printf("VCOM = -%.02fV\n", (double)_IT8951GetVCOM() / 1000);
+  }
+  printf("VCOM = -%.02fV\n", (double)_IT8951GetVCOM() / 1000);
+}
+
+void GxEPD2_it103_1872x1404::clearScreen(uint8_t value)
+{
+  _initial_write = false; // initial full screen buffer clean done
+  if (_initial_refresh) _Init_Full();
+  else _Init_Part();
+  _initial_refresh = false;
+  _setPartialRamArea(0, 0, WIDTH, HEIGHT);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x0000); // preamble for write data
+  _waitWhileBusy2("clearScreen preamble", default_wait_time);
+  for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT); i++)
+  {
+    SPI.transfer(value);
+#if defined(ESP8266) || defined(ESP32)
+    if (0 == i % 10000) yield();
+#endif
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+  _writeCommand16(IT8951_TCON_LD_IMG_END);
+  _waitWhileBusy2("clearScreen load end", default_wait_time);
+  _refresh(0, 0, WIDTH, HEIGHT, false);
+}
+
+void GxEPD2_it103_1872x1404::writeScreenBuffer(uint8_t value)
+{
+  if (_initial_refresh) clearScreen(value);
+  else _writeScreenBuffer(value);
+}
+
+void GxEPD2_it103_1872x1404::_writeScreenBuffer(uint8_t value)
+{
+  _initial_write = false; // initial full screen buffer clean done
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(0, 0, WIDTH, HEIGHT);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x0000); // preamble for write data
+  _waitWhileBusy2("clearScreen preamble", default_wait_time);
+  for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT); i++)
+  {
+    SPI.transfer(value);
+#if defined(ESP8266) || defined(ESP32)
+    if (0 == i % 10000) yield();
+#endif
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+  _writeCommand16(IT8951_TCON_LD_IMG_END);
+  _waitWhileBusy2("_writeScreenBuffer load end", default_wait_time);
+}
+
+void GxEPD2_it103_1872x1404::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
+  x -= x % 8; // byte boundary
+  w = wb * 8; // byte boundary
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x0000); // preamble for write data
+  _waitWhileBusy2("writeImage preamble", default_wait_time);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb, h of bitmap for index!
+      uint32_t idx = mirror_y ? uint32_t(j + dx / 8) + uint32_t((h - 1 - (i + dy))) * uint32_t(wb) : uint32_t(j + dx / 8) + uint32_t(i + dy) * uint32_t(wb);
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _send8pixel(~data);
+    }
+#if defined(ESP8266) || defined(ESP32)
+    yield();
+#endif
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+  _writeCommand16(IT8951_TCON_LD_IMG_END);
+  _waitWhileBusy2("writeImage load end", default_wait_time);
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_it103_1872x1404::writeImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
+  if ((x_part < 0) || (x_part >= w_bitmap)) return;
+  if ((y_part < 0) || (y_part >= h_bitmap)) return;
+  int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
+  x_part -= x_part % 8; // byte boundary
+  w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
+  h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
+  x -= x % 8; // byte boundary
+  w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  int16_t dx = x1 - x;
+  int16_t dy = y1 - y;
+  w1 -= dx;
+  h1 -= dy;
+  if ((w1 <= 0) || (h1 <= 0)) return;
+  if (!_using_partial_mode) _Init_Part();
+  _setPartialRamArea(x1, y1, w1, h1);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x0000); // preamble for write data
+  _waitWhileBusy2("writeImage preamble", default_wait_time);
+  for (int16_t i = 0; i < h1; i++)
+  {
+    for (int16_t j = 0; j < w1 / 8; j++)
+    {
+      uint8_t data;
+      // use wb_bitmap, h_bitmap of bitmap for index!
+      uint32_t idx = mirror_y ? x_part / 8 + (j + dx / 8) + uint32_t((h_bitmap - 1 - (y_part + i + dy))) * uint32_t(wb_bitmap) : x_part / 8 + j + dx / 8 + uint32_t(y_part + i + dy) * uint32_t(wb_bitmap);
+      if (pgm)
+      {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+        data = pgm_read_byte(&bitmap[idx]);
+#else
+        data = bitmap[idx];
+#endif
+      }
+      else
+      {
+        data = bitmap[idx];
+      }
+      if (invert) data = ~data;
+      _send8pixel(~data);
+    }
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+  _writeCommand16(IT8951_TCON_LD_IMG_END);
+  _waitWhileBusy2("writeImage load end", default_wait_time);
+  delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+}
+
+void GxEPD2_it103_1872x1404::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImage(black, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_it103_1872x1404::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, bool mirror_y, bool pgm)
+{
+  if (black)
+  {
+    writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  }
+}
+
+void GxEPD2_it103_1872x1404::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  if (data1)
+  {
+    if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
+    delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+    int16_t x1 = x < 0 ? 0 : x; // limit
+    int16_t y1 = y < 0 ? 0 : y; // limit
+    int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+    int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+    int16_t dx = x1 - x;
+    int16_t dy = y1 - y;
+    w1 -= dx;
+    h1 -= dy;
+    if ((w1 <= 0) || (h1 <= 0)) return;
+    if (!_using_partial_mode) _Init_Part();
+    _setPartialRamArea(x1, y1, w1, h1);
+    SPI.beginTransaction(_spi_settings);
+    if (_cs >= 0) digitalWrite(_cs, LOW);
+    _transfer16(0x0000); // preamble for write data
+    _waitWhileBusy2("writeNative preamble", default_wait_time);
+    for (int16_t i = 0; i < h1; i++)
+    {
+      for (int16_t j = 0; j < w1; j++)
+      {
+        uint8_t data;
+        // use w, h of bitmap for index!
+        uint32_t idx = mirror_y ? uint32_t(j + dx) + uint32_t((h - 1 - (i + dy))) * uint32_t(w) : uint32_t(j + dx) + uint32_t(i + dy) * uint32_t(w);
+        if (pgm)
+        {
+#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
+          data = pgm_read_byte(&data1[idx]);
+#else
+          data = data1[idx];
+#endif
+        }
+        else
+        {
+          data = data1[idx];
+        }
+        if (invert) data = ~data;
+        SPI.transfer(data);
+      }
+#if defined(ESP8266) || defined(ESP32)
+      yield();
+#endif
+    }
+    if (_cs >= 0) digitalWrite(_cs, HIGH);
+    SPI.endTransaction();
+    _writeCommand16(IT8951_TCON_LD_IMG_END);
+    _waitWhileBusy2("writeNative load end", default_wait_time);
+    delay(1); // yield() to avoid WDT on ESP8266 and ESP32
+  }
+}
+
+void GxEPD2_it103_1872x1404::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
+  _refresh(x, y, w, h, true);
+}
+
+void GxEPD2_it103_1872x1404::drawImagePart(const uint8_t bitmap[], 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, bool mirror_y, bool pgm)
+{
+  writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  _refresh(x, y, w, h, true);
+}
+
+void GxEPD2_it103_1872x1404::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
+  _refresh(x, y, w, h, true);
+}
+
+void GxEPD2_it103_1872x1404::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, bool mirror_y, bool pgm)
+{
+  writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
+  _refresh(x, y, w, h, true);
+}
+
+void GxEPD2_it103_1872x1404::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
+{
+  writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
+  _refresh(x, y, w, h, false);
+}
+
+void GxEPD2_it103_1872x1404::refresh(bool partial_update_mode)
+{
+  _refresh(0, 0, WIDTH, HEIGHT, partial_update_mode);
+}
+
+void GxEPD2_it103_1872x1404::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
+{
+  _refresh(x, y, w, h, true);
+}
+
+void GxEPD2_it103_1872x1404::_refresh(int16_t x, int16_t y, int16_t w, int16_t h, bool partial_update_mode)
+{
+  //x -= x % 8; // byte boundary
+  //w -= x % 8; // byte boundary
+  int16_t x1 = x < 0 ? 0 : x; // limit
+  int16_t y1 = y < 0 ? 0 : y; // limit
+  int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
+  int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
+  w1 -= x1 - x;
+  h1 -= y1 - y;
+  //Send I80 Display Command (User defined command of IT8951)
+  _writeCommand16(USDEF_I80_CMD_DPY_AREA); //0x0034
+  _waitWhileBusy2("refresh cmd", refresh_cmd_time);
+  //Write arguments
+  _writeData16(x1);
+  _waitWhileBusy2("refresh x", refresh_par_time);
+  _writeData16(y1);
+  _waitWhileBusy2("refresh y", refresh_par_time);
+  _writeData16(w1);
+  _waitWhileBusy2("refresh w", refresh_par_time);
+  _writeData16(h1);
+  _waitWhileBusy2("refresh h", refresh_par_time);
+  _writeData16(partial_update_mode ? 1 : 2); // mode
+  _waitWhileBusy("refresh", full_refresh_time);
+}
+
+void GxEPD2_it103_1872x1404::powerOff(void)
+{
+  _PowerOff();
+}
+
+void GxEPD2_it103_1872x1404::hibernate()
+{
+  if (_power_is_on) _PowerOff();
+  if (_rst >= 0)
+  {
+    // this does not work, does not reduce power, uses more than in stand by mode
+    //delay(1000);
+    //_IT8951Sleep();
+    //delay(1000);
+    //_hibernating = true;
+  }
+}
+
+void GxEPD2_it103_1872x1404::_send8pixel(uint8_t data)
+{
+  for (uint8_t j = 0; j < 8; j++)
+  {
+    SPI.transfer(data & 0x80 ? 0x00 : 0xFF);
+    data <<= 1;
+  }
+}
+
+void GxEPD2_it103_1872x1404::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
+{
+  //_IT8951WriteReg(LISAR + 2 , IT8951DevInfo.usImgBufAddrH);
+  //_IT8951WriteReg(LISAR , IT8951DevInfo.usImgBufAddrL);
+  uint16_t usArg[5];
+  //usArg[0] = (IT8951_LDIMG_L_ENDIAN << 8 ) | (IT8951_8BPP << 4) | (IT8951_ROTATE_0);
+  usArg[0] = (IT8951_LDIMG_B_ENDIAN << 8 ) | (IT8951_8BPP << 4) | (IT8951_ROTATE_0);
+  usArg[1] = x;
+  usArg[2] = y;
+  usArg[3] = w;
+  usArg[4] = h;
+  _writeCommandData16(IT8951_TCON_LD_IMG_AREA , usArg , 5);
+}
+
+void GxEPD2_it103_1872x1404::_PowerOn()
+{
+  if (!_power_is_on)
+  {
+    _IT8951SystemRun();
+    _waitWhileBusy("_PowerOn", power_on_time);
+  }
+  _power_is_on = true;
+}
+
+void GxEPD2_it103_1872x1404::_PowerOff()
+{
+  _IT8951StandBy();
+  _waitWhileBusy("_PowerOff", power_off_time);
+  _power_is_on = false;
+  _using_partial_mode = false;
+}
+
+void GxEPD2_it103_1872x1404::_InitDisplay()
+{
+  // we need a long reset pulse
+  if (_hibernating && (_rst >= 0))
+  {
+    digitalWrite(_rst, LOW);
+    delay(200);
+    digitalWrite(_rst, HIGH);
+    delay(200);
+  }
+}
+
+void GxEPD2_it103_1872x1404::_Init_Full()
+{
+  _InitDisplay();
+  _PowerOn();
+  _using_partial_mode = false;
+}
+
+void GxEPD2_it103_1872x1404::_Init_Part()
+{
+  _InitDisplay();
+  _PowerOn();
+  _using_partial_mode = true;
+}
+
+void GxEPD2_it103_1872x1404::_waitWhileBusy2(const char* comment, uint16_t busy_time)
+{
+  if (_busy >= 0)
+  {
+    unsigned long start = micros();
+    while (1)
+    {
+      if (digitalRead(_busy) != _busy_level) break;
+      delay(1);
+      if (micros() - start > _busy_timeout)
+      {
+        Serial.println("Busy Timeout!");
+        break;
+      }
+    }
+    if (comment)
+    {
+#if !defined(DISABLE_DIAGNOSTIC_OUTPUT)
+      if (_diag_enabled)
+      {
+        unsigned long elapsed = micros() - start;
+        if (elapsed > diag_min_time * 1000)
+        {
+          Serial.print(comment);
+          Serial.print(" : ");
+          Serial.println(elapsed);
+        }
+      }
+#endif
+    }
+    (void) start;
+  }
+  else delay(busy_time);
+}
+
+uint16_t GxEPD2_it103_1872x1404::_transfer16(uint16_t value)
+{
+  uint16_t rv = SPI.transfer(value >> 8) << 8;
+  return (rv | SPI.transfer(value));
+}
+
+void GxEPD2_it103_1872x1404::_writeCommand16(uint16_t c)
+{
+  String s = String("_writeCommand16(0x") + String(c, HEX) + String(")");
+  _waitWhileBusy2(s.c_str(), default_wait_time);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x6000); // preamble for write command
+  _waitWhileBusy2("_writeCommand16 preamble", default_wait_time);
+  _transfer16(c);
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+  //_waitWhileBusy(s.c_str(), default_wait_time);
+}
+
+void GxEPD2_it103_1872x1404::_writeData16(uint16_t d)
+{
+  _waitWhileBusy2("_writeData16", default_wait_time);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x0000); // preamble for write data
+  _waitWhileBusy2("_writeData16 preamble", default_wait_time);
+  _transfer16(d);
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+}
+
+void GxEPD2_it103_1872x1404::_writeData16(const uint16_t* d, uint32_t n)
+{
+  _waitWhileBusy2("_writeData16", default_wait_time);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x0000); // preamble for write data
+  _waitWhileBusy2("_writeData16 preamble", default_wait_time);
+  for (uint32_t i = 0; i < n; i++)
+  {
+    _transfer16(*d++);
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+}
+
+uint16_t GxEPD2_it103_1872x1404::_readData16()
+{
+  _waitWhileBusy2("_readData16", default_wait_time);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x1000); // preamble for read data
+  _waitWhileBusy2("_readData16 preamble", default_wait_time);
+  _transfer16(0); // dummy
+  _waitWhileBusy2("_readData16 dummy", default_wait_time);
+  uint16_t rv = _transfer16(0);
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+  return rv;
+}
+
+void GxEPD2_it103_1872x1404::_readData16(uint16_t* d, uint32_t n)
+{
+  _waitWhileBusy2("_readData16", default_wait_time);
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  _transfer16(0x1000); // preamble for read data
+  _waitWhileBusy2("_readData16 preamble", default_wait_time);
+  _transfer16(0); // dummy
+  _waitWhileBusy2("_readData16 dummy", default_wait_time);
+  for (uint32_t i = 0; i < n; i++)
+  {
+    *d++ = _transfer16(0);
+    //_waitWhileBusy("_readData16 data", default_wait_time);
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+}
+
+void GxEPD2_it103_1872x1404::_writeCommandData16(uint16_t c, const uint16_t* d, uint16_t n)
+{
+  _writeCommand16(c);
+  for (uint16_t i = 0; i < n; i++)
+  {
+    _writeData16(d[i]);
+  }
+}
+
+void GxEPD2_it103_1872x1404::_IT8951SystemRun()
+{
+  _writeCommand16(IT8951_TCON_SYS_RUN);
+}
+
+void GxEPD2_it103_1872x1404::_IT8951StandBy()
+{
+  _writeCommand16(IT8951_TCON_STANDBY);
+}
+
+void GxEPD2_it103_1872x1404::_IT8951Sleep()
+{
+  _writeCommand16(IT8951_TCON_SLEEP);
+}
+
+uint16_t GxEPD2_it103_1872x1404::_IT8951ReadReg(uint16_t usRegAddr)
+{
+  uint16_t usData;
+
+  //Send Cmd and Register Address
+  _writeCommand16(IT8951_TCON_REG_RD);
+  _writeData16(usRegAddr);
+  //Read data from Host Data bus
+  usData = _readData16();
+  return usData;
+}
+
+void GxEPD2_it103_1872x1404::_IT8951WriteReg(uint16_t usRegAddr, uint16_t usValue)
+{
+  //Send Cmd , Register Address and Write Value
+  _writeCommand16(IT8951_TCON_REG_WR);
+  _writeData16(usRegAddr);
+  _writeData16(usValue);
+}
+
+uint16_t GxEPD2_it103_1872x1404::_IT8951GetVCOM(void)
+{
+  uint16_t vcom;
+
+  _writeCommand16(USDEF_I80_CMD_VCOM);
+  _waitWhileBusy2("_IT8951GetVCOM", default_wait_time);
+  _writeData16(0);
+  //Read data from Host Data bus
+  vcom = _readData16();
+  return vcom;
+}
+
+void GxEPD2_it103_1872x1404::_IT8951SetVCOM(uint16_t vcom)
+{
+  _writeCommand16(USDEF_I80_CMD_VCOM);
+  _waitWhileBusy2("_IT8951SetVCOM", default_wait_time);
+  _writeData16(1);
+  //Read data from Host Data bus
+  _writeData16(vcom);
+  _waitWhileBusy2("_IT8951SetVCOM", set_vcom_time);
+}

+ 113 - 0
src/it8951/GxEPD2_it103_1872x1404.h

@@ -0,0 +1,113 @@
+// Display Library 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!
+//
+// GxEPD2_it103_1872x1404 class is based on Demo Example from Waveshare for Raspberry PI https://github.com/waveshare/IT8951/archive/master.zip
+// Controller: IT8951 : https://www.waveshare.com/w/upload/1/18/IT8951_D_V0.2.4.3_20170728.pdf
+//
+// The GxEPD2_it103_1872x1404 driver class supports the Waveshare e-Paper IT8951 Driver HAT connected with SPI for the ES103TC1 10.3" e-paper panel (parallel IF)
+// https://www.waveshare.com/product/displays/e-paper/epaper-1/10.3inch-e-paper-d.htm
+// This Driver HAT requires 5V power supply but works with 3.3V data lines; requires both MOSI and MISO SPI lines.
+//
+// Author: Jean-Marc Zingg
+//
+// Version: see library.properties
+//
+// Library: https://github.com/ZinggJM/GxEPD2
+
+#ifndef _GxEPD2_it103_1872x1404_H_
+#define _GxEPD2_it103_1872x1404_H_
+
+#include "../GxEPD2_EPD.h"
+
+class GxEPD2_it103_1872x1404 : public GxEPD2_EPD
+{
+  public:
+    // attributes
+    static const uint16_t WIDTH = 1872;
+    static const uint16_t HEIGHT = 1404;
+    static const GxEPD2::Panel panel = GxEPD2::ES103TC1;
+    static const bool hasColor = false;
+    static const bool hasPartialUpdate = true;
+    static const bool hasFastPartialUpdate = true;
+    static const uint16_t reset_to_ready_time = 1800; // ms, e.g. 1729001us
+    static const uint16_t power_on_time = 10; // ms, e.g. 3001us
+    static const uint16_t power_off_time = 250; // ms, e.g. 214001us
+    static const uint16_t full_refresh_time = 850; // ms, e.g. 827000us
+    static const uint16_t partial_refresh_time = 300; // ms, e.g. 284000us
+    static const uint16_t refresh_cmd_time = 10; // ms, e.g. 6052us
+    static const uint16_t refresh_par_time = 2; // ms, e.g. 1921us
+    static const uint16_t default_wait_time = 1; // ms, default busy check, needed?
+    static const uint16_t diag_min_time = 3; // ms, e.g. > refresh_par_time
+    static const uint16_t set_vcom_time = 500; // ms, e.g. 454967us
+    // constructor
+    GxEPD2_it103_1872x1404(int16_t cs, int16_t dc, int16_t rst, int16_t busy);
+    // methods (virtual)
+    void init(uint32_t serial_diag_bitrate = 0); // serial_diag_bitrate = 0 : disabled
+    void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false);
+    //  Support for Bitmaps (Sprites) to Controller Buffer and to Screen
+    void clearScreen(uint8_t value = 0x33); // init controller memory and screen (default white)
+    void writeScreenBuffer(uint8_t value = 0x33); // init controller memory (default white)
+    // write to controller memory, without screen refresh; x and w should be multiple of 8
+    void writeImage(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);
+    void writeImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // write sprite of native data to controller memory, without screen refresh; x and w should be multiple of 8
+    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);
+    // write to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void drawImagePart(const uint8_t bitmap[], 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);
+    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);
+    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);
+    // write sprite of native data to controller memory, with screen refresh; x and w should be multiple of 8
+    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);
+    void refresh(bool partial_update_mode = false); // screen refresh from controller memory to full screen
+    void refresh(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, partial screen
+    void powerOff(); // turns off generation of panel driving voltages, avoids screen fading over time
+    void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)
+  private:
+    struct IT8951DevInfoStruct
+    {
+      uint16_t usPanelW;
+      uint16_t usPanelH;
+      uint16_t usImgBufAddrL;
+      uint16_t usImgBufAddrH;
+      uint16_t usFWVersion[8];   //16 Bytes String
+      uint16_t usLUTVersion[8];   //16 Bytes String
+    };
+    IT8951DevInfoStruct IT8951DevInfo;
+    SPISettings _spi_settings;
+    SPISettings _spi_settings_for_read;
+  private:
+    void _writeScreenBuffer(uint8_t value);
+    void _refresh(int16_t x, int16_t y, int16_t w, int16_t h, bool partial_update_mode);
+    void _send8pixel(uint8_t data);
+    void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
+    void _PowerOn();
+    void _PowerOff();
+    void _InitDisplay();
+    void _Init_Full();
+    void _Init_Part();
+    // IT8951
+    void _waitWhileBusy2(const char* comment = 0, uint16_t busy_time = 5000);
+    uint16_t _transfer16(uint16_t value);
+    void _writeCommand16(uint16_t c);
+    void _writeData16(uint16_t d);
+    void _writeData16(const uint16_t* d, uint32_t n);
+    uint16_t _readData16();
+    void _readData16(uint16_t* d, uint32_t n);
+    void _writeCommandData16(uint16_t c, const uint16_t* d, uint16_t n);
+    void _IT8951SystemRun();
+    void _IT8951StandBy();
+    void _IT8951Sleep();
+    uint16_t _IT8951ReadReg(uint16_t usRegAddr);
+    void _IT8951WriteReg(uint16_t usRegAddr, uint16_t usValue);
+    uint16_t _IT8951GetVCOM(void);
+    void _IT8951SetVCOM(uint16_t vcom);
+};
+
+#endif