G6EJD / ESP32-e-Paper-Weather-Display

An ESP32 and 2.9", 4.2" or 7.5" ePaper Display reads Weather Underground data via their API and then displays the weather
Other
951 stars 206 forks source link

2.9inch e-Paper Module (B) and 3 line SPI or 4 line SPI #113

Closed echelon75 closed 4 years ago

echelon75 commented 4 years ago

Hi,

I am using a 2.9inch e-Paper Module (B): https://www.waveshare.com/wiki/2.9inch_e-PaperModule(B) This is a three-color version

When I try this code it return me a Busy Timeout!: Icon name: 01n Icon name: 01n Icon name: 01d Busy Timeout! Busy Timeout! Busy Timeout! Busy Timeout! Entering 1740-secs of sleep time and nothing move on my screen

1) First question , there are a 0ohm resistor on display . By default position of BS resistor is 0 = 4 line SPI EPD_MiSO is not use, in this case BS resistor must be 1= 3 lines SPI because EPD_MISO = 19 is not implemented ?

2) do you think this code is compatible 2.9inch e-Paper Module (B) three-color

3) Wiring : I am using a ESP32 Devkit static const uint8_t EPD_BUSY = 4; // GPIO4 to EPD BUSY static const uint8_t EPD_RST = 16; // GPIO16 to EPD RST static const uint8_t EPD_DC = 17; // GPIO17 to EPD DC static const uint8_t EPD_CS = 5; // GPIO5 to EPD CS static const uint8_t EPD_SCK = 18; // GPIO18 to EPD CLK static const uint8_t EPD_MOSI = 23; // GPIO23 to EPD DIN

IMG_20200718_210751

Regards

Richard

G6EJD commented 4 years ago

Yes the code will work on a 3C display. You have to ensure the display is wired as per your pin definitions but you can’t deviate from the standard SPI wiring for MOSI, SCK, Etc. You have to select the correct display driver for a colour display, if you look at the GxEPD2 examples you will see an ESP32 example line fir the 2.9” 3C display copy that and replace the current one with that, just one line amended. To get other colours you will need to add new colour options in place of black. Note the 3C displays are very slow typically 12-secs to update

G6EJD commented 4 years ago

You need the 4-line SPI switch position, are you using a v2 HAT ?

G6EJD commented 4 years ago

No your not I should have checked, so assuming the wiring is correct just one line to change

echelon75 commented 4 years ago

You need the 4-line SPI switch position OK I solder RS resistor on 0 position (4lines)

are you using a v2 HAT ? How can know version ? Here is rear of display: IMG_20200718_205045

No your not I should have checked, so assuming the wiring is correct just one line to change What do you mean by "Just one line to change" In your code wiring is : static const uint8_t EPD_BUSY = 4; // GPIO4 to EPD BUSY static const uint8_t EPD_RST = 16; // GPIO16 to EPD RST static const uint8_t EPD_DC = 17; // GPIO17 to EPD DC static const uint8_t EPD_CS = 5; // GPIO5 to EPD CS static const uint8_t EPD_SCK = 18; // GPIO18 to EPD CLK static const uint8_t EPD_MOSI = 23; // GPIO23 to EPD DIN Here my wiring : IMG_20200718_225758 IMG_20200718_225925 IMG_20200718_234817

