Skip to content

Commit

Permalink
Refactor EInkDisplay
Browse files Browse the repository at this point in the history
A lot of variant specific code is merged, with the macros pushed to the respective variant.h files.
"Dynamic Partial" code has been purged, pending a rewrite.
  • Loading branch information
todd-herbert committed Feb 28, 2024
1 parent 4ffb906 commit 440a79e
Show file tree
Hide file tree
Showing 17 changed files with 168 additions and 458 deletions.
390 changes: 34 additions & 356 deletions src/graphics/EInkDisplay2.cpp

Large diffs are not rendered by default.

83 changes: 10 additions & 73 deletions src/graphics/EInkDisplay2.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "GxEPD2_BW.h"
#include <OLEDDisplay.h>

#if defined(HELTEC_WIRELESS_PAPER_V1_0)
Expand All @@ -16,6 +17,7 @@
* Use the fast NRF52 SPI API rather than the slow standard arduino version
*
* turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
* Suggestion: perhaps similar to HELTEC_WIRELESS_PAPER issue, which resolved with rtc_gpio_hold_dis()
*/
class EInkDisplay : public OLEDDisplay
{
Expand Down Expand Up @@ -55,80 +57,15 @@ class EInkDisplay : public OLEDDisplay
// Connect to the display
virtual bool connect() override;

#if defined(USE_EINK_DYNAMIC_REFRESH)
// Full, fast, or skip: balance urgency with display health
// AdafruitGFX display object - instantiated in connect(), variant specific
GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT> *adafruitDisplay;

// Use fast refresh if EITHER:
// * highPriority() was set
// * a highPriority() update was previously skipped, for rate-limiting - (EINK_HIGHPRIORITY_LIMIT_SECONDS)

// Use full refresh if EITHER:
// * lowPriority() was set
// * demandFullRefresh() was called - (single shot)
// * too many fast updates in a row: protect display - (EINK_FASTREFRESH_REPEAT_LIMIT)
// * no recent updates, and last update was fast: redraw for image quality (EINK_LOWPRIORITY_LIMIT_SECONDS)
// * (optional) too many "erasures" since full-refresh (black pixels cleared to white)

// Rate limit if:
// * lowPriority() - (EINK_LOWPRIORITY_LIMIT_SECONDS)
// * highPriority(), if multiple fast updates have run back-to-back - (EINK_HIGHPRIORITY_LIMIT_SECONDS)

// Skip update entirely if ALL criteria met:
// * new image matches old image
// * lowPriority()
// * no call to demandFullRefresh()
// * not redrawing for image quality
// * not refreshing for display health

// ------------------------------------

// To implement for your E-Ink display:
// * edit configForFastRefresh()
// * edit configForFullRefresh()
// * add macros to variant.h, and adjust to taste:

/*
#define USE_EINK_DYNAMIC_REFRESH
#define EINK_LOWPRIORITY_LIMIT_SECONDS 30
#define EINK_HIGHPRIORITY_LIMIT_SECONDS 1
#define EINK_FASTREFRESH_REPEAT_LIMIT 5
#define EINK_FASTREFRESH_ERASURE_LIMIT 300 // optional
*/

public:
void highPriority(); // Suggest fast refresh
void lowPriority(); // Suggest full refresh
void demandFullRefresh(); // For next update: explicitly request full refresh

protected:
void configForFastRefresh(); // Display specific code to select fast refresh mode
void configForFullRefresh(); // Display specific code to return to full refresh mode
bool newImageMatchesOld(); // Is the new update actually different to the last image?
bool determineRefreshMode(); // Called immediately before data written to display - choose refresh mode, or abort update
#ifdef EINK_FASTREFRESH_ERASURE_LIMIT
int32_t countBlackPixels(); // Calculate the number of black pixels in the new image
bool tooManyErasures(); // Has too much "ghosting" (black pixels erased to white) accumulated since last full-refresh?
// If display uses HSPI
#if defined(HELTEC_WIRELESS_PAPER) || defined(HELTEC_WIRELESS_PAPER_V1_0)
SPIClass *hspi = NULL;
#endif

bool isHighPriority = true; // Does the method calling update believe that this is urgent?
bool needsFull = false; // Is a full refresh forced? (display health)
bool demandingFull = false; // Was full refresh specifically requested? (splash screens, etc)
bool missedHighPriorityUpdate = false; // Was a high priority update skipped for rate-limiting?
uint16_t fastRefreshCount = 0; // How many fast updates have occurred since last full refresh?
uint32_t lastUpdateMsec = 0; // When did the last update occur?
uint32_t prevImageHash = 0; // Used to check if update will change screen image (skippable or not)
int32_t prevBlackCount = 0; // How many black pixels were in the previous image
uint32_t erasedSinceFull = 0; // How many black pixels have been set back to white since last full-refresh? (roughly)

// Set in variant.h
const uint32_t lowPriorityLimitMsec = (uint32_t)1000 * EINK_LOWPRIORITY_LIMIT_SECONDS; // Max rate for fast refreshes
const uint32_t highPriorityLimitMsec = (uint32_t)1000 * EINK_HIGHPRIORITY_LIMIT_SECONDS; // Max rate for full refreshes
const uint32_t fastRefreshLimit = EINK_FASTREFRESH_REPEAT_LIMIT; // Max consecutive fast updates, before full is triggered

#else // !USE_EINK_DYNAMIC_REFRESH
// Tolerate calls to these methods anywhere, just to be safe
void highPriority() {}
void lowPriority() {}
void demandFullRefresh() {}
#endif
private:
// FIXME quick hack to limit drawing to a very slow rate
uint32_t lastDrawMsec;
};
6 changes: 5 additions & 1 deletion variants/Dongle_nRF52840-pca10059-v1/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (9) // EPD_SCLK
#define PIN_EINK_MOSI (10) // EPD_MOSI

