Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor EInkDisplay #3299

Merged
merged 6 commits into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
417 changes: 58 additions & 359 deletions src/graphics/EInkDisplay2.cpp

Large diffs are not rendered by default.

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

#ifdef USE_EINK

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

#if defined(HELTEC_WIRELESS_PAPER_V1_0)
Expand All @@ -16,6 +19,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 +59,17 @@ 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

// 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
// AdafruitGFX display object - instantiated in connect(), variant specific
GxEPD2_BW<EINK_DISPLAY_MODEL, EINK_DISPLAY_MODEL::HEIGHT> *adafruitDisplay = NULL;

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 = 0;
};

#endif
3 changes: 3 additions & 0 deletions variants/Dongle_nRF52840-pca10059-v1/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ board = nordic_pca10059
board_level = extra
build_flags = ${nrf52840_base.build_flags} -Ivariants/Dongle_nRF52840-pca10059-v1 -D NORDIC_PCA10059
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
-DEINK_DISPLAY_MODEL=GxEPD2_420_M01
-DEINK_WIDTH=300
-DEINK_HEIGHT=400
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/Dongle_nRF52840-pca10059-v1>
lib_deps =
${nrf52840_base.lib_deps}
Expand Down
2 changes: 1 addition & 1 deletion variants/Dongle_nRF52840-pca10059-v1/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,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
3 changes: 3 additions & 0 deletions variants/MakePython_nRF52840_eink/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ lib_deps =
${nrf52840_base.lib_deps}
https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f
zinggjm/GxEPD2@^1.4.9
-DEINK_DISPLAY_MODEL=GxEPD2_290_T5D
-DEINK_WIDTH=296
-DEINK_HEIGHT=128
debug_tool = jlink
;upload_port = /dev/ttyACM4
6 changes: 3 additions & 3 deletions variants/esp32-s3-pico/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ 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
-DEINK_DISPLAY_MODEL=GxEPD2_290_T94_V2
-DEINK_WIDTH=296
-DEINK_HEIGHT=128

lib_deps = ${esp32s3_base.lib_deps}
zinggjm/GxEPD2@^1.5.3
Expand Down
2 changes: 1 addition & 1 deletion variants/esp32-s3-pico/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@
#define PIN_EINK_DC 33
#define PIN_EINK_RES 42 // 37 //(-1) // cant be MISO Waveshare ??)
#define PIN_EINK_SCLK 35
#define PIN_EINK_MOSI 36
#define PIN_EINK_MOSI 36
7 changes: 6 additions & 1 deletion variants/heltec_wireless_paper/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
extends = esp32s3_base
board = heltec_wifi_lora_32_V3
build_flags =
${esp32s3_base.build_flags} -D HELTEC_WIRELESS_PAPER -I variants/heltec_wireless_paper
${esp32s3_base.build_flags}
-I variants/heltec_wireless_paper
-D HELTEC_WIRELESS_PAPER
-D EINK_DISPLAY_MODEL=GxEPD2_213_FC1
-D EINK_WIDTH=250
-D EINK_HEIGHT=122
lib_deps =
${esp32s3_base.lib_deps}
https://github.com/ixt/GxEPD2#39f325b677713eb04dfcc83b8e402e77523fb8bf
Expand Down
3 changes: 3 additions & 0 deletions variants/heltec_wireless_paper_v1/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ build_flags =
${esp32s3_base.build_flags}
-I variants/heltec_wireless_paper_v1
-D HELTEC_WIRELESS_PAPER_V1_0
-D EINK_DISPLAY_MODEL=GxEPD2_213_BN
-D EINK_WIDTH=250
-D EINK_HEIGHT=122
lib_deps =
${esp32s3_base.lib_deps}
https://github.com/meshtastic/GxEPD2/
Expand Down
7 changes: 0 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 Down
5 changes: 3 additions & 2 deletions variants/m5stack_coreink/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ build_flags =
;-D RADIOLIB_VERBOSE
-Ofast
-D__MCUXPRESSO
-DEPD_HEIGHT=200
-DEPD_WIDTH=200
-DEINK_DISPLAY_MODEL=GxEPD2_154_M09
-DEINK_WIDTH=200
-DEINK_HEIGHT=200
-DUSER_SETUP_LOADED
-DM5_COREINK
-DM5STACK
Expand Down
6 changes: 3 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,9 @@ 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
-DEINK_DISPLAY_MODEL=GxEPD2_290_T5D
-DEINK_WIDTH=296
-DEINK_HEIGHT=128
-DBOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-DARDUINO_USB_MODE=0
2 changes: 1 addition & 1 deletion variants/my_esp32s3_diy_eink/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@
#define PIN_EINK_DC 1
#define PIN_EINK_RES (-1)
#define PIN_EINK_SCLK 5
#define PIN_EINK_MOSI 6
#define PIN_EINK_MOSI 6
3 changes: 3 additions & 0 deletions variants/rak10701/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak10701 -D RAK_4631
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-DEINK_DISPLAY_MODEL=GxEPD2_213_BN
-DEINK_WIDTH=250
-DEINK_HEIGHT=122
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak10701> +<mesh/eth/> +<mesh/api/> +<mqtt/>
lib_deps =
${nrf52840_base.lib_deps}
Expand Down
14 changes: 7 additions & 7 deletions variants/rak10701/variant.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,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
3 changes: 3 additions & 0 deletions variants/rak4631/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631 -D RAK_4631
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-DEINK_DISPLAY_MODEL=GxEPD2_213_BN
-DEINK_WIDTH=250
-DEINK_HEIGHT=122
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631> +<mesh/eth/> +<mesh/api/> +<mqtt/>
lib_deps =
${nrf52840_base.lib_deps}
Expand Down
14 changes: 7 additions & 7 deletions variants/rak4631/variant.h
todd-herbert marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -181,13 +181,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
3 changes: 3 additions & 0 deletions variants/rak4631_epaper/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ extends = nrf52840_base
board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631_epaper -D RAK_4631
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
-DEINK_DISPLAY_MODEL=GxEPD2_213_BN
-DEINK_WIDTH=250
-DEINK_HEIGHT=122
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631_epaper>
lib_deps =
${nrf52840_base.lib_deps}
Expand Down
3 changes: 3 additions & 0 deletions variants/rak4631_epaper_onrxtx/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ board = wiscore_rak4631
build_flags = ${nrf52840_base.build_flags} -Ivariants/rak4631_epaper -D RAK_4631
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
-D PIN_EINK_EN=34
-D EINK_DISPLAY_MODEL=GxEPD2_213_BN
-D EINK_WIDTH=250
-D EINK_HEIGHT=122
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/rak4631_epaper_onrxtx>
lib_deps =
${nrf52840_base.lib_deps}
Expand Down
3 changes: 3 additions & 0 deletions variants/t-echo/platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ debug_tool = jlink
build_flags = ${nrf52840_base.build_flags} -Ivariants/t-echo
-DGPS_POWER_TOGGLE
-L "${platformio.libdeps_dir}/${this.__env__}/BSEC2 Software Library/src/cortex-m4/fpv4-sp-d16-hard"
-DEINK_DISPLAY_MODEL=GxEPD2_154_D67
-DEINK_WIDTH=200
-DEINK_HEIGHT=200
build_src_filter = ${nrf52_base.build_src_filter} +<../variants/t-echo>
lib_deps =
${nrf52840_base.lib_deps}
Expand Down
Loading