In GxEPD2_WS_ESP32_Driver wiring is : GxEPD2_3C<GxEPD2_290c, GxEPD2_290c::HEIGHT> display(GxEPD2_290c(/CS=/ 5, /DC=/ 17, /RST=/ 16, /BUSY=/ 4)); Here is modified source code : **`// Display Library example for SPI e-paper panels from Dalian Good Display and boards from Waveshare. // Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines! // // Display Library based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html // // Author: Jean-Marc Zingg // // Version: see library.properties // // Library: https://github.com/ZinggJM/GxEPD2

// GxEPD2_WS_ESP32_Driver : GxEPD2_Example variant for Universal e-Paper Raw Panel Driver Board, ESP32 WiFi / Bluetooth Wireless // https://www.waveshare.com/product/e-paper-esp32-driver-board.htm

// Supporting Arduino Forum Topics: // Waveshare e-paper displays with SPI: http://forum.arduino.cc/index.php?topic=487007.0 // Good Display ePaper for Arduino: https://forum.arduino.cc/index.php?topic=436411.0

// mapping of Waveshare ESP32 Driver Board // BUSY -> 25, RST -> 26, DC -> 27, CS-> 15, CLK -> 13, DIN -> 14

// NOTE: this board uses "unusual" SPI pins and requires re-mapping of HW SPI to these pins in SPIClass // this example shows how this can be done easily

// base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter, uses ~1.2k more code // enable or disable GxEPD2_GFX base class

define ENABLE_GxEPD2_GFX 0

// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX //#include // Note: if you use this with ENABLE_GxEPD2_GFX 1: // uncomment it in GxEPD2_GFX.h too, or add #include before any #include

include

include

include <Fonts/FreeMonoBold9pt7b.h>

if defined(ESP32)

// for mapping of Waveshare ESP32 Driver Board // use Board "ESP32 Dev Module" to build with Arduino IDE // select one, can use full buffer size (full HEIGHT) //GxEPD2_BW<GxEPD2_154, GxEPD2_154::HEIGHT> display(GxEPD2_154(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEP015OC1 no longer available //GxEPD2_BW<GxEPD2_154_D67, GxEPD2_154_D67::HEIGHT> display(GxEPD2_154_D67(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEH0154D67 //GxEPD2_BW<GxEPD2_154_T8, GxEPD2_154_T8::HEIGHT> display(GxEPD2_154_T8(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEW0154T8 152x152 //GxEPD2_BW<GxEPD2_154_M09, GxEPD2_154_M09::HEIGHT> display(GxEPD2_154_M09(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEW0154M09 200x200 //GxEPD2_BW<GxEPD2_154_M10, GxEPD2_154_M10::HEIGHT> display(GxEPD2_154_M10(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEW0154M10 152x152 //GxEPD2_BW<GxEPD2_213, GxEPD2_213::HEIGHT> display(GxEPD2_213(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDE0213B1, phased out //GxEPD2_BW<GxEPD2_213_B72, GxEPD2_213_B72::HEIGHT> display(GxEPD2_213_B72(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEH0213B72 //GxEPD2_BW<GxEPD2_213_B73, GxEPD2_213_B73::HEIGHT> display(GxEPD2_213_B73(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEH0213B73 //GxEPD2_BW<GxEPD2_213_flex, GxEPD2_213_flex::HEIGHT> display(GxEPD2_213_flex(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEW0213I5F //GxEPD2_BW<GxEPD2_290, GxEPD2_290::HEIGHT> display(GxEPD2_290(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_290_T5, GxEPD2_290_T5::HEIGHT> display(GxEPD2_290_T5(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEW029T5 //GxEPD2_BW<GxEPD2_260, GxEPD2_260::HEIGHT> display(GxEPD2_260(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_270, GxEPD2_270::HEIGHT> display(GxEPD2_270(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_371, GxEPD2_371::HEIGHT> display(GxEPD2_371(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_420, GxEPD2_420::HEIGHT> display(GxEPD2_420(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_583, GxEPD2_583::HEIGHT> display(GxEPD2_583(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_583_T8, GxEPD2_583_T8::HEIGHT> display(GxEPD2_583_T8(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_750, GxEPD2_750::HEIGHT> display(GxEPD2_750(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_BW<GxEPD2_750_T7, GxEPD2_750_T7::HEIGHT> display(GxEPD2_750_T7(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEW075T7 800x480 // 3-color e-papers //GxEPD2_3C<GxEPD2_154c, GxEPD2_154c::HEIGHT> display(GxEPD2_154c(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_3C<GxEPD2_213c, GxEPD2_213c::HEIGHT> display(GxEPD2_213c(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); GxEPD2_3C<GxEPD2_290c, GxEPD2_290c::HEIGHT> display(GxEPD2_290c(/CS=/ 5, /DC=/ 17, /RST=/ 16, /BUSY=/ 4)); //GxEPD2_3C<GxEPD2_270c, GxEPD2_270c::HEIGHT> display(GxEPD2_270c(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_3C<GxEPD2_420c, GxEPD2_420c::HEIGHT> display(GxEPD2_420c(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_3C<GxEPD2_583c, GxEPD2_583c::HEIGHT> display(GxEPD2_583c(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_3C<GxEPD2_750c, GxEPD2_750c::HEIGHT> display(GxEPD2_750c(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); //GxEPD2_3C<GxEPD2_750c_Z08, GxEPD2_750c_Z08::HEIGHT> display(GxEPD2_750c_Z08(/CS=/ 15, /DC=/ 27, /RST=/ 26, /BUSY=/ 25)); // GDEW075Z08 800x480

endif

// comment out unused bitmaps to reduce code space used //#include "bitmaps/Bitmaps200x200.h" // 1.54" b/w //#include "bitmaps/Bitmaps104x212.h" // 2.13" b/w flexible GDEW0213I5F //#include "bitmaps/Bitmaps128x250.h" // 2.13" b/w //#include "bitmaps/Bitmaps128x296.h" // 2.9" b/w //#include "bitmaps/Bitmaps176x264.h" // 2.7" b/w //#include "bitmaps/Bitmaps400x300.h" // 4.2" b/w //#include "bitmaps/Bitmaps640x384.h" // 7.5" b/w // 3-color //#include "bitmaps/Bitmaps3c200x200.h" // 1.54" b/w/r //#include "bitmaps/Bitmaps3c104x212.h" // 2.13" b/w/r

include "bitmaps/Bitmaps3c128x296.h" // 2.9" b/w/r

//#include "bitmaps/Bitmaps3c176x264.h" // 2.7" b/w/r //#include "bitmaps/Bitmaps3c400x300.h" // 4.2" b/w/r

void setup() { Serial.begin(115200); Serial.println(); Serial.println("setup"); display.init(115200); // uses standard SPI pins, e.g. SCK(18), MISO(19), MOSI(23), SS(5) // special handling for Waveshare ESP32 Driver board // // *** // SPI.end(); // release standard SPI pins, e.g. SCK(18), MISO(19), MOSI(23), SS(5) //SPI: void begin(int8_t sck=-1, int8_t miso=-1, int8_t mosi=-1, int8_t ss=-1); SPI.begin(13, 12, 14, 15); // map and init SPI pins SCK(13), MISO(12), MOSI(14), SS(15) // * end of special handling for Waveshare ESP32 Driver board * // // ** // // first update should be full refresh helloWorld(); delay(1000); // partial refresh mode can be used to full screen, // effective if display panel hasFastPartialUpdate helloFullScreenPartialMode(); delay(1000); helloArduino(); delay(1000); helloEpaper(); delay(1000); showFont("FreeMonoBold9pt7b", &FreeMonoBold9pt7b); delay(1000); drawBitmaps(); if (display.epd2.hasPartialUpdate) { showPartialUpdate(); delay(1000); } // else // on GDEW0154Z04 only full update available, doesn't look nice //drawCornerTest(); //showBox(16, 16, 48, 32, false); //showBox(16, 56, 48, 32, true); display.powerOff(); deepSleepTest(); Serial.println("setup done"); }

void loop() { }

// note for partial update window and setPartialWindow() method: // partial update window size and position is on byte boundary in physical x direction // the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation // see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow()

const char HelloWorld[] = "Hello World!"; const char HelloArduino[] = "Hello Arduino!"; const char HelloEpaper[] = "Hello E-Paper!";

void helloWorld() { //Serial.println("helloWorld"); display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); // center bounding box by transposition of origin: uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2) - tby; display.setFullWindow(); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(x, y); display.print(HelloWorld); } while (display.nextPage()); //Serial.println("helloWorld done"); }

void helloWorldForDummies() { //Serial.println("helloWorld"); const char text[] = "Hello World!"; // most e-papers have width < height (portrait) as native orientation, especially the small ones // in GxEPD2 rotation 0 is used for native orientation (most TFT libraries use 0 fix for portrait orientation) // set rotation to 1 (rotate right 90 degrees) to have enough space on small displays (landscape) display.setRotation(1); // select a suitable font in Adafruit_GFX display.setFont(&FreeMonoBold9pt7b); // on e-papers black on white is more pleasant to read display.setTextColor(GxEPD_BLACK); // Adafruit_GFX has a handy method getTextBounds() to determine the boundary box for a text for the actual font int16_t tbx, tby; uint16_t tbw, tbh; // boundary box window display.getTextBounds(text, 0, 0, &tbx, &tby, &tbw, &tbh); // it works for origin 0, 0, fortunately (negative tby!) // center bounding box by transposition of origin: uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2) - tby; // full window mode is the initial mode, set it anyway display.setFullWindow(); // here we use paged drawing, even if the processor has enough RAM for full buffer // so this can be used with any supported processor board. // the cost in code overhead and execution time penalty is marginal // tell the graphics class to use paged drawing mode display.firstPage(); do { // this part of code is executed multiple times, as many as needed, // in case of full buffer it is executed once // IMPORTANT: each iteration needs to draw the same, to avoid strange effects // use a copy of values that might change, don't read e.g. from analog or pins in the loop! display.fillScreen(GxEPD_WHITE); // set the background to white (fill the buffer with value for white) display.setCursor(x, y); // set the postition to start printing text display.print(text); // print some text // end of part executed multiple times } // tell the graphics class to transfer the buffer content (page) to the controller buffer // the graphics class will command the controller to refresh to the screen when the last page has been transferred // returns true if more pages need be drawn and transferred // returns false if the last page has been transferred and the screen refreshed for panels without fast partial update // returns false for panels with fast partial update when the controller buffer has been written once more, to make the differential buffers equal // (for full buffered with fast partial update the (full) buffer is just transferred again, and false returned) while (display.nextPage()); //Serial.println("helloWorld done"); }

void helloFullScreenPartialMode() { //Serial.println("helloFullScreenPartialMode"); const char fullscreen[] = "full screen update"; const char fpm[] = "fast partial mode"; const char spm[] = "slow partial mode"; const char npm[] = "no partial mode"; display.setPartialWindow(0, 0, display.width(), display.height()); display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); const char updatemode; if (display.epd2.hasFastPartialUpdate) { updatemode = fpm; } else if (display.epd2.hasPartialUpdate) { updatemode = spm; } else { updatemode = npm; } // do this outside of the loop int16_t tbx, tby; uint16_t tbw, tbh; // center update text display.getTextBounds(fullscreen, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t utx = ((display.width() - tbw) / 2) - tbx; uint16_t uty = ((display.height() / 4) - tbh / 2) - tby; // center update mode display.getTextBounds(updatemode, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t umx = ((display.width() - tbw) / 2) - tbx; uint16_t umy = ((display.height() 3 / 4) - tbh / 2) - tby; // center HelloWorld display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t hwx = ((display.width() - tbw) / 2) - tbx; uint16_t hwy = ((display.height() - tbh) / 2) - tby; display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(hwx, hwy); display.print(HelloWorld); display.setCursor(utx, uty); display.print(fullscreen); display.setCursor(umx, umy); display.print(updatemode); } while (display.nextPage()); //Serial.println("helloFullScreenPartialMode done"); }

void helloArduino() { //Serial.println("helloArduino"); display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; // align with centered HelloWorld display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t x = ((display.width() - tbw) / 2) - tbx; // height might be different display.getTextBounds(HelloArduino, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t y = ((display.height() / 4) - tbh / 2) - tby; // y is base line! // make the window big enough to cover (overwrite) descenders of previous text uint16_t wh = FreeMonoBold9pt7b.yAdvance; uint16_t wy = (display.height() / 4) - wh / 2; display.setPartialWindow(0, wy, display.width(), wh); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); //display.drawRect(x, y - tbh, tbw, tbh, GxEPD_BLACK); display.setCursor(x, y); display.print(HelloArduino); } while (display.nextPage()); delay(1000); //Serial.println("helloArduino done"); }

void helloEpaper() { //Serial.println("helloEpaper"); display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(display.epd2.hasColor ? GxEPD_RED : GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; // align with centered HelloWorld display.getTextBounds(HelloWorld, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t x = ((display.width() - tbw) / 2) - tbx; // height might be different display.getTextBounds(HelloEpaper, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t y = (display.height() 3 / 4) + tbh / 2; // y is base line! // make the window big enough to cover (overwrite) descenders of previous text uint16_t wh = FreeMonoBold9pt7b.yAdvance; uint16_t wy = (display.height() 3 / 4) - wh / 2; display.setPartialWindow(0, wy, display.width(), wh); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(x, y); display.print(HelloEpaper); } while (display.nextPage()); //Serial.println("helloEpaper done"); }

void deepSleepTest() { //Serial.println("deepSleepTest"); const char hibernating[] = "hibernating ..."; const char wokeup[] = "woke up"; const char from[] = "from deep sleep"; const char again[] = "again"; display.setRotation(1); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); int16_t tbx, tby; uint16_t tbw, tbh; // center text display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t x = ((display.width() - tbw) / 2) - tbx; uint16_t y = ((display.height() - tbh) / 2) - tby; display.setFullWindow(); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(x, y); display.print(hibernating); } while (display.nextPage()); display.hibernate(); delay(5000); display.getTextBounds(wokeup, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t wx = (display.width() - tbw) / 2; uint16_t wy = (display.height() / 3) + tbh / 2; // y is base line! display.getTextBounds(from, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t fx = (display.width() - tbw) / 2; uint16_t fy = (display.height() 2 / 3) + tbh / 2; // y is base line! display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(wx, wy); display.print(wokeup); display.setCursor(fx, fy); display.print(from); } while (display.nextPage()); delay(5000); display.getTextBounds(hibernating, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t hx = (display.width() - tbw) / 2; uint16_t hy = (display.height() / 3) + tbh / 2; // y is base line! display.getTextBounds(again, 0, 0, &tbx, &tby, &tbw, &tbh); uint16_t ax = (display.width() - tbw) / 2; uint16_t ay = (display.height() 2 / 3) + tbh / 2; // y is base line! display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.setCursor(hx, hy); display.print(hibernating); display.setCursor(ax, ay); display.print(again); } while (display.nextPage()); display.hibernate(); //Serial.println("deepSleepTest done"); }

void showBox(uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool partial) { //Serial.println("showBox"); display.setRotation(1); if (partial) { display.setPartialWindow(x, y, w, h); } else { display.setFullWindow(); } display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.fillRect(x, y, w, h, GxEPD_BLACK); } while (display.nextPage()); //Serial.println("showBox done"); }

void drawCornerTest() { display.setFullWindow(); display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); for (uint16_t r = 0; r <= 4; r++) { display.setRotation(r); display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.fillRect(0, 0, 8, 8, GxEPD_BLACK); display.fillRect(display.width() - 18, 0, 16, 16, GxEPD_BLACK); display.fillRect(display.width() - 25, display.height() - 25, 24, 24, GxEPD_BLACK); display.fillRect(0, display.height() - 33, 32, 32, GxEPD_BLACK); display.setCursor(display.width() / 2, display.height() / 2); display.print(display.getRotation()); } while (display.nextPage()); delay(2000); } }

void showFont(const char name[], const GFXfont* f) { display.setFullWindow(); display.setRotation(0); display.setTextColor(GxEPD_BLACK); display.firstPage(); do { drawFont(name, f); } while (display.nextPage()); }

void drawFont(const char name[], const GFXfont f) { //display.setRotation(0); display.fillScreen(GxEPD_WHITE); display.setTextColor(GxEPD_BLACK); display.setFont(f); display.setCursor(0, 0); display.println(); display.println(name); display.println(" !\"#$%&'()+,-./"); display.println("0123456789:;<=>?"); display.println("@ABCDEFGHIJKLMNO"); display.println("PQRSTUVWXYZ[\]^_"); if (display.epd2.hasColor) { display.setTextColor(GxEPD_RED); } display.println("`abcdefghijklmno"); display.println("pqrstuvwxyz{|}~ "); }

