Xinyuan-LilyGO / T-Echo

MIT License
152 stars 22 forks source link

How to use GxEPD2 instead of GxDEPG0150BN - Avoiding screen flickering #48

Closed goedzo closed 1 month ago

goedzo commented 1 month ago

In all the examples GxDEPG0150BN.h is used to display something on the screen. This works partially, because display->updateWindow() makes the screen flicker completely white, even when I only update a small region.

So I want to upgrade to GxEPD2 to avoid flickering and have better control with paging. However I cannot get it to display anything. I use the following code, but not sure why this is not working:

Note that display_v1 is working for the normal GxEPD v1, but the code with display-> does nothing.

#include "utilities.h"
#include <stdint.h>
#include "settings.h"
#include "app_modes.h"
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>
#include <GxDEPG0150BN/GxDEPG0150BN.h>  // 1.54" b/w 
#include "epd/GxEPD2_150_BN.h"
#include <GxEPD2_BW.h>  // For black and white displays

#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>

// E-Paper display initialization
SPIClass        *dispPort  = nullptr;
GxIO_Class      *io        = nullptr;
GxEPD_Class     *display_v1   = nullptr;
GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>* display = nullptr;

void setupDisplay() {

    //This is v1 of GxD that seems to work
    dispPort = new SPIClass(
        /*SPIPORT*/NRF_SPIM2,
        /*MISO*/ ePaper_Miso,
        /*SCLK*/ePaper_Sclk,
        /*MOSI*/ePaper_Mosi);

    io = new GxIO_Class(
        *dispPort,
        /*CS*/ ePaper_Cs,
        /*DC*/ ePaper_Dc,
        /*RST*/ePaper_Rst);

    display_v1 = new GxEPD_Class(
        *io,
        /*RST*/ ePaper_Rst,
        /*BUSY*/ ePaper_Busy);

    dispPort->begin();
    display_v1->init(/*115200*/);
    display_v1->setRotation(3);
    display_v1->fillScreen(GxEPD_WHITE);
    display_v1->setTextColor(GxEPD_BLACK);
    display_v1->setFont(&FreeMonoBold9pt7b);
    display_v1->update();

    //Now let's see if GxEPD2 works aswell
    display = new GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>(GxEPD2_150_BN(ePaper_Cs, ePaper_Dc, ePaper_Rst, ePaper_Busy));
    display->init(115200); // Initialize with baud rate
    display->setRotation(3); // Set display rotation
    display->clearScreen();
    display->setFullWindow(); // Use the full display window
    display->firstPage();     // Start drawing in first page
    do {
        display->fillScreen(GxEPD_WHITE); // Clear the screen
        display->setTextColor(GxEPD_BLACK); // Set text color
        display->setFont(&FreeMonoBold9pt7b); // Set default font
        display->setCursor(0, 100);
        display->print("Hello world!");
    } while (display->nextPage()); // Repeat until all pages are drawn
    display->refresh(false);
    display->display(false);
}
goedzo commented 1 month ago

Here is also a simple helloworld sketch (that you can use completely), which also shows nothing on the screen:

#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Wire.h>
#include <SPI.h>

// Define the display class and the display size
#define GxEPD2_DRIVER_CLASS GxEPD2_150_BN
GxEPD2_BW<GxEPD2_DRIVER_CLASS, GxEPD2_150_BN::HEIGHT> display(GxEPD2_150_BN(
  /*CS=*/ 30,  // ePaper_Cs
  /*DC=*/ 28,  // ePaper_Dc
  /*RST=*/ 2,  // ePaper_Rst
  /*BUSY=*/ 3  // ePaper_Busy
));

void setup() {
  // Wait for Serial Monitor to be connected
  Serial.begin(115200);
  while (!Serial) {
    ; // Wait for the serial connection
  }

  Serial.println("Serial initialized...");

  // Start SPI communication and initialize the display
  Serial.println("Initializing display...");
  display.init(); 
  delay(1000); // Give time for display to initialize
  Serial.println("Display initialized.");

  // Clear the display buffer
  display.setRotation(1); // Rotate display if needed (0-3)
  Serial.println("Display rotation set.");

  display.setTextColor(GxEPD_BLACK);
  Serial.println("Text color set to black.");

  // Print "Hello world" on the screen
  Serial.println("Starting display update...");

  display.firstPage();
  do {
    Serial.println("Clearing the display...");
    display.fillScreen(GxEPD_WHITE); // Clear the display

    Serial.println("Setting font...");
    display.setFont(&FreeMonoBold9pt7b); // Use a built-in font

    Serial.println("Setting cursor position...");
    display.setCursor(10, 40); // Position for the text

    Serial.println("Printing 'Hello world'...");
    display.print("Hello world");
  } while (display.nextPage()); 

  // Refresh the display after drawing
  Serial.println("Refreshing the display...");
  display.refresh(); // This will ensure the content is rendered on the display

  Serial.println("Display refresh finished.");

  // Add delay to allow e-paper to finish update
  delay(5000);
}

void loop() {
  // Nothing to do here
}
goedzo commented 1 month ago

Ok I seem to have found the solution :).

The init of the display needs to get custom SPI variable in order to work:

    // Create SPI settings with speed, data order, and mode
    SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);  // 4 MHz speed, MSB first, SPI mode 0

    //Now let's see if GxEPD2 works aswell
    display = new GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>(GxEPD2_150_BN(ePaper_Cs, ePaper_Dc, ePaper_Rst, ePaper_Busy));
goedzo commented 1 month ago

And in case you need a full example, here is the working "hello world" code completely

#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Wire.h>
#include <SPI.h>

// Declare the display class and custom SPI settings
SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);  // 4 MHz speed, MSB first, SPI mode 0
GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>* display; // Pointer for dynamic allocation
SPIClass* dispPort;

// Pin definitions for the e-paper display
const int ePaper_Miso = 6;  // Define these based on your hardware setup
const int ePaper_Mosi = 29;
const int ePaper_Sclk = 31;
const int ePaper_Cs = 30;
const int ePaper_Dc = 28;
const int ePaper_Rst = 2;
const int ePaper_Busy = 3;

void setup() {
  // Start Serial Monitor
  Serial.begin(115200);
  while (!Serial) {
    ; // Wait for serial to be ready
  }

  Serial.println("Serial initialized...");

  // Create a new SPIClass instance for the e-paper display
  dispPort = new SPIClass(NRF_SPIM2, ePaper_Miso, ePaper_Sclk, ePaper_Mosi);

  // Initialize the SPI port
  dispPort->begin();

  // Dynamically allocate memory for the GxEPD2 display object
  display = new GxEPD2_BW<GxEPD2_150_BN, GxEPD2_150_BN::HEIGHT>(GxEPD2_150_BN(ePaper_Cs, ePaper_Dc, ePaper_Rst, ePaper_Busy));

  // Initialize the display with custom SPI class and settings
  display->init(115200, true, 20, false, *dispPort, spiSettings);
  Serial.println("Display initialized with custom SPI.");

  // Set display rotation, fill screen, and set text properties
  display->setRotation(3);
  display->fillScreen(GxEPD_WHITE);
  display->setTextColor(GxEPD_BLACK);
  display->setFont(&FreeMonoBold9pt7b);

  // Draw "Hello World" on the display
  display->firstPage();
  do {
    display->setCursor(10, 40);
    display->print("Hello world!");
  } while (display->nextPage());

  // Refresh the display to show the content
  display->refresh();

  Serial.println("Display update complete.");
}

void loop() {
  // Nothing to do here
}