* Add shared e-ink hardware layer (graphics/eink) alongside legacy drivers Foundation for a target-by-target migration off the GxEPD2-based EInkDisplay2/EInkDynamicDisplay/EInkParallelDisplay stack: - src/graphics/eink/: chipset drivers, panel profiles, backlight helper (promoted from the InkHUD driver set, shared by BaseUI and InkHUD) - src/graphics/BaseUIEInkDisplay: OLEDDisplay adapter driving the new layer, with EINK_* compat macros matching EInkDynamicDisplay - [niche] build helper in platformio.ini; graphics/eink/ excluded from arduino_base so unconverted targets are unaffected - Screen/CannedMessageModule dispatch between the two stacks per env - InkHUD-specific touch code in TouchScreenImpl1 guarded with MESHTASTIC_INCLUDE_INKHUD (no-op today, required once BaseUI variants define MESHTASTIC_INCLUDE_NICHE_GRAPHICS without InkHUD) No variant is converted and no legacy file is removed; every existing env builds identical firmware. * Fix clang-format comment alignment in Screen.cpp * Address review findings in the e-ink driver layer - Screen.cpp: exclude InkHUD builds from all NicheGraphics BaseUI guards - BaseUIEInkDisplay: size the OLEDDisplay buffer from its actual indexing - EInkParallel: defer update() while an async refresh is in flight, honor the selected clear mode in the async task, never delete a live task - ED047TC1: clean up on failed initPanel, fix inverted bbepI2CWrite checks - UC8175: drop bogus 0x12 soft reset (0x12 is display refresh on UC8175) - LCMEN2R13EFC1: guard absent reset pin, bound the busy wait - SSD16XX/SSD1682: build the RAM window from the instance, not statics - Doc corrections in driver banners and Drivers/README * SSD16XX/SSD1682: send inclusive Y-end address (height - 1) * LCMEN213EFC1: adopt the shared wait timeout / fail-through pattern wait() now bounds the busy poll via Throttle and sets the EInk failed flag on timeout; sendCommand/sendData fail through like the SSD16XX and UC8175 drivers. EInk::runOnce clears the flag after the failed cycle.
84 lines
2.9 KiB
C++
84 lines
2.9 KiB
C++
#include "./E0213A367.h"
|
|
|
|
#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|
|
|
|
using namespace NicheGraphics::Drivers;
|
|
|
|
// Map the display controller IC's output to the connected panel
|
|
void E0213A367::configScanning()
|
|
{
|
|
// "Driver output control"
|
|
// Scan gates from 0 to 249 (vertical resolution 250px)
|
|
sendCommand(0x01);
|
|
sendData(0xF9);
|
|
sendData(0x00);
|
|
}
|
|
|
|
// Specify which information is used to control the sequence of voltages applied to move the pixels
|
|
void E0213A367::configWaveform()
|
|
{
|
|
// This command (0x37) is poorly documented
|
|
// As of July 2025, the datasheet for this display's controller IC is unavailable
|
|
// The values are supplied by Heltec, who presumably have privileged access to information from the display manufacturer
|
|
// Datasheet for the similar SSD1680 IC hints at the function of this command:
|
|
|
|
// "Spare VCOM OTP selection":
|
|
// Unclear why 0x40 is set. Sane values for related SSD1680 seem to be 0x80 or 0x00.
|
|
// Maybe value is redundant? No noticeable impact when set to 0x00.
|
|
// We'll leave it set to 0x40, following Heltec's lead, just in case.
|
|
|
|
// "Display Mode"
|
|
// Seems to specify whether a waveform stored in OTP should use display mode 1 or 2 (full refresh or differential refresh)
|
|
|
|
// Unusual that waveforms are programmed to OTP, but this meta information is not ..?
|
|
|
|
sendCommand(0x37); // "Write Register for Display Option" ?
|
|
sendData(0x40); // "Spare VCOM OTP selection" ?
|
|
sendData(0x80); // "Display Mode for WS[7:0]" ?
|
|
sendData(0x03); // "Display Mode for WS[15:8]" ?
|
|
sendData(0x0E); // "Display Mode [23:16]" ?
|
|
|
|
switch (updateType) {
|
|
case FAST:
|
|
sendCommand(0x3C); // Border waveform:
|
|
sendData(0x81); // As specified by Heltec. Actually VCOM (0x80)?. Bit 0 seems redundant here.
|
|
break;
|
|
case FULL:
|
|
default:
|
|
sendCommand(0x3C); // Border waveform:
|
|
sendData(0x01); // Follow LUT 1 (blink same as white pixels)
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Tell controller IC which operations to run
|
|
void E0213A367::configUpdateSequence()
|
|
{
|
|
switch (updateType) {
|
|
case FAST:
|
|
sendCommand(0x22); // Set "update sequence"
|
|
sendData(0xFF); // Will load LUT from OTP memory, Display mode 2 "differential refresh"
|
|
break;
|
|
case FULL:
|
|
default:
|
|
sendCommand(0x22); // Set "update sequence"
|
|
sendData(0xF7); // Will load LUT from OTP memory, Display mode 1 "full refresh"
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Once the refresh operation has been started,
|
|
// begin periodically polling the display to check for completion, using the normal Meshtastic threading code
|
|
// Only used when refresh is "async"
|
|
void E0213A367::detachFromUpdate()
|
|
{
|
|
switch (updateType) {
|
|
case FAST:
|
|
return beginPolling(50, 500); // At least 500ms for fast refresh
|
|
case FULL:
|
|
default:
|
|
return beginPolling(100, 1500); // At least 1.5 seconds for full refresh
|
|
}
|
|
}
|
|
|
|
#endif // MESHTASTIC_INCLUDE_NICHE_GRAPHICS
|