// note for partial update window and setPartialWindow() method: // partial update window size and position is on byte boundary in physical x direction // the size is increased in setPartialWindow() if x or w are not multiple of 8 for even rotation, y or h for odd rotation // see also comment in GxEPD2_BW.h, GxEPD2_3C.h or GxEPD2_GFX.h for method setPartialWindow() // showPartialUpdate() purposely uses values that are not multiples of 8 to test this

void showPartialUpdate() { // some useful background helloWorld(); // use asymmetric values for test uint16_t box_x = 10; uint16_t box_y = 15; uint16_t box_w = 70; uint16_t box_h = 20; uint16_t cursor_y = box_y + box_h - 6; float value = 13.95; uint16_t incr = display.epd2.hasFastPartialUpdate ? 1 : 3; display.setFont(&FreeMonoBold9pt7b); display.setTextColor(GxEPD_BLACK); // show where the update box is for (uint16_t r = 0; r < 4; r++) { display.setRotation(r); display.setPartialWindow(box_x, box_y, box_w, box_h); display.firstPage(); do { display.fillRect(box_x, box_y, box_w, box_h, GxEPD_BLACK); //display.fillScreen(GxEPD_BLACK); } while (display.nextPage()); delay(2000); display.firstPage(); do { display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); } while (display.nextPage()); delay(1000); } //return; // show updates in the update box for (uint16_t r = 0; r < 4; r++) { display.setRotation(r); display.setPartialWindow(box_x, box_y, box_w, box_h); for (uint16_t i = 1; i <= 10; i += incr) { display.firstPage(); do { display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); display.setCursor(box_x, cursor_y); display.print(value * i, 2); } while (display.nextPage()); delay(500); } delay(1000); display.firstPage(); do { display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE); } while (display.nextPage()); delay(1000); } }

void drawBitmaps() { display.setFullWindow();

ifdef _GxBitmaps104x212H

drawBitmaps104x212();

endif

ifdef _GxBitmaps128x250H

drawBitmaps128x250();

endif

ifdef _GxBitmaps128x296H

drawBitmaps128x296();

endif

ifdef _GxBitmaps176x264H

drawBitmaps176x264();

endif

ifdef _GxBitmaps400x300H

drawBitmaps400x300();

endif

ifdef _GxBitmaps640x384H

drawBitmaps640x384();

endif

ifdef _WS_Bitmaps800x600H

drawBitmaps800x600();

endif

// 3-color

ifdef _GxBitmaps3c104x212H

drawBitmaps3c104x212();

endif

ifdef _GxBitmaps3c128x296H

drawBitmaps3c128x296();

endif

ifdef _GxBitmaps3c176x264H

drawBitmaps3c176x264();

endif

ifdef _GxBitmaps3c400x300H

drawBitmaps3c400x300();

endif

// show these after the specific bitmaps

ifdef _GxBitmaps200x200H

drawBitmaps200x200();

endif

// 3-color

ifdef _GxBitmaps3c200x200H

drawBitmaps3c200x200();

endif

}

ifdef _GxBitmaps200x200H

void drawBitmaps200x200() {

if defined(__AVR)

const unsigned char* bitmaps[] = { logo200x200, first200x200 //, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200 };

elif defined(_BOARD_GENERIC_STM32F103CH)

const unsigned char* bitmaps[] = { logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200 //, sixth200x200, senventh200x200, eighth200x200 };

else

const unsigned char* bitmaps[] = { logo200x200, first200x200, second200x200, third200x200, fourth200x200, fifth200x200, sixth200x200, senventh200x200, eighth200x200 };

endif

if ((display.epd2.panel == GxEPD2::GDEP015OC1) || (display.epd2.panel == GxEPD2::GDEH0154D67)) { bool m = display.mirror(true); for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } while (display.nextPage()); delay(2000); } display.mirror(m); } //else { bool mirror_y = (display.epd2.panel != GxEPD2::GDE0213B1); display.clearScreen(); // use default for white int16_t x = (int16_t(display.epd2.WIDTH) - 200) / 2; int16_t y = (int16_t(display.epd2.HEIGHT) - 200) / 2; for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char); i++) { display.drawImage(bitmaps[i], x, y, 200, 200, false, mirror_y, true); delay(2000); } } bool mirror_y = (display.epd2.panel != GxEPD2::GDE0213B1); for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) { int16_t x = -60; int16_t y = -60; for (uint16_t j = 0; j < 10; j++) { display.writeScreenBuffer(); // use default for white display.writeImage(bitmaps[i], x, y, 200, 200, false, mirror_y, true); display.refresh(true); if (display.epd2.hasFastPartialUpdate) { // for differential update: set previous buffer equal to current buffer in controller display.epd2.writeScreenBufferAgain(); // use default for white display.epd2.writeImageAgain(bitmaps[i], x, y, 200, 200, false, mirror_y, true); } delay(2000); x += 40; y += 40; if ((x >= int16_t(display.epd2.WIDTH)) || (y >= int16_t(display.epd2.HEIGHT))) break; } if (!display.epd2.hasFastPartialUpdate) break; // comment out for full show break; // comment out for full show } display.writeScreenBuffer(); // use default for white display.writeImage(bitmaps[0], int16_t(0), 0, 200, 200, false, mirror_y, true); display.writeImage(bitmaps[0], int16_t(int16_t(display.epd2.WIDTH) - 200), int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, mirror_y, true); display.refresh(true); delay(2000); }

endif

ifdef _GxBitmaps104x212H

void drawBitmaps104x212() {

if !defined(__AVR)

const unsigned char* bitmaps[] = { WS_Bitmap104x212, Bitmap104x212_1, Bitmap104x212_2, Bitmap104x212_3 };

else

const unsigned char* bitmaps[] = { WS_Bitmap104x212, Bitmap104x212_1, Bitmap104x212_2, Bitmap104x212_3 };

endif

if (display.epd2.panel == GxEPD2::GDEW0213I5F) { for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } while (display.nextPage()); delay(2000); } } }