#define EINK_DISPLAY_MODEL GxEPD2_420_M01 // 4.2 inch 300x400
#define EINK_WIDTH 300
#define EINK_HEIGHT 400

#define USE_EINK

/*
Expand All @@ -136,7 +140,7 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define USE_SX1262
#define SX126X_CS (0 + 31) // LORA_CS P0.31
#define SX126X_DIO1 (0 + 29) // DIO1 P0.29
#define SX126X_BUSY (0 + 2) // LORA_BUSY P0.02
#define SX126X_BUSY (0 + 2) // LORA_BUSY P0.02
#define SX126X_RESET (32 + 15) // LORA_RESET P1.15
#define SX126X_TXEN (32 + 13) // TXEN P1.13 NiceRF 868 dont use
#define SX126X_RXEN (32 + 10) // RXEN P1.10 NiceRF 868 dont use
Expand Down
4 changes: 4 additions & 0 deletions variants/MakePython_nRF52840_eink/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 2) // EPD_SCLK
#define PIN_EINK_MOSI (0 + 28) // EPD_MOSI

#define EINK_DISPLAY_MODEL GxEPD2_290_T5D // 2.9 inch 296x128
#define EINK_WIDTH 296
#define EINK_HEIGHT 128

#define USE_EINK

/*
Expand Down
5 changes: 2 additions & 3 deletions variants/esp32-s3-pico/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ build_flags = ${esp32_base.build_flags}
;-DPRIVATE_HW
-Ivariants/esp32-s3-pico
-DBOARD_HAS_PSRAM
-DTECHO_DISPLAY_MODEL=GxEPD2_290_T94_V2
-DEPD_HEIGHT=128
-DEPD_WIDTH=296
-DEPD_HEIGHT=128 ;Redundant? See variant.h
-DEPD_WIDTH=296 ;Redundant? See variant.h

lib_deps = ${esp32s3_base.lib_deps}
zinggjm/GxEPD2@^1.5.3
Expand Down
4 changes: 4 additions & 0 deletions variants/esp32-s3-pico/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,7 @@
#define PIN_EINK_RES 42 // 37 //(-1) // cant be MISO Waveshare ??)
#define PIN_EINK_SCLK 35
#define PIN_EINK_MOSI 36

#define EINK_DISPLAY_MODEL GxEPD2_290_T94_V2
#define EINK_WIDTH 296
#define EINK_HEIGHT 128
4 changes: 4 additions & 0 deletions variants/heltec_wireless_paper/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
#define PIN_EINK_SCLK 3
#define PIN_EINK_MOSI 2

#define EINK_DISPLAY_MODEL GxEPD2_213_FC1
#define EINK_WIDTH 250
#define EINK_HEIGHT 122

/*
* SPI interfaces
*/
Expand Down
11 changes: 4 additions & 7 deletions variants/heltec_wireless_paper_v1/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,6 @@

#define USE_EINK

// Settings for Dynamic Refresh mode
// Change between full-refresh, fast-refresh, or update-skipping, to balance urgency and display health.
#define USE_EINK_DYNAMIC_REFRESH
#define EINK_LOWPRIORITY_LIMIT_SECONDS 30
#define EINK_HIGHPRIORITY_LIMIT_SECONDS 1
#define EINK_FASTREFRESH_REPEAT_LIMIT 5

/*
* eink display pins
*/
Expand All @@ -23,6 +16,10 @@
#define PIN_EINK_SCLK 3
#define PIN_EINK_MOSI 2

