Przeglądaj źródła

initial release version 1.0.2

ZinggJM 8 lat temu
rodzic
commit
f0c313a13b

+ 19 - 0
CONTRIBUTING.md

@@ -0,0 +1,19 @@
+## Contributions are welcome. Keep It Simple is the Goal.
+
+### enhancement suggestions:
+- please use the Arduino Forum Displays for questions or enhancement suggestions.
+- questions and enhancement suggestions are an important source of inspiration for me.
+- the Arduino Forum is my favorite source for learning about displays and processor boards.
+- Keep It Simple: I will try to add enhancements to separate classes or subclasses.
+
+### issues:
+- please post only issues that are real issues with this library!
+- please add all information according to the issue template
+
+### pull requests:
+- in general, I will not merge pull request.
+- pull requests are useful to inform users and me about interesting additions in forked repositories.
+- I will close or remove pull request at will.
+- enhancements as separate classes are preferred.
+
+## Thank you for all the inspiration I get for this library.

+ 59 - 0
ConnectingHardware.md

@@ -0,0 +1,59 @@
+#### GxEPD2 : a simple E-Paper display library for Arduino for SPI e-paper displays panels from Dalian Good Display and SPI e-paper display boards from Waveshare
+ 
+#### important note :
+#### - these displays are for 3.3V supply and 3.3V data lines
+#### - never connect data lines directly to 5V Arduino data pins, you may use e.g. 4k7 series resistor
+#### - do not forget to connect GND
+
+## mapping suggestions
+
+#### mapping suggestion from Waveshare SPI e-Paper to Wemos D1 mini
+##### - BUSY -> D2, RST -> D4, DC -> D3, CS -> D8, CLK -> D5, DIN -> D7, GND -> GND, 3.3V -> 3.3V
+
+#### mapping suggestion from Waveshare SPI e-Paper to generic ESP8266
+##### - BUSY -> GPIO4, RST -> GPIO2, DC -> GPIO0, CS -> GPIO15, CLK -> GPIO14, DIN -> GPIO13, GND -> GND, 3.3V -> 3.3V
+
+#### mapping suggestion for ESP32, e.g. LOLIN32, see .../variants/.../pins_arduino.h for your board
+##### - NOTE: there are variants with different pins for SPI ! CHECK SPI PINS OF YOUR BOARD
+##### - BUSY -> 4, RST -> 16, DC -> 17, CS -> SS(5), CLK -> SCK(18), DIN -> MOSI(23), GND -> GND, 3.3V -> 3.3V
+
+#### mapping suggestion for STM32F1, e.g. STM32F103C8T6 "BluePill"
+##### - BUSY -> A1, RST -> A2, DC -> A3, CS-> A4, CLK -> A5, DIN -> A7
+
+#### mapping suggestion for AVR, UNO, NANO etc.
+##### - BUSY -> 7, RST -> 9, DC -> 8, CS-> 10, CLK -> 13, DIN -> 11
+
+## connection scheme for DESTM32-S2 connection board for e-paper panels:
+
+```
+   connection to the e-Paper display is through DESTM32-S2 connection board, available from Good Display
+
+
+
+   DESTM32-S2 pinout (top, component side view):
+
+         |-------------------------------------------------
+
+         |  VCC  |o o| VCC 5V  not needed
+
+         |  GND  |o o| GND     GND
+
+         |  3.3  |o o| 3.3     3.3V
+
+         |  nc   |o o| nc
+
+         |  nc   |o o| nc
+
+         |  nc   |o o| nc
+
+   MOSI  |  DIN  |o o| CLK     SCK
+
+   SS    |  CS   |o o| DC      e.g. D3
+
+   D4    |  RST  |o o| BUSY    e.g. D2
+
+         |  nc   |o o| BS      GND
+
+         |-------------------------------------------------
+
+```

+ 7 - 1
README.md

@@ -33,7 +33,13 @@ New Simplified Version of GxEPD for Arduino
 - Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0
 - Good Dispay ePaper for Arduino : https://forum.arduino.cc/index.php?topic=436411.0
 
-### Version 1.0.1
+### Version 1.0.2
+- initial release version 1.0.2
+- tested with ESP8266, ESP32, STM32F103C8T6, AVR Arduino (Pro Mini 3.3V)
+- 1.54" 3-color GxEPD2_154c can be used with paging for AVR
+- wave tables in program space,  4.2" b/w can be used with GxEPD2_SD_AVR_Example
+- issues enabled and welcome, please use Forum Topic for enhancement suggestions
+#### Version 1.0.1
 - pre-release test version
 - GxEPD2_SD_AVR_Example added, has no graphics buffer to reduce RAM usage (base display class use)
 - issues disabled so far, use Arduino Forum Topics instead

+ 18 - 11
examples/GxEPD2_Example/GxEPD2_Example.ino

@@ -97,7 +97,7 @@
 #endif
 
 #if defined(_BOARD_GENERIC_STM32F103C_H_)
-#define MAX_DISPAY_BUFFER_SIZE (400 * 300) // ~15k is a good compromise
+#define MAX_DISPAY_BUFFER_SIZE 15000ul // ~15k is a good compromise
 #define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8))
 // select one and adapt to your mapping
 //GxEPD2_BW<GxEPD2_154, MAX_HEIGHT(GxEPD2_154)> display(GxEPD2_154(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
@@ -105,6 +105,7 @@
 //GxEPD2_BW<GxEPD2_290, MAX_HEIGHT(GxEPD2_290)> display(GxEPD2_290(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 //GxEPD2_BW<GxEPD2_270, MAX_HEIGHT(GxEPD2_270)> display(GxEPD2_270(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 //GxEPD2_BW<GxEPD2_420, MAX_HEIGHT(GxEPD2_420)> display(GxEPD2_420(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
+//GxEPD2_BW<GxEPD2_583, MAX_HEIGHT(GxEPD2_583)> display(GxEPD2_583(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 //GxEPD2_BW<GxEPD2_750, MAX_HEIGHT(GxEPD2_750)> display(GxEPD2_750(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 // 3-color e-papers
 #define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8))
@@ -113,6 +114,7 @@
 //GxEPD2_3C<GxEPD2_290c, MAX_HEIGHT_3C(GxEPD2_290c)> display(GxEPD2_290c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 //GxEPD2_3C<GxEPD2_270c, MAX_HEIGHT_3C(GxEPD2_270c)> display(GxEPD2_270c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 //GxEPD2_3C<GxEPD2_420c, MAX_HEIGHT_3C(GxEPD2_420c)> display(GxEPD2_420c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
+//GxEPD2_3C<GxEPD2_583c, MAX_HEIGHT_3C(GxEPD2_583c)> display(GxEPD2_583c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 //GxEPD2_3C<GxEPD2_750c, MAX_HEIGHT_3C(GxEPD2_750c)> display(GxEPD2_750c(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
 #endif
 
@@ -125,20 +127,20 @@
 //GxEPD2_BW<GxEPD2_290, MAX_HEIGHT(GxEPD2_290)> display(GxEPD2_290(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_BW<GxEPD2_270, MAX_HEIGHT(GxEPD2_270)> display(GxEPD2_270(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_BW<GxEPD2_420, MAX_HEIGHT(GxEPD2_420)> display(GxEPD2_420(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