endif

ifdef _GxBitmaps128x250H

void drawBitmaps128x250() {

if !defined(__AVR)

const unsigned char* bitmaps[] = { Bitmap128x250_1, logo128x250, first128x250, second128x250, third128x250 };

else

const unsigned char* bitmaps[] = { Bitmap128x250_1, logo128x250, first128x250, second128x250, third128x250 };

endif

if ((display.epd2.panel == GxEPD2::GDE0213B1) || (display.epd2.panel == GxEPD2::GDEH0213B72)) { bool m = display.mirror(true); for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } while (display.nextPage()); delay(2000); } display.mirror(m); } }

endif

ifdef _GxBitmaps128x296H

void drawBitmaps128x296() {

if !defined(__AVR)

const unsigned char* bitmaps[] = { Bitmap128x296_1, logo128x296, first128x296, second128x296, third128x296 };

else

const unsigned char* bitmaps[] = { Bitmap128x296_1, logo128x296 //, first128x296, second128x296, third128x296 };

endif

if (display.epd2.panel == GxEPD2::GDEH029A1) { bool m = display.mirror(true); for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } while (display.nextPage()); delay(2000); } display.mirror(m); } }

endif

ifdef _GxBitmaps176x264H

void drawBitmaps176x264() {

if !defined(__AVR)

const unsigned char* bitmaps[] = { Bitmap176x264_1, Bitmap176x264_2, Bitmap176x264_3, Bitmap176x264_4, Bitmap176x264_5 };

else

const unsigned char* bitmaps[] = { Bitmap176x264_1, Bitmap176x264_2 //, Bitmap176x264_3, Bitmap176x264_4, Bitmap176x264_5 };

endif

if (display.epd2.panel == GxEPD2::GDEW027W3) { for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } while (display.nextPage()); delay(2000); } } }