#define EINK_DISPLAY_MODEL GxEPD2_213_BN
#define EINK_WIDTH 250
#define EINK_HEIGHT 122

/*
* SPI interfaces
*/
Expand Down
4 changes: 4 additions & 0 deletions variants/m5stack_coreink/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@
#define PIN_EINK_SCLK 18 // EPD_SCLK
#define PIN_EINK_MOSI 23 // EPD_MOSI

#define EINK_DISPLAY_MODEL GxEPD2_154_M09 // 1.54 inch
#define EINK_WIDTH 200
#define EINK_HEIGHT 200

#define BATTERY_PIN 35
#define ADC_CHANNEL ADC1_GPIO35_CHANNEL
// https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/schematic/Core/m5paper/M5_PAPER_SCH.pdf
Expand Down
2 changes: 1 addition & 1 deletion variants/monteops_hw1/platformio.ini
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
; MonteOps M.Node/M.Backbone/M.Eagle hardware based on hardware variant #1 (RAK4630 based)
; MonteOps M.Node/M.Backbone/M.Eagle hardware based on hardware variant #1 ( based)
[env:monteops_hw1]
extends = nrf52840_base
board = wiscore_rak4631
Expand Down
5 changes: 2 additions & 3 deletions variants/my_esp32s3_diy_eink/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ build_flags =
;${esp32_base.build_flags} -D MY_ESP32S3_DIY -I variants/my_esp32s3_diy_eink
${esp32_base.build_flags} -D PRIVATE_HW -I variants/my_esp32s3_diy_eink
-Dmy
-DTECHO_DISPLAY_MODEL=GxEPD2_290_T5D
-DEPD_HEIGHT=128
-DEPD_WIDTH=296
-DEPD_HEIGHT=128 ;Redundant? See variant.h
-DEPD_WIDTH=296 ;Redundant? See variant.h
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-DARDUINO_USB_MODE=0
4 changes: 4 additions & 0 deletions variants/my_esp32s3_diy_eink/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,7 @@
#define PIN_EINK_RES (-1)
#define PIN_EINK_SCLK 5
#define PIN_EINK_MOSI 6

#define EINK_DISPLAY_MODEL GxEPD2_290_T5D
#define EINK_WIDTH 296
#define EINK_HEIGHT 128
32 changes: 25 additions & 7 deletions variants/rak10701/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,24 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 3)
#define PIN_EINK_MOSI (0 + 30) // also called SDI

// E-Ink model selection

#define EINK_DISPLAY_MODEL GxEPD2_213_BN // 2.13 inch b/w 250x122
#define EINK_WIDTH 250
#define EINK_HEIGHT 122

// #define EINK_DISPLAY_MODEL GxEPD2_420_M01 // 4.2 inch 300x400
// #define EINK_WIDTH 300
// #define EINK_HEIGHT 400

// #define EINK_DISPLAY_MODEL GxEPD2_290_T5D // 2.9 inch 296x128
// #define EINK_WIDTH 296
// #define EINK_HEIGHT 128

// #define EINK_DISPLAY_MODEL GxEPD2_154_M09 // 1.54 inch 200x200
// #define EINK_WIDTH 200
// #define EINK_HEIGHT 200

// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
// #define PIN_EINK_PWR_ON (-1)
Expand Down Expand Up @@ -202,13 +220,13 @@ static const uint8_t WB_SPI_MOSI = 30; // IO_SLOT

/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ )
P1.10 NSS SPI NSS (Arduino GPIO number 42)
P1.11 SCK SPI CLK (Arduino GPIO number 43)
P1.12 MOSI SPI MOSI (Arduino GPIO number 44)
P1.13 MISO SPI MISO (Arduino GPIO number 45)
P1.14 BUSY BUSY signal (Arduino GPIO number 46)
P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47)
P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38)
P1.10 NSS SPI NSS (Arduino GPIO number 42)
P1.11 SCK SPI CLK (Arduino GPIO number 43)
P1.12 MOSI SPI MOSI (Arduino GPIO number 44)
P1.13 MISO SPI MISO (Arduino GPIO number 45)
P1.14 BUSY BUSY signal (Arduino GPIO number 46)
P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47)
P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38)
Important for successful SX1262 initialization:
Expand Down
32 changes: 25 additions & 7 deletions variants/rak4631/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,24 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 3)
#define PIN_EINK_MOSI (0 + 30) // also called SDI

// E-Ink model selection

#define EINK_DISPLAY_MODEL GxEPD2_213_BN // 2.13 inch b/w 250x122
#define EINK_WIDTH 250
#define EINK_HEIGHT 122

