Add EINK_DISPLAY_SINGLE_BUFFER_MODE build flag and allow for single buffer rendering
This commit is contained in:
@@ -30,12 +30,17 @@ class EInkDisplay {
|
|||||||
void clearScreen(uint8_t color = 0xFF) const;
|
void clearScreen(uint8_t color = 0xFF) const;
|
||||||
void drawImage(const uint8_t* imageData, uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool fromProgmem = false) const;
|
void drawImage(const uint8_t* imageData, uint16_t x, uint16_t y, uint16_t w, uint16_t h, bool fromProgmem = false) const;
|
||||||
|
|
||||||
|
#ifndef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
void swapBuffers();
|
void swapBuffers();
|
||||||
|
#endif
|
||||||
void setFramebuffer(const uint8_t* bwBuffer) const;
|
void setFramebuffer(const uint8_t* bwBuffer) const;
|
||||||
|
|
||||||
void copyGrayscaleBuffers(const uint8_t* lsbBuffer, const uint8_t* msbBuffer);
|
void copyGrayscaleBuffers(const uint8_t* lsbBuffer, const uint8_t* msbBuffer);
|
||||||
void copyGrayscaleLsbBuffers(const uint8_t* lsbBuffer);
|
void copyGrayscaleLsbBuffers(const uint8_t* lsbBuffer);
|
||||||
void copyGrayscaleMsbBuffers(const uint8_t* msbBuffer);
|
void copyGrayscaleMsbBuffers(const uint8_t* msbBuffer);
|
||||||
|
#ifdef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
|
void cleanupGrayscaleBuffers(const uint8_t* bwBuffer);
|
||||||
|
#endif
|
||||||
|
|
||||||
void displayBuffer(RefreshMode mode = FAST_REFRESH);
|
void displayBuffer(RefreshMode mode = FAST_REFRESH);
|
||||||
void displayGrayBuffer(bool turnOffScreen = false);
|
void displayGrayBuffer(bool turnOffScreen = false);
|
||||||
@@ -65,10 +70,11 @@ class EInkDisplay {
|
|||||||
|
|
||||||
// Frame buffer (statically allocated)
|
// Frame buffer (statically allocated)
|
||||||
uint8_t frameBuffer0[BUFFER_SIZE];
|
uint8_t frameBuffer0[BUFFER_SIZE];
|
||||||
uint8_t frameBuffer1[BUFFER_SIZE];
|
|
||||||
|
|
||||||
uint8_t* frameBuffer;
|
uint8_t* frameBuffer;
|
||||||
|
#ifndef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
|
uint8_t frameBuffer1[BUFFER_SIZE];
|
||||||
uint8_t* frameBufferActive;
|
uint8_t* frameBufferActive;
|
||||||
|
#endif
|
||||||
|
|
||||||
// SPI settings
|
// SPI settings
|
||||||
SPISettings spiSettings;
|
SPISettings spiSettings;
|
||||||
|
|||||||
@@ -115,7 +115,9 @@ EInkDisplay::EInkDisplay(int8_t sclk, int8_t mosi, int8_t cs, int8_t dc, int8_t
|
|||||||
_rst(rst),
|
_rst(rst),
|
||||||
_busy(busy),
|
_busy(busy),
|
||||||
frameBuffer(nullptr),
|
frameBuffer(nullptr),
|
||||||
|
#ifndef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
frameBufferActive(nullptr),
|
frameBufferActive(nullptr),
|
||||||
|
#endif
|
||||||
customLutActive(false) {
|
customLutActive(false) {
|
||||||
Serial.printf("[%lu] EInkDisplay: Constructor called\n", millis());
|
Serial.printf("[%lu] EInkDisplay: Constructor called\n", millis());
|
||||||
Serial.printf("[%lu] SCLK=%d, MOSI=%d, CS=%d, DC=%d, RST=%d, BUSY=%d\n", millis(), sclk, mosi, cs, dc, rst, busy);
|
Serial.printf("[%lu] SCLK=%d, MOSI=%d, CS=%d, DC=%d, RST=%d, BUSY=%d\n", millis(), sclk, mosi, cs, dc, rst, busy);
|
||||||
@@ -125,13 +127,19 @@ void EInkDisplay::begin() {
|
|||||||
Serial.printf("[%lu] EInkDisplay: begin() called\n", millis());
|
Serial.printf("[%lu] EInkDisplay: begin() called\n", millis());
|
||||||
|
|
||||||
frameBuffer = frameBuffer0;
|
frameBuffer = frameBuffer0;
|
||||||
|
#ifndef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
frameBufferActive = frameBuffer1;
|
frameBufferActive = frameBuffer1;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Initialize to white
|
// Initialize to white
|
||||||
memset(frameBuffer0, 0xFF, BUFFER_SIZE);
|
memset(frameBuffer0, 0xFF, BUFFER_SIZE);
|
||||||
|
#ifdef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
|
Serial.printf("[%lu] Static frame buffer (%lu bytes = 48KB)\n", millis(), BUFFER_SIZE);
|
||||||
|
#else
|
||||||
memset(frameBuffer1, 0xFF, BUFFER_SIZE);
|
memset(frameBuffer1, 0xFF, BUFFER_SIZE);
|
||||||
|
|
||||||
Serial.printf("[%lu] Static frame buffers (2 x %lu bytes = 96KB)\n", millis(), BUFFER_SIZE);
|
Serial.printf("[%lu] Static frame buffers (2 x %lu bytes = 96KB)\n", millis(), BUFFER_SIZE);
|
||||||
|
#endif
|
||||||
|
|
||||||
Serial.printf("[%lu] Initializing e-ink display driver...\n", millis());
|
Serial.printf("[%lu] Initializing e-ink display driver...\n", millis());
|
||||||
|
|
||||||
// Initialize SPI with custom pins
|
// Initialize SPI with custom pins
|
||||||
@@ -351,11 +359,13 @@ void EInkDisplay::setFramebuffer(const uint8_t* bwBuffer) const {
|
|||||||
memcpy(frameBuffer, bwBuffer, BUFFER_SIZE);
|
memcpy(frameBuffer, bwBuffer, BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
void EInkDisplay::swapBuffers() {
|
void EInkDisplay::swapBuffers() {
|
||||||
uint8_t* temp = frameBuffer;
|
uint8_t* temp = frameBuffer;
|
||||||
frameBuffer = frameBufferActive;
|
frameBuffer = frameBufferActive;
|
||||||
frameBufferActive = temp;
|
frameBufferActive = temp;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void EInkDisplay::grayscaleRevert() {
|
void EInkDisplay::grayscaleRevert() {
|
||||||
if (!inGrayscaleMode) {
|
if (!inGrayscaleMode) {
|
||||||
@@ -386,6 +396,18 @@ void EInkDisplay::copyGrayscaleBuffers(const uint8_t* lsbBuffer, const uint8_t*
|
|||||||
writeRamBuffer(CMD_WRITE_RAM_RED, msbBuffer, BUFFER_SIZE);
|
writeRamBuffer(CMD_WRITE_RAM_RED, msbBuffer, BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
|
/**
|
||||||
|
* In single buffer mode, this should be called with the previously written BW buffer
|
||||||
|
* to reconstruct the RED buffer for proper differential fast refreshes following a
|
||||||
|
* grayscale display.
|
||||||
|
*/
|
||||||
|
void EInkDisplay::cleanupGrayscaleBuffers(const uint8_t* bwBuffer) {
|
||||||
|
setRamArea(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
||||||
|
writeRamBuffer(CMD_WRITE_RAM_RED, bwBuffer, BUFFER_SIZE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void EInkDisplay::displayBuffer(RefreshMode mode) {
|
void EInkDisplay::displayBuffer(RefreshMode mode) {
|
||||||
if (!isScreenOn) {
|
if (!isScreenOn) {
|
||||||
// Force half refresh if screen is off
|
// Force half refresh if screen is off
|
||||||
@@ -408,14 +430,22 @@ void EInkDisplay::displayBuffer(RefreshMode mode) {
|
|||||||
} else {
|
} else {
|
||||||
// For fast refresh, write to BW buffer only
|
// For fast refresh, write to BW buffer only
|
||||||
writeRamBuffer(CMD_WRITE_RAM_BW, frameBuffer, BUFFER_SIZE);
|
writeRamBuffer(CMD_WRITE_RAM_BW, frameBuffer, BUFFER_SIZE);
|
||||||
|
// In single buffer mode, the RED RAM should already contain the previous frame
|
||||||
|
// In dual buffer mode, we write back frameBufferActive which is the last frame
|
||||||
|
#ifndef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
writeRamBuffer(CMD_WRITE_RAM_RED, frameBufferActive, BUFFER_SIZE);
|
writeRamBuffer(CMD_WRITE_RAM_RED, frameBufferActive, BUFFER_SIZE);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// swap active buffer for next time
|
|
||||||
swapBuffers();
|
|
||||||
|
|
||||||
// Refresh the display
|
// Refresh the display
|
||||||
refreshDisplay(mode);
|
refreshDisplay(mode);
|
||||||
|
|
||||||
|
#ifdef EINK_DISPLAY_SINGLE_BUFFER_MODE
|
||||||
|
// In single buffer mode always sync RED RAM after refresh to prepare for next fast refresh
|
||||||
|
// This ensures RED contains the currently displayed frame for differential comparison
|
||||||
|
setRamArea(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
|
||||||
|
writeRamBuffer(CMD_WRITE_RAM_RED, frameBuffer, BUFFER_SIZE);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void EInkDisplay::displayGrayBuffer(const bool turnOffScreen) {
|
void EInkDisplay::displayGrayBuffer(const bool turnOffScreen) {
|
||||||
|
|||||||
Reference in New Issue
Block a user