forked from wellenvogel/esp32-nmea2000
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
da4089c
commit aeed8ad
Showing
2 changed files
with
400 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,394 @@ | ||
// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare. | ||
// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines! | ||
// | ||
// based on Demo Example from Good Display, available here: https://www.good-display.com/product/386.html | ||
// Panel: GDEY042T81 : https://www.good-display.com/product/386.html | ||
// Controller : SSD1683 : https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF | ||
// | ||
// Author: Jean-Marc Zingg | ||
// | ||
// Version: see library.properties | ||
// | ||
// Library: https://github.com/ZinggJM/GxEPD2 | ||
|
||
#include "GxEPD2_420_GDEY042T81.h" | ||
|
||
GxEPD2_420_GDEY042T81::GxEPD2_420_GDEY042T81(int16_t cs, int16_t dc, int16_t rst, int16_t busy) : | ||
GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate) | ||
{ | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::clearScreen(uint8_t value) | ||
{ | ||
// full refresh needed for all cases (previous != screen) | ||
_writeScreenBuffer(0x26, value); // set previous | ||
_writeScreenBuffer(0x24, value); // set current | ||
refresh(false); // full refresh | ||
_initial_write = false; | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeScreenBuffer(uint8_t value) | ||
{ | ||
if (_initial_write) return clearScreen(value); | ||
_writeScreenBuffer(0x24, value); // set current | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeScreenBufferAgain(uint8_t value) | ||
{ | ||
_writeScreenBuffer(0x24, value); // set current | ||
_writeScreenBuffer(0x26, value); // set previous | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_writeScreenBuffer(uint8_t command, uint8_t value) | ||
{ | ||
if (!_init_display_done) _InitDisplay(); | ||
_setPartialRamArea(0, 0, WIDTH, HEIGHT); | ||
_writeCommand(command); | ||
_startTransfer(); | ||
for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++) | ||
{ | ||
_transfer(value); | ||
} | ||
_endTransfer(); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
_writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeImageForFullRefresh(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
_writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous | ||
_writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm); // set current | ||
} | ||
|
||
|
||
void GxEPD2_420_GDEY042T81::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
_writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm); // set previous | ||
_writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm); // set current | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_writeImage(uint8_t command, const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
delay(1); // yield() to avoid WDT on ESP8266 and ESP32 | ||
int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded | ||
x -= x % 8; // byte boundary | ||
w = wb * 8; // byte boundary | ||
int16_t x1 = x < 0 ? 0 : x; // limit | ||
int16_t y1 = y < 0 ? 0 : y; // limit | ||
int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit | ||
int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit | ||
int16_t dx = x1 - x; | ||
int16_t dy = y1 - y; | ||
w1 -= dx; | ||
h1 -= dy; | ||
if ((w1 <= 0) || (h1 <= 0)) return; | ||
if (!_init_display_done) _InitDisplay(); | ||
if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean | ||
_setPartialRamArea(x1, y1, w1, h1); | ||
_writeCommand(command); | ||
_startTransfer(); | ||
for (int16_t i = 0; i < h1; i++) | ||
{ | ||
for (int16_t j = 0; j < w1 / 8; j++) | ||
{ | ||
uint8_t data; | ||
// use wb, h of bitmap for index! | ||
int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb; | ||
if (pgm) | ||
{ | ||
#if defined(__AVR) || defined(ESP8266) || defined(ESP32) | ||
data = pgm_read_byte(&bitmap[idx]); | ||
#else | ||
data = bitmap[idx]; | ||
#endif | ||
} | ||
else | ||
{ | ||
data = bitmap[idx]; | ||
} | ||
if (invert) data = ~data; | ||
_transfer(data); | ||
} | ||
} | ||
_endTransfer(); | ||
delay(1); // yield() to avoid WDT on ESP8266 and ESP32 | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, | ||
int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
_writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeImagePartAgain(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, | ||
int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
_writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
_writeImagePart(0x26, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_writeImagePart(uint8_t command, const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, | ||
int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
delay(1); // yield() to avoid WDT on ESP8266 and ESP32 | ||
if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return; | ||
if ((x_part < 0) || (x_part >= w_bitmap)) return; | ||
if ((y_part < 0) || (y_part >= h_bitmap)) return; | ||
int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded | ||
x_part -= x_part % 8; // byte boundary | ||
w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit | ||
h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit | ||
x -= x % 8; // byte boundary | ||
w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded | ||
int16_t x1 = x < 0 ? 0 : x; // limit | ||
int16_t y1 = y < 0 ? 0 : y; // limit | ||
int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit | ||
int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit | ||
int16_t dx = x1 - x; | ||
int16_t dy = y1 - y; | ||
w1 -= dx; | ||
h1 -= dy; | ||
if ((w1 <= 0) || (h1 <= 0)) return; | ||
if (!_init_display_done) _InitDisplay(); | ||
if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean | ||
_setPartialRamArea(x1, y1, w1, h1); | ||
_writeCommand(command); | ||
_startTransfer(); | ||
for (int16_t i = 0; i < h1; i++) | ||
{ | ||
for (int16_t j = 0; j < w1 / 8; j++) | ||
{ | ||
uint8_t data; | ||
// use wb_bitmap, h_bitmap of bitmap for index! | ||
int16_t idx = mirror_y ? x_part / 8 + j + dx / 8 + ((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / 8 + j + dx / 8 + (y_part + i + dy) * wb_bitmap; | ||
if (pgm) | ||
{ | ||
#if defined(__AVR) || defined(ESP8266) || defined(ESP32) | ||
data = pgm_read_byte(&bitmap[idx]); | ||
#else | ||
data = bitmap[idx]; | ||
#endif | ||
} | ||
else | ||
{ | ||
data = bitmap[idx]; | ||
} | ||
if (invert) data = ~data; | ||
_transfer(data); | ||
} | ||
} | ||
_endTransfer(); | ||
delay(1); // yield() to avoid WDT on ESP8266 and ESP32 | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
if (black) | ||
{ | ||
writeImage(black, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, | ||
int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
if (black) | ||
{ | ||
writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::writeNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
if (data1) | ||
{ | ||
writeImage(data1, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
refresh(x, y, w, h); | ||
writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, | ||
int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
refresh(x, y, w, h); | ||
writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::drawImage(const uint8_t* black, const uint8_t* color, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
if (black) | ||
{ | ||
drawImage(black, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::drawImagePart(const uint8_t* black, const uint8_t* color, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap, | ||
int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
if (black) | ||
{ | ||
drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::drawNative(const uint8_t* data1, const uint8_t* data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm) | ||
{ | ||
if (data1) | ||
{ | ||
drawImage(data1, x, y, w, h, invert, mirror_y, pgm); | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::refresh(bool partial_update_mode) | ||
{ | ||
if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT); | ||
else | ||
{ | ||
_Update_Full(); | ||
_initial_refresh = false; // initial full update done | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::refresh(int16_t x, int16_t y, int16_t w, int16_t h) | ||
{ | ||
if (_initial_refresh) return refresh(false); // initial update needs be full update | ||
// intersection with screen | ||
int16_t w1 = x < 0 ? w + x : w; // reduce | ||
int16_t h1 = y < 0 ? h + y : h; // reduce | ||
int16_t x1 = x < 0 ? 0 : x; // limit | ||
int16_t y1 = y < 0 ? 0 : y; // limit | ||
w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit | ||
h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit | ||
if ((w1 <= 0) || (h1 <= 0)) return; | ||
// make x1, w1 multiple of 8 | ||
w1 += x1 % 8; | ||
if (w1 % 8 > 0) w1 += 8 - w1 % 8; | ||
x1 -= x1 % 8; | ||
_setPartialRamArea(x1, y1, w1, h1); | ||
_Update_Part(); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::powerOff() | ||
{ | ||
_PowerOff(); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::hibernate() | ||
{ | ||
_PowerOff(); | ||
if (_rst >= 0) | ||
{ | ||
_writeCommand(0x10); // deep sleep mode | ||
_writeData(0x1); // enter deep sleep | ||
_hibernating = true; | ||
_init_display_done = false; | ||
} | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h) | ||
{ | ||
_writeCommand(0x11); // set ram entry mode | ||
_writeData(0x03); // x increase, y increase : normal mode | ||
_writeCommand(0x44); | ||
_writeData(x / 8); | ||
_writeData((x + w - 1) / 8); | ||
_writeCommand(0x45); | ||
_writeData(y % 256); | ||
_writeData(y / 256); | ||
_writeData((y + h - 1) % 256); | ||
_writeData((y + h - 1) / 256); | ||
_writeCommand(0x4e); | ||
_writeData(x / 8); | ||
_writeCommand(0x4f); | ||
_writeData(y % 256); | ||
_writeData(y / 256); | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_PowerOn() | ||
{ | ||
if (!_power_is_on) | ||
{ | ||
_writeCommand(0x22); | ||
_writeData(0xe0); | ||
_writeCommand(0x20); | ||
_waitWhileBusy("_PowerOn", power_on_time); | ||
} | ||
_power_is_on = true; | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_PowerOff() | ||
{ | ||
if (_power_is_on) | ||
{ | ||
_writeCommand(0x22); | ||
_writeData(0x83); | ||
_writeCommand(0x20); | ||
_waitWhileBusy("_PowerOff", power_off_time); | ||
} | ||
_power_is_on = false; | ||
_using_partial_mode = false; | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_InitDisplay() | ||
{ | ||
if (_hibernating) _reset(); | ||
delay(10); // 10ms according to specs | ||
_writeCommand(0x12); //SWRESET | ||
delay(10); // 10ms according to specs | ||
_writeCommand(0x01); // Set MUX as 300 | ||
_writeData(0x2B); | ||
_writeData(0x01); | ||
_writeData(0x00); | ||
_writeCommand(0x3C); //BorderWavefrom | ||
_writeData(0x01); // | ||
_writeCommand(0x18); //Read built-in temperature sensor | ||
_writeData(0x80); | ||
_setPartialRamArea(0, 0, WIDTH, HEIGHT); | ||
_init_display_done = true; | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_Update_Full() | ||
{ | ||
_writeCommand(0x21); // Display Update Controll | ||
_writeData(0x40); // bypass RED as 0 | ||
_writeData(0x00); // single chip application | ||
if (useFastFullUpdate) | ||
{ | ||
_writeCommand(0x1A); // Write to temperature register | ||
// _writeData(0x64); | ||
_writeData(0x19); | ||
_writeCommand(0x22); | ||
_writeData(0xd7); | ||
} | ||
else | ||
{ | ||
_writeCommand(0x22); | ||
_writeData(0xf7); | ||
} | ||
_writeCommand(0x20); | ||
_waitWhileBusy("_Update_Full", full_refresh_time); | ||
_power_is_on = false; | ||
} | ||
|
||
void GxEPD2_420_GDEY042T81::_Update_Part() | ||
{ | ||
_writeCommand(0x21); // Display Update Controll | ||
_writeData(0x00); // RED normal | ||
_writeData(0x00); // single chip application | ||
_writeCommand(0x22); | ||
// _writeData(0xfc); | ||
_writeData(0xff); | ||
_writeCommand(0x20); | ||
_waitWhileBusy("_Update_Part", partial_refresh_time); | ||
_power_is_on = true; | ||
} |
Oops, something went wrong.