Heltec Wireless Paper, VM-E213 Hardware Revisions (#7258)

* Tests to identify display model

* (InkHUD) SSD1682 controller IC
Has a few quirks, gets its own base class

* (InkHUD) E0213A367 Display
For Heltec Wireless Paper V1.1.1, V1.2
For Heltec VM-E213 V1.1

* (InkHUD) Select display model at boot

* (BaseUI) Wrapper to combine multiple GxEPD2 drivers
Workaround for issue of GxEPD2_BW objects not having a shared base class. Allows us to select a driver at runtime.
https://github.com/meshtastic/firmware/issues/6851#issuecomment-2905353447

* (BaseUI) Select E-Ink model at boot

* (InkHUD) SSD1682 deep sleep

* (InkHUD) No deep sleep for SSD1682

* (InkHUD) Fully no-op deep sleep for SSD1682
This commit is contained in:
todd-herbert
2025-07-09 06:01:48 +12:00
committed by GitHub
parent 9c08220d24
commit db4e4e6e53
13 changed files with 483 additions and 14 deletions

View File

@@ -0,0 +1,35 @@
#pragma once
#include "configuration.h"
enum class EInkDetectionResult : uint8_t {
LCMEN213EFC1 = 0, // Initial version
E0213A367 = 1, // E213 PCB marked V1.1 (Mid 2025)
};
EInkDetectionResult detectEInk()
{
// Test 1: Logic of BUSY pin
// Determines controller IC manufacturer
// Fitipower: busy when LOW
// Solomon Systech: busy when HIGH
// Force display BUSY by holding reset pin active
pinMode(PIN_EINK_RES, OUTPUT);
digitalWrite(PIN_EINK_RES, LOW);
delay(10);
// Read whether pin is HIGH or LOW while busy
pinMode(PIN_EINK_BUSY, INPUT);
bool busyLogic = digitalRead(PIN_EINK_BUSY);
// Test complete. Release pin
pinMode(PIN_EINK_RES, INPUT);
if (busyLogic == LOW)
return EInkDetectionResult::LCMEN213EFC1;
else // busy HIGH
return EInkDetectionResult::E0213A367;
}

View File

@@ -18,16 +18,22 @@
// Shared NicheGraphics components
// --------------------------------
#include "graphics/niche/Drivers/EInk/E0213A367.h"
#include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h"
#include "graphics/niche/Inputs/TwoButton.h"
// Button feedback
#include "buzz.h"
#include "buzz.h" // Button feedback
#include "einkDetect.h" // Detect display model at runtime
void setupNicheGraphics()
{
using namespace NicheGraphics;
// Detect E-Ink Model
// -------------------
EInkDetectionResult displayModel = detectEInk();
// SPI
// -----------------------------
@@ -38,7 +44,13 @@ void setupNicheGraphics()
// E-Ink Driver
// -----------------------------
Drivers::EInk *driver = new Drivers::LCMEN213EFC1;
Drivers::EInk *driver;
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1 (unmarked)
driver = new Drivers::LCMEN213EFC1;
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1
driver = new Drivers::E0213A367;
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
// InkHUD
@@ -51,7 +63,11 @@ void setupNicheGraphics()
// Set how many FAST updates per FULL update
// Set how unhealthy additional FAST updates beyond this number are
inkhud->setDisplayResilience(10, 1.5);
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1 (unmarked)
inkhud->setDisplayResilience(10, 1.5);
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1
inkhud->setDisplayResilience(15, 3);
// Select fonts
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;

View File

@@ -7,7 +7,8 @@ build_flags =
-Ivariants/heltec_vision_master_e213
-DHELTEC_VISION_MASTER_E213
-DUSE_EINK
-DEINK_DISPLAY_MODEL=GxEPD2_213_FC1
-DGXEPD2_DRIVER_0=GxEPD2_213_FC1
-DGXEPD2_DRIVER_1=GxEPD2_213_E0213A367
-DEINK_WIDTH=250
-DEINK_HEIGHT=122
-DUSE_EINK_DYNAMICDISPLAY ; Enable Dynamic EInk
@@ -16,7 +17,7 @@ build_flags =
-DEINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
lib_deps =
${esp32s3_base.lib_deps}
https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip
https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip
lewisxhe/PCF8563_Library@^1.0.1
upload_speed = 115200

View File

@@ -0,0 +1,35 @@
#pragma once
#include "configuration.h"
enum class EInkDetectionResult : uint8_t {
LCMEN213EFC1 = 0, // V1.1
E0213A367 = 1, // V1.1.1, V1.2
};
EInkDetectionResult detectEInk()
{
// Test 1: Logic of BUSY pin
// Determines controller IC manufacturer
// Fitipower: busy when LOW
// Solomon Systech: busy when HIGH
// Force display BUSY by holding reset pin active
pinMode(PIN_EINK_RES, OUTPUT);
digitalWrite(PIN_EINK_RES, LOW);
delay(10);
// Read whether pin is HIGH or LOW while busy
pinMode(PIN_EINK_BUSY, INPUT);
bool busyLogic = digitalRead(PIN_EINK_BUSY);
// Test complete. Release pin
pinMode(PIN_EINK_RES, INPUT);
if (busyLogic == LOW)
return EInkDetectionResult::LCMEN213EFC1;
else // busy HIGH
return EInkDetectionResult::E0213A367;
}

View File

@@ -18,13 +18,21 @@
// Shared NicheGraphics components
// --------------------------------
#include "graphics/niche/Drivers/EInk/E0213A367.h"
#include "graphics/niche/Drivers/EInk/LCMEN2R13EFC1.h"
#include "graphics/niche/Inputs/TwoButton.h"
#include "einkDetect.h" // Detect display model at runtime
void setupNicheGraphics()
{
using namespace NicheGraphics;
// Detect E-Ink Model
// -------------------
EInkDetectionResult displayModel = detectEInk();
// SPI
// -----------------------------
@@ -35,7 +43,13 @@ void setupNicheGraphics()
// E-Ink Driver
// -----------------------------
Drivers::EInk *driver = new Drivers::LCMEN213EFC1;
Drivers::EInk *driver;
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1.1
driver = new Drivers::LCMEN213EFC1;
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1.1, V1.2
driver = new Drivers::E0213A367;
driver->begin(hspi, PIN_EINK_DC, PIN_EINK_CS, PIN_EINK_BUSY, PIN_EINK_RES);
// InkHUD
@@ -48,7 +62,11 @@ void setupNicheGraphics()
// Set how many FAST updates per FULL update
// Set how unhealthy additional FAST updates beyond this number are
inkhud->setDisplayResilience(10, 1.5);
if (displayModel == EInkDetectionResult::LCMEN213EFC1) // V1.1 (unmarked)
inkhud->setDisplayResilience(10, 1.5);
else if (displayModel == EInkDetectionResult::E0213A367) // V1.1.1, V1.2
inkhud->setDisplayResilience(15, 3);
// Select fonts
InkHUD::Applet::fontLarge = FREESANS_12PT_WIN1252;

View File

@@ -7,7 +7,8 @@ build_flags =
${esp32s3_base.build_flags}
-I variants/heltec_wireless_paper
-D HELTEC_WIRELESS_PAPER
-D EINK_DISPLAY_MODEL=GxEPD2_213_FC1
-D GXEPD2_DRIVER_0=GxEPD2_213_FC1
-D GXEPD2_DRIVER_1=GxEPD2_213_E0213A367
-D EINK_WIDTH=250
-D EINK_HEIGHT=122
-D USE_EINK
@@ -17,7 +18,7 @@ build_flags =
-D EINK_HASQUIRK_GHOSTING ; Display model is identified as "prone to ghosting"
lib_deps =
${esp32s3_base.lib_deps}
https://github.com/meshtastic/GxEPD2/archive/b202ebfec6a4821e098cf7a625ba0f6f2400292d.zip
https://github.com/meshtastic/GxEPD2/archive/1655054ba298e0e29fc2044741940f927f9c2a43.zip
lewisxhe/PCF8563_Library@^1.0.1
upload_speed = 115200