endif

ifdef _GxBitmaps400x300H

void drawBitmaps400x300() {

if !defined(__AVR)

const unsigned char* bitmaps[] = { Bitmap400x300_1, Bitmap400x300_2 };

else

const unsigned char* bitmaps[] = {}; // not enough code space

endif

if (display.epd2.panel == GxEPD2::GDEW042T2) { for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } while (display.nextPage()); delay(2000); } } }

endif

ifdef _GxBitmaps640x384H

void drawBitmaps640x384() {

if !defined(__AVR)

const unsigned char* bitmaps[] = { Bitmap640x384_1, Bitmap640x384_2 };

else

const unsigned char* bitmaps[] = {}; // not enough code space

endif

if ((display.epd2.panel == GxEPD2::GDEW075T8) || (display.epd2.panel == GxEPD2::GDEW075Z09)) { for (uint16_t i = 0; i < sizeof(bitmaps) / sizeof(char*); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmaps[i], display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); } while (display.nextPage()); delay(2000); } } }

endif

ifdef _WS_Bitmaps800x600H

void drawBitmaps800x600() {

if defined(ESP8266) || defined(ESP32)

if (display.epd2.panel == GxEPD2::ED060SCT) { // Serial.print("sizeof(WS_zoo_800x600) is "); Serial.println(sizeof(WS_zoo_800x600)); display.drawNative(WS_zoo_800x600, 0, 0, 0, 800, 600, false, false, true); delay(2000); // Serial.print("sizeof(WS_pic_1200x825) is "); Serial.println(sizeof(WS_pic_1200x825)); // display.drawNative((const uint8_t*)WS_pic_1200x825, 0, 0, 0, 1200, 825, false, false, true); // delay(2000); // Serial.print("sizeof(WS_acaa_1024x731) is "); Serial.println(sizeof(WS_acaa_1024x731)); // display.drawNative(WS_acaa_1024x731, 0, 0, 0, 1024, 731, false, false, true); // delay(2000); }

endif

}

endif

struct bitmap_pair { const unsigned char black; const unsigned char red; };

ifdef _GxBitmaps3c200x200H

void drawBitmaps3c200x200() { bitmap_pair bitmap_pairs[] = { //{Bitmap3c200x200_black, Bitmap3c200x200_red}, {WS_Bitmap3c200x200_black, WS_Bitmap3c200x200_red} }; if (display.epd2.panel == GxEPD2::GDEW0154Z04) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); // Bitmap3c200x200_black has 2 bits per pixel // taken from Adafruit_GFX.cpp, modified int16_t byteWidth = (display.epd2.WIDTH + 7) / 8; // Bitmap scanline pad = whole byte uint8_t byte = 0; for (int16_t j = 0; j < display.epd2.HEIGHT; j++) { for (int16_t i = 0; i < display.epd2.WIDTH; i++) { if (i & 3) byte <<= 2; else {

if defined(__AVR) || defined(ESP8266) || defined(ESP32)

        byte = pgm_read_byte(&Bitmap3c200x200_black[j * byteWidth * 2 + i / 4]);

else

        byte = Bitmap3c200x200_black[j * byteWidth * 2 + i / 4];

endif

      }
      if (!(byte & 0x80))
      {
        display.drawPixel(i, j, GxEPD_BLACK);
      }
    }
  }
  display.drawInvertedBitmap(0, 0, Bitmap3c200x200_red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED);
}
while (display.nextPage());
delay(2000);
for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++)
{
  display.firstPage();
  do
  {
    display.fillScreen(GxEPD_WHITE);
    display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK);
    display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED);
  }
  while (display.nextPage());
  delay(2000);
}

} if (display.epd2.hasColor) { display.clearScreen(); // use default for white int16_t x = (int16_t(display.epd2.WIDTH) - 200) / 2; int16_t y = (int16_t(display.epd2.HEIGHT) - 200) / 2; for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) { display.drawImage(bitmap_pairs[i].black, bitmap_pairs[i].red, x, y, 200, 200, false, false, true); delay(2000); } for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) { int16_t x = -60; int16_t y = -60; for (uint16_t j = 0; j < 10; j++) { display.writeScreenBuffer(); // use default for white display.writeImage(bitmap_pairs[i].black, bitmap_pairs[i].red, x, y, 200, 200, false, false, true); display.refresh(); delay(1000); x += 40; y += 40; if ((x >= int16_t(display.epd2.WIDTH)) || (y >= int16_t(display.epd2.HEIGHT))) break; } } display.writeScreenBuffer(); // use default for white display.writeImage(bitmap_pairs[0].black, bitmap_pairs[0].red, 0, 0, 200, 200, false, false, true); display.writeImage(bitmap_pairs[0].black, bitmap_pairs[0].red, int16_t(display.epd2.WIDTH) - 200, int16_t(display.epd2.HEIGHT) - 200, 200, 200, false, false, true); display.refresh(); delay(2000); } }

endif

ifdef _GxBitmaps3c104x212H

void drawBitmaps3c104x212() {

if !defined(__AVR)

bitmap_pair bitmap_pairs[] = { {Bitmap3c104x212_1_black, Bitmap3c104x212_1_red}, {Bitmap3c104x212_2_black, Bitmap3c104x212_2_red}, {WS_Bitmap3c104x212_black, WS_Bitmap3c104x212_red} };

else

bitmap_pair bitmap_pairs[] = { {Bitmap3c104x212_1_black, Bitmap3c104x212_1_red}, //{Bitmap3c104x212_2_black, Bitmap3c104x212_2_red}, {WS_Bitmap3c104x212_black, WS_Bitmap3c104x212_red} };

endif

if (display.epd2.panel == GxEPD2::GDEW0213Z16) { for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); if (bitmap_pairs[i].red == WS_Bitmap3c104x212_red) { display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); } else display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); } while (display.nextPage()); delay(2000); } } }

