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

Async Full Refresh #6

Merged
merged 4 commits into from
Mar 11, 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
19 changes: 19 additions & 0 deletions src/GxEPD2_BW.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
#ifndef _GxEPD2_BW_H_
#define _GxEPD2_BW_H_

// This version of meshtastic/GxEPD2 has been modified (defiled) to allow nextPage() to run full refreshes asynchronously
// This macro ensures that the relevant modifications to meshtastic/firmware will only run with a correctly modified version of GxEPD2
// Note: this async behavior is unrelated to the callback system implemented in newer versions of ZinggJM/GxEPD2
#define HAS_EINK_ASYNCFULL

// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX
//#include <GFX.h>

Expand Down Expand Up @@ -239,6 +244,16 @@ class GxEPD2_BW : public GxEPD2_GFX_BASE_CLASS
_second_phase = false;
}

// Transplanted from nextPage(), non-paged, full refresh
// This is the code which runs after the refresh() call
// Method is called by meshtastic/firmware, once polling GxEPD2_BW::isBusy() reports that the physical refresh is complete
void endAsyncFull() {
if (epd2.hasFastPartialUpdate) {
epd2.writeImageAgain(_buffer, 0, 0, WIDTH, HEIGHT);
}
epd2.powerOff();
}

bool nextPage()
{
if (1 == _pages)
Expand All @@ -258,12 +273,16 @@ class GxEPD2_BW : public GxEPD2_GFX_BASE_CLASS
{
epd2.writeImageForFullRefresh(_buffer, 0, 0, WIDTH, HEIGHT);
epd2.refresh(false);
#if defined(USE_EINK_DYNAMICDISPLAY) // This macro defined in meshtastic/firmware
// -- meshtastic: moved to endAsyncFull() --
#else
if (epd2.hasFastPartialUpdate)
{
epd2.writeImageAgain(_buffer, 0, 0, WIDTH, HEIGHT);
//epd2.refresh(true); // not needed
}
epd2.powerOff();
#endif
}
return false;
}
Expand Down
17 changes: 17 additions & 0 deletions src/GxEPD2_EPD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ void GxEPD2_EPD::_reset()

void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time)
{
// For full refreshes, meshtastic/firmare will poll GxEPD2_EPD::isBusy() instead of waiting here (for EInkDynamicDisplay only)
#if defined(USE_EINK_DYNAMICDISPLAY)
if (_isUpdatingFull(comment))
return;
#endif

if (_busy >= 0)
{
delay(1); // add some margin to become active
Expand Down Expand Up @@ -241,3 +247,14 @@ void GxEPD2_EPD::_endTransfer()
if (_cs >= 0) digitalWrite(_cs, HIGH);
_spi.endTransaction();
}

// Polled by meshtastic/firmware, during async full-refresh
bool GxEPD2_EPD::isBusy() {
return (digitalRead(_busy) == _busy_level);
}

// Used to skip _waitWhileBusy(), for meshtastic async
bool GxEPD2_EPD::_isUpdatingFull(const char* comment) {
// True if comment matches
return ( strcmp(comment, "_Update_Full") == 0 );
}
2 changes: 2 additions & 0 deletions src/GxEPD2_EPD.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class GxEPD2_EPD
{
return (a > b ? a : b);
};
bool isBusy(); // Used in meshtastic/firmware, to poll after nextPage(), for async full refresh
protected:
void _reset();
void _waitWhileBusy(const char* comment = 0, uint16_t busy_time = 5000);
Expand All @@ -104,6 +105,7 @@ class GxEPD2_EPD
void _startTransfer();
void _transfer(uint8_t value);
void _endTransfer();
bool _isUpdatingFull(const char* comment); // Meshtastic: Determine if _waitWhileBusy() should be skipped (for async), by comparing the comment string..
protected:
int8_t _cs, _dc, _rst, _busy, _busy_level;
uint32_t _busy_timeout;
Expand Down
14 changes: 2 additions & 12 deletions src/epd/GxEPD2_213_FC1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ void GxEPD2_213_FC1::clearScreen(uint8_t value)
_writeScreenBuffer(0x13, value); // Clear "NEW" (red) mem
_writeScreenBuffer(0x10, value); // Clear "OLD" (black) mem
refresh(false); // Full refresh
_PowerOff();
_initial_write = false;
_initial_refresh = false;
}
Expand Down Expand Up @@ -158,19 +159,10 @@ void GxEPD2_213_FC1::powerOff()
_PowerOff();
}

// Put the display into an extra-low power state. Hard reset required to wake.
// Caution: will wipe display memory - problematic for fast-refresh, so not used by meshtastic
// No hibernate for this display, only power off. Preserves image memory for fast refresh.
void GxEPD2_213_FC1::hibernate()
{
_PowerOff();
if (_rst >= 0)
{
_writeCommand(0x07); // deep sleep mode
_writeData(0xA5); // enter deep sleep
_hibernating = true;
_configured_for_full = false;
_configured_for_fast = false;
}
}

void GxEPD2_213_FC1::_PowerOn()
Expand Down Expand Up @@ -280,7 +272,6 @@ void GxEPD2_213_FC1::_Update_Full()
_PowerOn();
_writeCommand(0x12);
_waitWhileBusy("_Update_Full", full_refresh_time);
_PowerOff();
}

void GxEPD2_213_FC1::_Update_Part()
Expand All @@ -289,7 +280,6 @@ void GxEPD2_213_FC1::_Update_Part()
_PowerOn();
_writeCommand(0x12);
_waitWhileBusy("_Update_Part", partial_refresh_time);
_PowerOff();
}

// Fast refresh waveform is unofficial (experimental?)
Expand Down
2 changes: 1 addition & 1 deletion src/epd/GxEPD2_213_FC1.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class GxEPD2_213_FC1 : public GxEPD2_EPD
void refresh(bool partial_update_mode = false); // screen refresh from controller memory to full screen
void refresh(int16_t x, int16_t y, int16_t w, int16_t h); // screen refresh from controller memory, fast-refresh
void powerOff(); // turns off generation of panel driving voltages, avoids screen fading over time
void hibernate(); // turns powerOff() and sets controller to deep sleep for minimum power use, ONLY if wakeable by RST (rst >= 0)
void hibernate(); // For this display, no deep sleep, only power off. Preserves image memory for fast refresh

// Unimplemented for meshtastic
public:
Expand Down