+//GxEPD2_BW<GxEPD2_583, MAX_HEIGHT(GxEPD2_583)> display(GxEPD2_583(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_BW<GxEPD2_750, MAX_HEIGHT(GxEPD2_750)> display(GxEPD2_750(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 // 3-color e-papers
 #define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8))
-////GxEPD2_3C<GxEPD2_154c, MAX_HEIGHT_3C(GxEPD2_154c)> display(GxEPD2_154c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // not available
-// in this version GxEPD2_154c can only be used with full size buffer (or with no buffer base display class)
-//GxEPD2_3C<GxEPD2_154c, (GxEPD2_154c::HEIGHT> display(GxEPD2_154c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
+//GxEPD2_3C<GxEPD2_154c, MAX_HEIGHT_3C(GxEPD2_154c)> display(GxEPD2_154c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_3C<GxEPD2_213c, MAX_HEIGHT_3C(GxEPD2_213c)> display(GxEPD2_213c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_3C<GxEPD2_290c, MAX_HEIGHT_3C(GxEPD2_290c)> display(GxEPD2_290c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_3C<GxEPD2_270c, MAX_HEIGHT_3C(GxEPD2_270c)> display(GxEPD2_270c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_3C<GxEPD2_420c, MAX_HEIGHT_3C(GxEPD2_420c)> display(GxEPD2_420c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
+//GxEPD2_3C<GxEPD2_583c, MAX_HEIGHT_3C(GxEPD2_583c)> display(GxEPD2_583c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_3C<GxEPD2_750c, MAX_HEIGHT_3C(GxEPD2_750c)> display(GxEPD2_750c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 #endif
 
-#if !defined(__AVR)
+#if !defined(__AVR) && !defined(_BOARD_GENERIC_STM32F103C_H_)
 
 // comment out unused bitmaps to reduce code space used
 #include "bitmaps/Bitmaps200x200.h" // 1.54" b/w
@@ -483,7 +485,7 @@ void drawBitmaps()
 #ifdef _GxBitmaps3c400x300_H_
   drawBitmaps3c400x300();
 #endif
-// show these after the specific bitmaps
+  // show these after the specific bitmaps
 #ifdef _GxBitmaps200x200_H_
   drawBitmaps200x200();
 #endif
@@ -496,15 +498,20 @@ void drawBitmaps()
 #ifdef _GxBitmaps200x200_H_
 void drawBitmaps200x200()
 {
-#if !defined(__AVR)
+#if defined(__AVR)
   const unsigned char* bitmaps[] =
   {
-    logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200
+    logo200x200, first200x200 //, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200
+  };
+#elif defined(_BOARD_GENERIC_STM32F103C_H_)
+  const unsigned char* bitmaps[] =
+  {
+    logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200 //, sixth200x200, senventh200x200, eighth200x200
   };
 #else
   const unsigned char* bitmaps[] =
   {
-    logo200x200, first200x200 //, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200
+    logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200
   };
 #endif
   if (display.epd2.panel == GxEPD2::GDEP015OC1)
@@ -554,8 +561,8 @@ void drawBitmaps200x200()
     break; // comment out for full show
   }
   display.writeScreenBuffer(); // use default for white
-  display.writeImage(bitmaps[0], 0, 0, 200, 200, false, mirror_y, true);
-  display.writeImage(bitmaps[0], int16_t(display.epd2.WIDTH) - 200, int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, mirror_y, true);
+  display.writeImage(bitmaps[0], int16_t(0), 0, 200, 200, false, mirror_y, true);
+  display.writeImage(bitmaps[0], int16_t(int16_t(display.epd2.WIDTH) - 200), int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, mirror_y, true);
   display.refresh(true);
   delay(2000);
 }

+ 2 - 3
examples/GxEPD2_PagedDisplayUsingCallback/GxEPD2_PagedDisplayUsingCallback.ino

@@ -97,7 +97,7 @@
 #endif
 
 #if defined(_BOARD_GENERIC_STM32F103C_H_)
-#define MAX_DISPAY_BUFFER_SIZE (400 * 300) // ~15k is a good compromise
+#define MAX_DISPAY_BUFFER_SIZE 15000ul // ~15k is a good compromise
 #define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8))
 // select one and adapt to your mapping
 //GxEPD2_BW<GxEPD2_154, MAX_HEIGHT(GxEPD2_154)> display(GxEPD2_154(/*CS=4*/ SS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));
@@ -128,8 +128,7 @@
 //GxEPD2_BW<GxEPD2_750, MAX_HEIGHT(GxEPD2_750)> display(GxEPD2_750(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 // 3-color e-papers
 #define MAX_HEIGHT_3C(EPD) (EPD::HEIGHT <= (MAX_DISPAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8) ? EPD::HEIGHT : (MAX_DISPAY_BUFFER_SIZE / 2) / (EPD::WIDTH / 8))
-////GxEPD2_3C<GxEPD2_154c, MAX_HEIGHT_3C(GxEPD2_154c)> display(GxEPD2_154c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // not available
-// in this version GxEPD2_154c can only be used with full size buffer (or with no buffer base display class)
+//GxEPD2_3C<GxEPD2_154c, MAX_HEIGHT_3C(GxEPD2_154c)> display(GxEPD2_154c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7)); // not available
 //GxEPD2_3C<GxEPD2_213c, MAX_HEIGHT_3C(GxEPD2_213c)> display(GxEPD2_213c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_3C<GxEPD2_290c, MAX_HEIGHT_3C(GxEPD2_290c)> display(GxEPD2_290c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));
 //GxEPD2_3C<GxEPD2_270c, MAX_HEIGHT_3C(GxEPD2_270c)> display(GxEPD2_270c(/*CS=10*/ SS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7));

+ 1 - 1
examples/GxEPD2_SD_AVR_Example/GxEPD2_SD_AVR_Example.ino

@@ -56,7 +56,7 @@ SdFat SD;
 //GxEPD2_213 display(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7);
 //GxEPD2_290 display(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7);
 //GxEPD2_270 display(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7);
-////GxEPD2_420 display(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7); // not enough RAM (wavetable uses too much)
+//GxEPD2_420 display(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7);
 //GxEPD2_750 display(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7);
 // 3-color e-papers
 // !!! can't be used for this //GxEPD2_154c display(GxEPD2_154c(/*CS=10*/ EPD_CS, /*DC=*/ 8, /*RST=*/ 9, /*BUSY=*/ 7);

+ 3 - 1
examples/GxEPD2_SD_Example/GxEPD2_SD_Example.ino

@@ -126,7 +126,9 @@ SdFat SD;
 #endif
 
 #if defined(_BOARD_GENERIC_STM32F103C_H_)
-#define MAX_DISPAY_BUFFER_SIZE (400 * 300) // ~15k is a good compromise
+#define SD_CS 0  // adapt to your wiring
+#define EPD_CS SS // adapt to your wiring
+#define MAX_DISPAY_BUFFER_SIZE 15000ul // ~15k is a good compromise
 #define MAX_HEIGHT(EPD) (EPD::HEIGHT <= MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8) ? EPD::HEIGHT : MAX_DISPAY_BUFFER_SIZE / (EPD::WIDTH / 8))
 // select one and adapt to your mapping
 //GxEPD2_BW<GxEPD2_154, MAX_HEIGHT(GxEPD2_154)> display(GxEPD2_154(/*CS=4*/ EPD_CS, /*DC=*/ 3, /*RST=*/ 2, /*BUSY=*/ 1));