endif

ifdef _GxBitmaps3c128x296H

void drawBitmaps3c128x296() {

if !defined(__AVR)

bitmap_pair bitmap_pairs[] = { {Bitmap3c128x296_1_black, Bitmap3c128x296_1_red}, {Bitmap3c128x296_2_black, Bitmap3c128x296_2_red}, {WS_Bitmap3c128x296_black, WS_Bitmap3c128x296_red} };

else

bitmap_pair bitmap_pairs[] = { //{Bitmap3c128x296_1_black, Bitmap3c128x296_1_red}, //{Bitmap3c128x296_2_black, Bitmap3c128x296_2_red}, {WS_Bitmap3c128x296_black, WS_Bitmap3c128x296_red} };

endif

if (display.epd2.panel == GxEPD2::GDEW029Z10) { for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); if (bitmap_pairs[i].red == WS_Bitmap3c128x296_red) { display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); } else display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); } while (display.nextPage()); delay(2000); } } }

endif

ifdef _GxBitmaps3c176x264H

void drawBitmaps3c176x264() { bitmap_pair bitmap_pairs[] = { {Bitmap3c176x264_black, Bitmap3c176x264_red} }; if (display.epd2.panel == GxEPD2::GDEW027C44) { for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); display.drawBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); } while (display.nextPage()); delay(2000); } } }