// #define EINK_DISPLAY_MODEL GxEPD2_420_M01 // 4.2 inch 300x400
// #define EINK_WIDTH 300
// #define EINK_HEIGHT 400

// #define EINK_DISPLAY_MODEL GxEPD2_290_T5D // 2.9 inch 296x128
// #define EINK_WIDTH 296
// #define EINK_HEIGHT 128

// #define EINK_DISPLAY_MODEL GxEPD2_154_M09 // 1.54 inch 200x200
// #define EINK_WIDTH 200
// #define EINK_HEIGHT 200

// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
// #define PIN_EINK_PWR_ON (-1)
Expand Down Expand Up @@ -181,13 +199,13 @@ static const uint8_t SCK = PIN_SPI_SCK;

/* Setup of the SX1262 LoRa module ( https://docs.rakwireless.com/Product-Categories/WisBlock/RAK4631/Datasheet/ )
P1.10 NSS SPI NSS (Arduino GPIO number 42)
P1.11 SCK SPI CLK (Arduino GPIO number 43)
P1.12 MOSI SPI MOSI (Arduino GPIO number 44)
P1.13 MISO SPI MISO (Arduino GPIO number 45)
P1.14 BUSY BUSY signal (Arduino GPIO number 46)
P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47)
P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38)
P1.10 NSS SPI NSS (Arduino GPIO number 42)
P1.11 SCK SPI CLK (Arduino GPIO number 43)
P1.12 MOSI SPI MOSI (Arduino GPIO number 44)
P1.13 MISO SPI MISO (Arduino GPIO number 45)
P1.14 BUSY BUSY signal (Arduino GPIO number 46)
P1.15 DIO1 DIO1 event interrupt (Arduino GPIO number 47)
P1.06 NRESET NRESET manual reset of the SX1262 (Arduino GPIO number 38)
Important for successful SX1262 initialization:
Expand Down
18 changes: 18 additions & 0 deletions variants/rak4631_epaper/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,24 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 3)
#define PIN_EINK_MOSI (0 + 30) // also called SDI

// E-Ink model selection

#define EINK_DISPLAY_MODEL GxEPD2_213_BN // 2.13 inch b/w 250x122
#define EINK_WIDTH 250
#define EINK_HEIGHT 122

// #define EINK_DISPLAY_MODEL GxEPD2_420_M01 // 4.2 inch 300x400
// #define EINK_WIDTH 300
// #define EINK_HEIGHT 400

// #define EINK_DISPLAY_MODEL GxEPD2_290_T5D // 2.9 inch 296x128
// #define EINK_WIDTH 296
// #define EINK_HEIGHT 128

// #define EINK_DISPLAY_MODEL GxEPD2_154_M09 // 1.54 inch 200x200
// #define EINK_WIDTH 200
// #define EINK_HEIGHT 200

// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
// #define PIN_EINK_PWR_ON (-1)
Expand Down
18 changes: 18 additions & 0 deletions variants/rak4631_epaper_onrxtx/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,24 @@ static const uint8_t SCK = PIN_SPI_SCK;
#define PIN_EINK_SCLK (0 + 14) // SCL
#define PIN_EINK_MOSI (0 + 13) // SDA

// E-Ink model selection

#define EINK_DISPLAY_MODEL GxEPD2_213_BN // 2.13 inch b/w 250x122
#define EINK_WIDTH 250
#define EINK_HEIGHT 122

// #define EINK_DISPLAY_MODEL GxEPD2_420_M01 // 4.2 inch 300x400
// #define EINK_WIDTH 300
// #define EINK_HEIGHT 400

// #define EINK_DISPLAY_MODEL GxEPD2_290_T5D // 2.9 inch 296x128
// #define EINK_WIDTH 296
// #define EINK_HEIGHT 128

// #define EINK_DISPLAY_MODEL GxEPD2_154_M09 // 1.54 inch 200x200
// #define EINK_WIDTH 200
// #define EINK_HEIGHT 200

// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
// #define PIN_EINK_PWR_ON (-1)
Expand Down
4 changes: 4 additions & 0 deletions variants/t-echo/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ External serial flash WP25R1635FZUIL0
#define PIN_EINK_SCLK (0 + 31)
#define PIN_EINK_MOSI (0 + 29) // also called SDI

#define EINK_DISPLAY_MODEL GxEPD2_154_D67
#define EINK_WIDTH 200
#define EINK_HEIGHT 200

// Controls power for the eink display - Board power is enabled either by VBUS from USB or the CPU asserting PWR_ON
// FIXME - I think this is actually just the board power enable - it enables power to the CPU also
#define PIN_EINK_PWR_ON (0 + 12)
Expand Down

0 comments on commit 440a79e

Please sign in to comment.