+ 12 - 0
issue_template.md

@@ -0,0 +1,12 @@
+## Please post only issues that are real issues with this library!
+- please use the Arduino Forum Displays for questions or enhancement suggestions
+
+### Expected Behavior
+
+### Actual Behavior
+
+### E-Paper module used
+
+### Arduino / Processor module used
+
+### Steps to reproduce the behavior or reduced but complete code example

+ 1 - 1
library.properties

@@ -1,5 +1,5 @@
 name=GxEPD2
-version=1.0.1
+version=1.0.2
 author=Jean-Marc Zingg
 maintainer=Jean-Marc Zingg
 sentence=Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.

+ 13 - 1
src/GxEPD2_3C.h

@@ -135,6 +135,7 @@ class GxEPD2_3C : public Adafruit_GFX
       fillScreen(GxEPD_WHITE);
       _current_page = 0;
       _second_phase = false;
+      epd2.setPaged(); // for GxEPD2_154c paged workaround
     }
 
     bool nextPage()
@@ -184,7 +185,7 @@ class GxEPD2_3C : public Adafruit_GFX
         if (_current_page == _pages)
         {
           _current_page = 0;
-          if (epd2.hasFastPartialUpdate)
+          if (epd2.panel == GxEPD2::GDEW0154Z04)
           {
             if (!_second_phase)
             {
@@ -225,6 +226,7 @@ class GxEPD2_3C : public Adafruit_GFX
       }
       else
       {
+        epd2.setPaged(); // for GxEPD2_154c paged workaround
         for (_current_page = 0; _current_page < _pages; _current_page++)
         {
           uint16_t page_ys = _current_page * _page_height;
@@ -232,6 +234,16 @@ class GxEPD2_3C : public Adafruit_GFX
           drawCallback(pv);
           epd2.writeImage(_black_buffer, _color_buffer, 0, page_ys, WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys));
         }
+        if (epd2.panel == GxEPD2::GDEW0154Z04)
+        { // GxEPD2_154c paged workaround: write color part
+          for (_current_page = 0; _current_page < _pages; _current_page++)
+          {
+            uint16_t page_ys = _current_page * _page_height;
+            fillScreen(GxEPD_WHITE);
+            drawCallback(pv);
+            epd2.writeImage(_black_buffer, _color_buffer, 0, page_ys, WIDTH, gx_uint16_min(_page_height, HEIGHT - page_ys));
+          }
+        }
         epd2.refresh();
       }
       _current_page = 0;

+ 33 - 0
src/GxEPD2_EPD.cpp

@@ -11,6 +11,12 @@
 
 #include "GxEPD2_EPD.h"
 
+#if defined(ESP8266) || defined(ESP32)
+#include <pgmspace.h>
+#else
+#include <avr/pgmspace.h>
+#endif
+
 GxEPD2_EPD::GxEPD2_EPD(int8_t cs, int8_t dc, int8_t rst, int8_t busy, int8_t busy_level, uint32_t busy_timeout) :
   _cs(cs), _dc(dc), _rst(rst), _busy(busy), _busy_level(busy_level), _busy_timeout(busy_timeout), _diag_enabled(false),
   _spi_settings(4000000, MSBFIRST, SPI_MODE0)
@@ -126,6 +132,18 @@ void GxEPD2_EPD::_writeData(const uint8_t* data, uint16_t n)
   SPI.endTransaction();
 }
 
+void GxEPD2_EPD::_writeDataPGM(const uint8_t* data, uint16_t n)
+{
+  SPI.beginTransaction(_spi_settings);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  for (uint8_t i = 0; i < n; i++)
+  {
+    SPI.transfer(pgm_read_byte(&*data++));
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+}
+
 void GxEPD2_EPD::_writeCommandData(const uint8_t* pCommandData, uint8_t datalen)
 {
   SPI.beginTransaction(_spi_settings);
@@ -141,4 +159,19 @@ void GxEPD2_EPD::_writeCommandData(const uint8_t* pCommandData, uint8_t datalen)
   SPI.endTransaction();
 }
 
+void GxEPD2_EPD::_writeCommandDataPGM(const uint8_t* pCommandData, uint8_t datalen)
+{
+  SPI.beginTransaction(_spi_settings);
+  if (_dc >= 0) digitalWrite(_dc, LOW);
+  if (_cs >= 0) digitalWrite(_cs, LOW);
+  SPI.transfer(pgm_read_byte(&*pCommandData++));
+  if (_dc >= 0) digitalWrite(_dc, HIGH);
+  for (uint8_t i = 0; i < datalen - 1; i++)  // sub the command
+  {
+    SPI.transfer(pgm_read_byte(&*pCommandData++));
+  }
+  if (_cs >= 0) digitalWrite(_cs, HIGH);
+  SPI.endTransaction();
+}
+
 

+ 3 - 0
src/GxEPD2_EPD.h

@@ -63,6 +63,7 @@ class GxEPD2_EPD
     virtual void drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert = false, bool mirror_y = false, bool pgm = false) = 0;
     virtual void refresh(bool partial_update_mode = false) = 0; // screen refresh from controller memory to full screen
     virtual void refresh(int16_t x, int16_t y, int16_t w, int16_t h) = 0; // screen refresh from controller memory, partial screen