endif

ifdef _GxBitmaps3c400x300H

void drawBitmaps3c400x300() {

if !defined(__AVR)

bitmap_pair bitmap_pairs[] = { {Bitmap3c400x300_1_black, Bitmap3c400x300_1_red}, {Bitmap3c400x300_2_black, Bitmap3c400x300_2_red}, {WS_Bitmap3c400x300_black, WS_Bitmap3c400x300_red} };

else

bitmap_pair bitmap_pairs[] = {}; // not enough code space

endif

if (display.epd2.panel == GxEPD2::GDEW042Z15) { for (uint16_t i = 0; i < sizeof(bitmap_pairs) / sizeof(bitmap_pair); i++) { display.firstPage(); do { display.fillScreen(GxEPD_WHITE); display.drawInvertedBitmap(0, 0, bitmap_pairs[i].black, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_BLACK); display.drawInvertedBitmap(0, 0, bitmap_pairs[i].red, display.epd2.WIDTH, display.epd2.HEIGHT, GxEPD_RED); } while (display.nextPage()); delay(2000); } } }

endif**`

But display doesn't display anything. I order a new monochrome display in case of mine is dead . I will receive it on 23/07 I keep you in touch...

Regards

Richard

G6EJD commented 4 years ago

Hello Richard, your pin setup and wiring looks OK, as does the 3C display object setting, so the code should be working. I can see it is receiving weather data OK, so it's down to the display.

Have you tried any of the GxEPD2 3C examples, they should all work as I use the default wiring in my code too.

You do-not need to change the display to a 4-line SPI, mine all work OK on 3-line setting.

This is a display issue (hardware) or wiring, be sure those du-pont cables are actually making contact end-to-end they are notoriously unreliable for connections.