+    virtual void setPaged() {}; // for GxEPD2_154c paged workaround
     static inline uint16_t gx_uint16_min(uint16_t a, uint16_t b)
     {
       return (a < b ? a : b);
@@ -76,7 +77,9 @@ class GxEPD2_EPD
     void _writeCommand(uint8_t c);
     void _writeData(uint8_t d);
     void _writeData(const uint8_t* data, uint16_t n);
+    void _writeDataPGM(const uint8_t* data, uint16_t n);
     void _writeCommandData(const uint8_t* pCommandData, uint8_t datalen);
+    void _writeCommandDataPGM(const uint8_t* pCommandData, uint8_t datalen);
   protected:
     int8_t _cs, _dc, _rst, _busy, _busy_level;
     uint32_t _busy_timeout;

+ 2 - 2
src/epd/GxEPD2_154.cpp

@@ -250,7 +250,7 @@ void GxEPD2_154::_InitDisplay()
 void GxEPD2_154::_Init_Full()
 {
   _InitDisplay();
-  _writeCommandData(GDEP015OC1_LUTDefault_full, sizeof(GDEP015OC1_LUTDefault_full));
+  _writeCommandDataPGM(GDEP015OC1_LUTDefault_full, sizeof(GDEP015OC1_LUTDefault_full));
   _PowerOn();
   _using_partial_mode = false;
 }
@@ -258,7 +258,7 @@ void GxEPD2_154::_Init_Full()
 void GxEPD2_154::_Init_Part()
 {
   _InitDisplay();
-  _writeCommandData(GDEP015OC1_LUTDefault_part, sizeof(GDEP015OC1_LUTDefault_part));
+  _writeCommandDataPGM(GDEP015OC1_LUTDefault_part, sizeof(GDEP015OC1_LUTDefault_part));
   _PowerOn();
   _using_partial_mode = true;
 }

+ 3 - 3
src/epd/GxEPD2_213.cpp

@@ -103,7 +103,7 @@ void GxEPD2_213::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_
     {
       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;
+      int16_t idx = mirror_y ? j + dx / 8 + (h - 1 - i) * wb : j + dx / 8 + i * wb;
       if (pgm)
       {
 #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
@@ -250,7 +250,7 @@ void GxEPD2_213::_InitDisplay()
 void GxEPD2_213::_Init_Full()
 {
   _InitDisplay();
-  _writeCommandData(GxGDE0213B1_LUTDefault_full, sizeof(GxGDE0213B1_LUTDefault_full));
+  _writeCommandDataPGM(GxGDE0213B1_LUTDefault_full, sizeof(GxGDE0213B1_LUTDefault_full));
   _PowerOn();
   _using_partial_mode = false;
 }
@@ -258,7 +258,7 @@ void GxEPD2_213::_Init_Full()
 void GxEPD2_213::_Init_Part()
 {
   _InitDisplay();
-  _writeCommandData(GxGDE0213B1_LUTDefault_part, sizeof(GxGDE0213B1_LUTDefault_part));
+  _writeCommandDataPGM(GxGDE0213B1_LUTDefault_part, sizeof(GxGDE0213B1_LUTDefault_part));
   _PowerOn();
   _using_partial_mode = true;
 }

+ 10 - 10
src/epd/GxEPD2_270.cpp

@@ -266,15 +266,15 @@ void GxEPD2_270::_Init_Full()
 {
   _InitDisplay();
   _writeCommand(0x20);
-  _writeData(GxGDEW027W3_lut_20_vcomDC, sizeof(GxGDEW027W3_lut_20_vcomDC));
+  _writeDataPGM(GxGDEW027W3_lut_20_vcomDC, sizeof(GxGDEW027W3_lut_20_vcomDC));
   _writeCommand(0x21);
-  _writeData(GxGDEW027W3_lut_21_ww, sizeof(GxGDEW027W3_lut_21_ww));
+  _writeDataPGM(GxGDEW027W3_lut_21_ww, sizeof(GxGDEW027W3_lut_21_ww));
   _writeCommand(0x22);
-  _writeData(GxGDEW027W3_lut_22_bw, sizeof(GxGDEW027W3_lut_22_bw));
+  _writeDataPGM(GxGDEW027W3_lut_22_bw, sizeof(GxGDEW027W3_lut_22_bw));
   _writeCommand(0x23);
-  _writeData(GxGDEW027W3_lut_23_wb, sizeof(GxGDEW027W3_lut_23_wb));
+  _writeDataPGM(GxGDEW027W3_lut_23_wb, sizeof(GxGDEW027W3_lut_23_wb));
   _writeCommand(0x24);
-  _writeData(GxGDEW027W3_lut_24_bb, sizeof(GxGDEW027W3_lut_24_bb));
+  _writeDataPGM(GxGDEW027W3_lut_24_bb, sizeof(GxGDEW027W3_lut_24_bb));
   _PowerOn();
   _using_partial_mode = false;
 }
@@ -284,15 +284,15 @@ void GxEPD2_270::_Init_Part()
   _InitDisplay();
   // no partial update LUT
   _writeCommand(0x20);
-  _writeData(GxGDEW027W3_lut_20_vcomDC, sizeof(GxGDEW027W3_lut_20_vcomDC));
+  _writeDataPGM(GxGDEW027W3_lut_20_vcomDC, sizeof(GxGDEW027W3_lut_20_vcomDC));
   _writeCommand(0x21);
-  _writeData(GxGDEW027W3_lut_21_ww, sizeof(GxGDEW027W3_lut_21_ww));
+  _writeDataPGM(GxGDEW027W3_lut_21_ww, sizeof(GxGDEW027W3_lut_21_ww));
   _writeCommand(0x22);
-  _writeData(GxGDEW027W3_lut_22_bw, sizeof(GxGDEW027W3_lut_22_bw));
+  _writeDataPGM(GxGDEW027W3_lut_22_bw, sizeof(GxGDEW027W3_lut_22_bw));
   _writeCommand(0x23);
-  _writeData(GxGDEW027W3_lut_23_wb, sizeof(GxGDEW027W3_lut_23_wb));
+  _writeDataPGM(GxGDEW027W3_lut_23_wb, sizeof(GxGDEW027W3_lut_23_wb));
   _writeCommand(0x24);
-  _writeData(GxGDEW027W3_lut_24_bb, sizeof(GxGDEW027W3_lut_24_bb));
+  _writeDataPGM(GxGDEW027W3_lut_24_bb, sizeof(GxGDEW027W3_lut_24_bb));
   _PowerOn();
   _using_partial_mode = true;
 }

+ 2 - 2
src/epd/GxEPD2_290.cpp

@@ -250,7 +250,7 @@ void GxEPD2_290::_InitDisplay()
 void GxEPD2_290::_Init_Full()
 {
   _InitDisplay();
-  _writeCommandData(GxGDEH029A1_LUTDefault_full, sizeof(GxGDEH029A1_LUTDefault_full));
+  _writeCommandDataPGM(GxGDEH029A1_LUTDefault_full, sizeof(GxGDEH029A1_LUTDefault_full));
   _PowerOn();
   _using_partial_mode = false;
 }
@@ -258,7 +258,7 @@ void GxEPD2_290::_Init_Full()
 void GxEPD2_290::_Init_Part()
 {
   _InitDisplay();
-  _writeCommandData(GxGDEH029A1_LUTDefault_part, sizeof(GxGDEH029A1_LUTDefault_part));
+  _writeCommandDataPGM(GxGDEH029A1_LUTDefault_part, sizeof(GxGDEH029A1_LUTDefault_part));
   _PowerOn();
   _using_partial_mode = true;
 }

+ 10 - 10
src/epd/GxEPD2_420.cpp

@@ -242,15 +242,15 @@ void GxEPD2_420::_Init_Full()
 {
   _InitDisplay();
   _writeCommand(0x20);
-  _writeData(GxGDEW042T2_lut_20_vcom0_full, sizeof(GxGDEW042T2_lut_20_vcom0_full));
+  _writeDataPGM(GxGDEW042T2_lut_20_vcom0_full, sizeof(GxGDEW042T2_lut_20_vcom0_full));
   _writeCommand(0x21);
-  _writeData(GxGDEW042T2_lut_21_ww_full, sizeof(GxGDEW042T2_lut_21_ww_full));
+  _writeDataPGM(GxGDEW042T2_lut_21_ww_full, sizeof(GxGDEW042T2_lut_21_ww_full));
   _writeCommand(0x22);
-  _writeData(GxGDEW042T2_lut_22_bw_full, sizeof(GxGDEW042T2_lut_22_bw_full));
+  _writeDataPGM(GxGDEW042T2_lut_22_bw_full, sizeof(GxGDEW042T2_lut_22_bw_full));
   _writeCommand(0x23);
-  _writeData(GxGDEW042T2_lut_23_wb_full, sizeof(GxGDEW042T2_lut_23_wb_full));
+  _writeDataPGM(GxGDEW042T2_lut_23_wb_full, sizeof(GxGDEW042T2_lut_23_wb_full));
   _writeCommand(0x24);
-  _writeData(GxGDEW042T2_lut_24_bb_full, sizeof(GxGDEW042T2_lut_24_bb_full));
+  _writeDataPGM(GxGDEW042T2_lut_24_bb_full, sizeof(GxGDEW042T2_lut_24_bb_full));
   _PowerOn();
   _using_partial_mode = false;
 }
@@ -259,15 +259,15 @@ void GxEPD2_420::_Init_Part()
 {
   _InitDisplay();
   _writeCommand(0x20);
-  _writeData(GxGDEW042T2_lut_20_vcom0_partial, sizeof(GxGDEW042T2_lut_20_vcom0_partial));
+  _writeDataPGM(GxGDEW042T2_lut_20_vcom0_partial, sizeof(GxGDEW042T2_lut_20_vcom0_partial));
   _writeCommand(0x21);
-  _writeData(GxGDEW042T2_lut_21_ww_partial, sizeof(GxGDEW042T2_lut_21_ww_partial));
+  _writeDataPGM(GxGDEW042T2_lut_21_ww_partial, sizeof(GxGDEW042T2_lut_21_ww_partial));
   _writeCommand(0x22);
-  _writeData(GxGDEW042T2_lut_22_bw_partial, sizeof(GxGDEW042T2_lut_22_bw_partial));
+  _writeDataPGM(GxGDEW042T2_lut_22_bw_partial, sizeof(GxGDEW042T2_lut_22_bw_partial));
   _writeCommand(0x23);
-  _writeData(GxGDEW042T2_lut_23_wb_partial, sizeof(GxGDEW042T2_lut_23_wb_partial));
+  _writeDataPGM(GxGDEW042T2_lut_23_wb_partial, sizeof(GxGDEW042T2_lut_23_wb_partial));
   _writeCommand(0x24);
-  _writeData(GxGDEW042T2_lut_24_bb_partial, sizeof(GxGDEW042T2_lut_24_bb_partial));
+  _writeDataPGM(GxGDEW042T2_lut_24_bb_partial, sizeof(GxGDEW042T2_lut_24_bb_partial));
   _PowerOn();
   _using_partial_mode = true;
 }

+ 40 - 34
src/epd/WaveTables.h

@@ -1,49 +1,55 @@
 #ifndef _WaveTables_H_
 #define _WaveTables_H_
 
-const uint8_t GDEP015OC1_LUTDefault_full[] =
+#if defined(ESP8266) || defined(ESP32)
+#include <pgmspace.h>
+#else
+#include <avr/pgmspace.h>
+#endif
+
+const uint8_t GDEP015OC1_LUTDefault_full[] PROGMEM =
 {
   0x32,  // command
   0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GDEP015OC1_LUTDefault_part[] =
+const uint8_t GDEP015OC1_LUTDefault_part[] PROGMEM =
 {
   0x32,  // command
   0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDE0213B1_LUTDefault_full[] =
+const uint8_t GxGDE0213B1_LUTDefault_full[] PROGMEM =
 {
   0x32,  // command
   0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x01, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDE0213B1_LUTDefault_part[] =
+const uint8_t GxGDE0213B1_LUTDefault_part[] PROGMEM =
 {
   0x32,  // command
   0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDEH029A1_LUTDefault_full[] =
+const uint8_t GxGDEH029A1_LUTDefault_full[] PROGMEM =
 {
   0x32,  // command
   0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDEH029A1_LUTDefault_part[] =
+const uint8_t GxGDEH029A1_LUTDefault_part[] PROGMEM =
 {
   0x32,  // command
   0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDEW027W3_lut_20_vcomDC[] =
+const uint8_t GxGDEW027W3_lut_20_vcomDC[] PROGMEM =
 {
 0x00  ,0x00 ,
 0x00  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,    
@@ -55,7 +61,7 @@ const uint8_t GxGDEW027W3_lut_20_vcomDC[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R21H
-const uint8_t GxGDEW027W3_lut_21_ww[] =
+const uint8_t GxGDEW027W3_lut_21_ww[] PROGMEM =
 {
 0x50  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -66,7 +72,7 @@ const uint8_t GxGDEW027W3_lut_21_ww[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R22H  r
-const uint8_t GxGDEW027W3_lut_22_bw[] =
+const uint8_t GxGDEW027W3_lut_22_bw[] PROGMEM =
 {
 0x50  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -77,7 +83,7 @@ const uint8_t GxGDEW027W3_lut_22_bw[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R23H  w
-const uint8_t GxGDEW027W3_lut_23_wb[] =
+const uint8_t GxGDEW027W3_lut_23_wb[] PROGMEM =
 {
 0xA0  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -88,7 +94,7 @@ const uint8_t GxGDEW027W3_lut_23_wb[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R24H  b
-const uint8_t GxGDEW027W3_lut_24_bb[] =
+const uint8_t GxGDEW027W3_lut_24_bb[] PROGMEM =
 {
 0xA0  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -99,16 +105,16 @@ const uint8_t GxGDEW027W3_lut_24_bb[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 
-const uint8_t GxGDEW0154Z04_lut_20_vcom0[] = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x06 , 0x04 , 0x0A , 0x0A , 0x0F , 0x03 , 0x03 , 0x0C , 0x06 , 0x0A , 0x00 };
-const uint8_t GxGDEW0154Z04_lut_21_w[] = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x46 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x86 , 0x0A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_22_b[] = {  0x0E  , 0x14 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x4A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_23_g1[] = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_24_g2[] = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_25_vcom1[] = {  0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
-const uint8_t GxGDEW0154Z04_lut_26_red0[] = { 0x83  , 0x5D , 0x01 , 0x81 , 0x48 , 0x23 , 0x77 , 0x77 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
-const uint8_t GxGDEW0154Z04_lut_27_red1[] = { 0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_20_vcom0[] PROGMEM = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x06 , 0x04 , 0x0A , 0x0A , 0x0F , 0x03 , 0x03 , 0x0C , 0x06 , 0x0A , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_21_w[] PROGMEM = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x46 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x86 , 0x0A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_22_b[] PROGMEM = {  0x0E  , 0x14 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x4A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_23_g1[] PROGMEM = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_24_g2[] PROGMEM = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_25_vcom1[] PROGMEM = {  0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_26_red0[] PROGMEM = { 0x83  , 0x5D , 0x01 , 0x81 , 0x48 , 0x23 , 0x77 , 0x77 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_27_red1[] PROGMEM = { 0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
 
-const uint8_t GxGDEW027C44_lut_20_vcomDC[] =
+const uint8_t GxGDEW027C44_lut_20_vcomDC[] PROGMEM =
 {
   0x00  , 0x00,
   0x00  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
@@ -120,7 +126,7 @@ const uint8_t GxGDEW027C44_lut_20_vcomDC[] =
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R21H
-const uint8_t GxGDEW027C44_lut_21[] = {
+const uint8_t GxGDEW027C44_lut_21[] PROGMEM = {
   0x90  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x40  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -130,7 +136,7 @@ const uint8_t GxGDEW027C44_lut_21[] = {
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R22H  r
-const uint8_t GxGDEW027C44_lut_22_red[] = {
+const uint8_t GxGDEW027C44_lut_22_red[] PROGMEM = {
   0xA0  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x00  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -140,7 +146,7 @@ const uint8_t GxGDEW027C44_lut_22_red[] = {
   0xC0  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R23H  w
-const uint8_t GxGDEW027C44_lut_23_white[] = {
+const uint8_t GxGDEW027C44_lut_23_white[] PROGMEM = {
   0x90  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x40  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -150,7 +156,7 @@ const uint8_t GxGDEW027C44_lut_23_white[] = {
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R24H  b
-const uint8_t GxGDEW027C44_lut_24_black[] = {
+const uint8_t GxGDEW027C44_lut_24_black[] PROGMEM = {
   0x90  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x20  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -160,7 +166,7 @@ const uint8_t GxGDEW027C44_lut_24_black[] = {
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 
-const unsigned char GxGDEW042T2_lut_20_vcom0_full[] =
+const unsigned char GxGDEW042T2_lut_20_vcom0_full[] PROGMEM =
 {
 0x40, 0x17, 0x00, 0x00, 0x00, 0x02,        
 0x00, 0x17, 0x17, 0x00, 0x00, 0x02,        
@@ -171,7 +177,7 @@ const unsigned char GxGDEW042T2_lut_20_vcom0_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_21_ww_full[] =
+const unsigned char GxGDEW042T2_lut_21_ww_full[] PROGMEM =
 {
 0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -182,7 +188,7 @@ const unsigned char GxGDEW042T2_lut_21_ww_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_22_bw_full[] =
+const unsigned char GxGDEW042T2_lut_22_bw_full[] PROGMEM =
 {
 0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -193,7 +199,7 @@ const unsigned char GxGDEW042T2_lut_22_bw_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     
 };
 
-const unsigned char GxGDEW042T2_lut_23_wb_full[] =
+const unsigned char GxGDEW042T2_lut_23_wb_full[] PROGMEM =
 {
 0x80, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -204,7 +210,7 @@ const unsigned char GxGDEW042T2_lut_23_wb_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,         
 };
 
-const unsigned char GxGDEW042T2_lut_24_bb_full[] =
+const unsigned char GxGDEW042T2_lut_24_bb_full[] PROGMEM =
 {
 0x80, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -218,7 +224,7 @@ const unsigned char GxGDEW042T2_lut_24_bb_full[] =
 #define TP0A  2 // sustain phase for bb and ww, change phase for bw and wb
 #define TP0B 45 // change phase for bw and wb
 
-const unsigned char GxGDEW042T2_lut_20_vcom0_partial[] =
+const unsigned char GxGDEW042T2_lut_20_vcom0_partial[] PROGMEM =
 {
   0x00,
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -230,7 +236,7 @@ const unsigned char GxGDEW042T2_lut_20_vcom0_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_21_ww_partial[] =
+const unsigned char GxGDEW042T2_lut_21_ww_partial[] PROGMEM =
 {
   0x80, // 10 00 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -242,7 +248,7 @@ const unsigned char GxGDEW042T2_lut_21_ww_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_22_bw_partial[] =
+const unsigned char GxGDEW042T2_lut_22_bw_partial[] PROGMEM =
 {
   0xA0, // 10 10 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -254,7 +260,7 @@ const unsigned char GxGDEW042T2_lut_22_bw_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_23_wb_partial[] =
+const unsigned char GxGDEW042T2_lut_23_wb_partial[] PROGMEM =
 {
   0x50, // 01 01 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -266,7 +272,7 @@ const unsigned char GxGDEW042T2_lut_23_wb_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_24_bb_partial[] =
+const unsigned char GxGDEW042T2_lut_24_bb_partial[] PROGMEM =
 {
   0x40, // 01 00 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,

+ 99 - 49
src/epd3c/GxEPD2_154c.cpp

@@ -24,6 +24,8 @@ GxEPD2_154c::GxEPD2_154c(int8_t cs, int8_t dc, int8_t rst, int8_t busy) : GxEPD2
 {
   _initial = true;
   _power_is_on = false;
+  _paged = false;
+  _second_phase = false;
 }
 
 void GxEPD2_154c::init(uint32_t serial_diag_bitrate)
@@ -31,6 +33,8 @@ void GxEPD2_154c::init(uint32_t serial_diag_bitrate)
   GxEPD2_EPD::init(serial_diag_bitrate);
   _initial = true;
   _power_is_on = false;
+  _paged = false;
+  _second_phase = false;
 }
 
 void GxEPD2_154c::clearScreen(uint8_t value)
@@ -84,70 +88,107 @@ void GxEPD2_154c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16
 
 void GxEPD2_154c::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)
 {
+  //Serial.print("writeImage("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
+  //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
   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
-  if ((w <= 0) || (h <= 0)) return;
-  _Init_Full();
-  _writeCommand(0x10);
-  for (int16_t i = 0; i < HEIGHT; i++)
+  if (_paged && (x == 0) && (w == WIDTH) && (h < HEIGHT))
+  {
+    //Serial.println("paged");
+    if (!_second_phase)
+    {
+      for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
+      {
+        _writeData(bw2grey[(black[i] & 0xF0) >> 4]);
+        _writeData(bw2grey[black[i] & 0x0F]);
+      }
+      if (y + h == HEIGHT) // last page
+      {
+        //Serial.println("phase 1 ended");
+        _second_phase = true;
+        _writeCommand(0x13);
+      }
+    }
+    else
+    {
+      for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
+      {
+        _writeData(color[i]);
+      }
+      if (y + h == HEIGHT) // last page
+      {
+        //Serial.println("phase 2 ended");
+        _second_phase = false;
+        _paged = false;
+      }
+    }
+  }
+  else
   {
-    for (int16_t j = 0; j < WIDTH; j += 8)
+    _paged = false;
+    int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
+    x -= x % 8; // byte boundary
+    w = wb * 8; // byte boundary
+    if ((w <= 0) || (h <= 0)) return;
+    _Init_Full();
+    _writeCommand(0x10);
+    for (int16_t i = 0; i < HEIGHT; i++)
     {
-      uint8_t data = 0xFF;
-      if (black)
+      for (int16_t j = 0; j < WIDTH; j += 8)
       {
-        if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
+        uint8_t data = 0xFF;
+        if (black)
         {
-          int16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
-          if (pgm)
+          if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
           {
+            int16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
+            if (pgm)
+            {
 #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
-            data = pgm_read_byte(&black[idx]);
+              data = pgm_read_byte(&black[idx]);
 #else
-            data = black[idx];
+              data = black[idx];
 #endif
+            }
+            else
+            {
+              data = black[idx];
+            }
+            if (invert) data = ~data;
           }
-          else
-          {
-            data = black[idx];
-          }
-          if (invert) data = ~data;
         }
+        //_writeData(data);
+        _writeData(bw2grey[(data & 0xF0) >> 4]);
+        _writeData(bw2grey[data & 0x0F]);
       }
-      //_writeData(data);
-      _writeData(bw2grey[(data & 0xF0) >> 4]);
-      _writeData(bw2grey[data & 0x0F]);
     }
-  }
-  _writeCommand(0x13);
-  for (int16_t i = 0; i < HEIGHT; i++)
-  {
-    for (int16_t j = 0; j < WIDTH; j += 8)
+    _writeCommand(0x13);
+    for (int16_t i = 0; i < HEIGHT; i++)
     {
-      uint8_t data = 0xFF;
-      if (color)
+      for (int16_t j = 0; j < WIDTH; j += 8)
       {
-        if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
+        uint8_t data = 0xFF;
+        if (color)
         {
-          int16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
-          if (pgm)
+          if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
           {
+            int16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
+            if (pgm)
+            {
 #if defined(__AVR) || defined(ESP8266) || defined(ESP32)
-            data = pgm_read_byte(&color[idx]);
+              data = pgm_read_byte(&color[idx]);
 #else
-            data = color[idx];
+              data = color[idx];
 #endif
+            }
+            else
+            {
+              data = color[idx];
+            }
+            if (invert) data = ~data;
           }
-          else
-          {
-            data = color[idx];
-          }
-          if (invert) data = ~data;
         }
+        _writeData(data);
       }
-      _writeData(data);
     }
   }
   delay(1); // yield() to avoid WDT on ESP8266 and ESP32
@@ -181,6 +222,7 @@ void GxEPD2_154c::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t
 
 void GxEPD2_154c::refresh(bool partial_update_mode)
 {
+  if (_paged) return;
   _Update_Full();
 }
 
@@ -225,6 +267,14 @@ void GxEPD2_154c::_PowerOff()
   _power_is_on = false;
 }
 
+void GxEPD2_154c::setPaged()
+{
+  _paged = true;
+  _second_phase = false;
+  _Init_Full();
+  _writeCommand(0x10);
+}
+
 void GxEPD2_154c::_InitDisplay()
 {
   // reset required for wakeup
@@ -263,21 +313,21 @@ void GxEPD2_154c::_Init_Full()
 {
   _InitDisplay();
   _writeCommand(0x20);
-  _writeData(GxGDEW0154Z04_lut_20_vcom0, sizeof(GxGDEW0154Z04_lut_20_vcom0));
+  _writeDataPGM(GxGDEW0154Z04_lut_20_vcom0, sizeof(GxGDEW0154Z04_lut_20_vcom0));
   _writeCommand(0x21);
-  _writeData(GxGDEW0154Z04_lut_21_w, sizeof(GxGDEW0154Z04_lut_21_w));
+  _writeDataPGM(GxGDEW0154Z04_lut_21_w, sizeof(GxGDEW0154Z04_lut_21_w));
   _writeCommand(0x22);
-  _writeData(GxGDEW0154Z04_lut_22_b, sizeof(GxGDEW0154Z04_lut_22_b));
+  _writeDataPGM(GxGDEW0154Z04_lut_22_b, sizeof(GxGDEW0154Z04_lut_22_b));
   _writeCommand(0x23);
-  _writeData(GxGDEW0154Z04_lut_23_g1, sizeof(GxGDEW0154Z04_lut_23_g1));
+  _writeDataPGM(GxGDEW0154Z04_lut_23_g1, sizeof(GxGDEW0154Z04_lut_23_g1));
   _writeCommand(0x24);
-  _writeData(GxGDEW0154Z04_lut_24_g2, sizeof(GxGDEW0154Z04_lut_24_g2));
+  _writeDataPGM(GxGDEW0154Z04_lut_24_g2, sizeof(GxGDEW0154Z04_lut_24_g2));
   _writeCommand(0x25);
-  _writeData(GxGDEW0154Z04_lut_25_vcom1, sizeof(GxGDEW0154Z04_lut_25_vcom1));
+  _writeDataPGM(GxGDEW0154Z04_lut_25_vcom1, sizeof(GxGDEW0154Z04_lut_25_vcom1));
   _writeCommand(0x26);
-  _writeData(GxGDEW0154Z04_lut_26_red0, sizeof(GxGDEW0154Z04_lut_26_red0));
+  _writeDataPGM(GxGDEW0154Z04_lut_26_red0, sizeof(GxGDEW0154Z04_lut_26_red0));
   _writeCommand(0x27);
-  _writeData(GxGDEW0154Z04_lut_27_red1, sizeof(GxGDEW0154Z04_lut_27_red1));
+  _writeDataPGM(GxGDEW0154Z04_lut_27_red1, sizeof(GxGDEW0154Z04_lut_27_red1));
   _PowerOn();
 }
 

+ 2 - 0
src/epd3c/GxEPD2_154c.h

@@ -50,6 +50,7 @@ class GxEPD2_154c : public GxEPD2_EPD
     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();
+    void setPaged(); // for GxEPD2_154c paged workaround
   private:
     void _writeScreenBuffer(uint8_t value);
     void _setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
@@ -62,6 +63,7 @@ class GxEPD2_154c : public GxEPD2_EPD
     void _Update_Part();
   protected:
     bool _initial, _power_is_on;
+    bool _paged, _second_phase;
     static const uint8_t bw2grey[];
 };
 

+ 1 - 1
src/epd3c/GxEPD2_270c.cpp

@@ -212,7 +212,7 @@ void GxEPD2_270c::_writeData_nCS(const uint8_t* data, uint16_t n)
   for (uint8_t i = 0; i < n; i++)
   {
     if (_cs >= 0) digitalWrite(_cs, LOW);
-    SPI.transfer(*data++);
+    SPI.transfer(pgm_read_byte(&*data++));
     if (_cs >= 0) digitalWrite(_cs, HIGH);
   }
   SPI.endTransaction();

+ 40 - 34
src/epd3c/WaveTables.h

@@ -1,49 +1,55 @@
 #ifndef _WaveTables_H_
 #define _WaveTables_H_
 
-const uint8_t GDEP015OC1_LUTDefault_full[] =
+#if defined(ESP8266) || defined(ESP32)
+#include <pgmspace.h>
+#else
+#include <avr/pgmspace.h>
+#endif
+
+const uint8_t GDEP015OC1_LUTDefault_full[] PROGMEM =
 {
   0x32,  // command
   0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GDEP015OC1_LUTDefault_part[] =
+const uint8_t GDEP015OC1_LUTDefault_part[] PROGMEM =
 {
   0x32,  // command
   0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDE0213B1_LUTDefault_full[] =
+const uint8_t GxGDE0213B1_LUTDefault_full[] PROGMEM =
 {
   0x32,  // command
   0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x01, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDE0213B1_LUTDefault_part[] =
+const uint8_t GxGDE0213B1_LUTDefault_part[] PROGMEM =
 {
   0x32,  // command
   0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDEH029A1_LUTDefault_full[] =
+const uint8_t GxGDEH029A1_LUTDefault_full[] PROGMEM =
 {
   0x32,  // command
   0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDEH029A1_LUTDefault_part[] =
+const uint8_t GxGDEH029A1_LUTDefault_part[] PROGMEM =
 {
   0x32,  // command
   0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
 
-const uint8_t GxGDEW027W3_lut_20_vcomDC[] =
+const uint8_t GxGDEW027W3_lut_20_vcomDC[] PROGMEM =
 {
 0x00  ,0x00 ,
 0x00  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,    
@@ -55,7 +61,7 @@ const uint8_t GxGDEW027W3_lut_20_vcomDC[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R21H
-const uint8_t GxGDEW027W3_lut_21_ww[] =
+const uint8_t GxGDEW027W3_lut_21_ww[] PROGMEM =
 {
 0x50  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -66,7 +72,7 @@ const uint8_t GxGDEW027W3_lut_21_ww[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R22H  r
-const uint8_t GxGDEW027W3_lut_22_bw[] =
+const uint8_t GxGDEW027W3_lut_22_bw[] PROGMEM =
 {
 0x50  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -77,7 +83,7 @@ const uint8_t GxGDEW027W3_lut_22_bw[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R23H  w
-const uint8_t GxGDEW027W3_lut_23_wb[] =
+const uint8_t GxGDEW027W3_lut_23_wb[] PROGMEM =
 {
 0xA0  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -88,7 +94,7 @@ const uint8_t GxGDEW027W3_lut_23_wb[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 //R24H  b
-const uint8_t GxGDEW027W3_lut_24_bb[] =
+const uint8_t GxGDEW027W3_lut_24_bb[] PROGMEM =
 {
 0xA0  ,0x0F ,0x0F ,0x00 ,0x00 ,0x05,
 0x60  ,0x32 ,0x32 ,0x00 ,0x00 ,0x02,
@@ -99,16 +105,16 @@ const uint8_t GxGDEW027W3_lut_24_bb[] =
 0x00  ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
 };
 
-const uint8_t GxGDEW0154Z04_lut_20_vcom0[] = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x06 , 0x04 , 0x0A , 0x0A , 0x0F , 0x03 , 0x03 , 0x0C , 0x06 , 0x0A , 0x00 };
-const uint8_t GxGDEW0154Z04_lut_21_w[] = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x46 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x86 , 0x0A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_22_b[] = {  0x0E  , 0x14 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x4A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_23_g1[] = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_24_g2[] = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
-const uint8_t GxGDEW0154Z04_lut_25_vcom1[] = {  0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
-const uint8_t GxGDEW0154Z04_lut_26_red0[] = { 0x83  , 0x5D , 0x01 , 0x81 , 0x48 , 0x23 , 0x77 , 0x77 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
-const uint8_t GxGDEW0154Z04_lut_27_red1[] = { 0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_20_vcom0[] PROGMEM = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x06 , 0x04 , 0x0A , 0x0A , 0x0F , 0x03 , 0x03 , 0x0C , 0x06 , 0x0A , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_21_w[] PROGMEM = {  0x0E  , 0x14 , 0x01 , 0x0A , 0x46 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x86 , 0x0A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_22_b[] PROGMEM = {  0x0E  , 0x14 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x4A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_23_g1[] PROGMEM = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_24_g2[] PROGMEM = { 0x8E  , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
+const uint8_t GxGDEW0154Z04_lut_25_vcom1[] PROGMEM = {  0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_26_red0[] PROGMEM = { 0x83  , 0x5D , 0x01 , 0x81 , 0x48 , 0x23 , 0x77 , 0x77 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
+const uint8_t GxGDEW0154Z04_lut_27_red1[] PROGMEM = { 0x03  , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
 
-const uint8_t GxGDEW027C44_lut_20_vcomDC[] =
+const uint8_t GxGDEW027C44_lut_20_vcomDC[] PROGMEM =
 {
   0x00  , 0x00,
   0x00  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
@@ -120,7 +126,7 @@ const uint8_t GxGDEW027C44_lut_20_vcomDC[] =
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R21H
-const uint8_t GxGDEW027C44_lut_21[] = {
+const uint8_t GxGDEW027C44_lut_21[] PROGMEM = {
   0x90  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x40  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -130,7 +136,7 @@ const uint8_t GxGDEW027C44_lut_21[] = {
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R22H  r
-const uint8_t GxGDEW027C44_lut_22_red[] = {
+const uint8_t GxGDEW027C44_lut_22_red[] PROGMEM = {
   0xA0  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x00  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -140,7 +146,7 @@ const uint8_t GxGDEW027C44_lut_22_red[] = {
   0xC0  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R23H  w
-const uint8_t GxGDEW027C44_lut_23_white[] = {
+const uint8_t GxGDEW027C44_lut_23_white[] PROGMEM = {
   0x90  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x40  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -150,7 +156,7 @@ const uint8_t GxGDEW027C44_lut_23_white[] = {
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 //R24H  b
-const uint8_t GxGDEW027C44_lut_24_black[] = {
+const uint8_t GxGDEW027C44_lut_24_black[] PROGMEM = {
   0x90  , 0x1A  , 0x1A  , 0x00  , 0x00  , 0x01,
   0x20  , 0x0A  , 0x0A  , 0x00  , 0x00  , 0x08,
   0x84  , 0x0E  , 0x01  , 0x0E  , 0x01  , 0x10,
@@ -160,7 +166,7 @@ const uint8_t GxGDEW027C44_lut_24_black[] = {
   0x00  , 0x23  , 0x00  , 0x00  , 0x00  , 0x01
 };
 
-const unsigned char GxGDEW042T2_lut_20_vcom0_full[] =
+const unsigned char GxGDEW042T2_lut_20_vcom0_full[] PROGMEM =
 {
 0x40, 0x17, 0x00, 0x00, 0x00, 0x02,        
 0x00, 0x17, 0x17, 0x00, 0x00, 0x02,        
@@ -171,7 +177,7 @@ const unsigned char GxGDEW042T2_lut_20_vcom0_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_21_ww_full[] =
+const unsigned char GxGDEW042T2_lut_21_ww_full[] PROGMEM =
 {
 0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -182,7 +188,7 @@ const unsigned char GxGDEW042T2_lut_21_ww_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_22_bw_full[] =
+const unsigned char GxGDEW042T2_lut_22_bw_full[] PROGMEM =
 {
 0x40, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -193,7 +199,7 @@ const unsigned char GxGDEW042T2_lut_22_bw_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,     
 };
 
-const unsigned char GxGDEW042T2_lut_23_wb_full[] =
+const unsigned char GxGDEW042T2_lut_23_wb_full[] PROGMEM =
 {
 0x80, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -204,7 +210,7 @@ const unsigned char GxGDEW042T2_lut_23_wb_full[] =
 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,         
 };
 
-const unsigned char GxGDEW042T2_lut_24_bb_full[] =
+const unsigned char GxGDEW042T2_lut_24_bb_full[] PROGMEM =
 {
 0x80, 0x17, 0x00, 0x00, 0x00, 0x02,
 0x90, 0x17, 0x17, 0x00, 0x00, 0x02,
@@ -218,7 +224,7 @@ const unsigned char GxGDEW042T2_lut_24_bb_full[] =
 #define TP0A  2 // sustain phase for bb and ww, change phase for bw and wb
 #define TP0B 45 // change phase for bw and wb
 
-const unsigned char GxGDEW042T2_lut_20_vcom0_partial[] =
+const unsigned char GxGDEW042T2_lut_20_vcom0_partial[] PROGMEM =
 {
   0x00,
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -230,7 +236,7 @@ const unsigned char GxGDEW042T2_lut_20_vcom0_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_21_ww_partial[] =
+const unsigned char GxGDEW042T2_lut_21_ww_partial[] PROGMEM =
 {
   0x80, // 10 00 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -242,7 +248,7 @@ const unsigned char GxGDEW042T2_lut_21_ww_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_22_bw_partial[] =
+const unsigned char GxGDEW042T2_lut_22_bw_partial[] PROGMEM =
 {
   0xA0, // 10 10 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -254,7 +260,7 @@ const unsigned char GxGDEW042T2_lut_22_bw_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_23_wb_partial[] =
+const unsigned char GxGDEW042T2_lut_23_wb_partial[] PROGMEM =
 {
   0x50, // 01 01 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,
@@ -266,7 +272,7 @@ const unsigned char GxGDEW042T2_lut_23_wb_partial[] =
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 };
 
-const unsigned char GxGDEW042T2_lut_24_bb_partial[] =
+const unsigned char GxGDEW042T2_lut_24_bb_partial[] PROGMEM =
 {
   0x40, // 01 00 00 00
   TP0A, TP0B, 0x01, 0x00, 0x01,