Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_270_T91.cpp
Go to the documentation of this file.
1// Display Library for SPI e-paper panels from Dalian Good Display and boards from Waveshare.
2// Requires HW SPI and Adafruit_GFX. Caution: the e-paper panels require 3.3V supply AND data lines!
3//
4// based on Demo Example from Good Display, available here: http://www.e-paper-display.com/download_detail/downloadsId=806.html
5// Panel: GDEY027T91 : https://www.good-display.com/product/432.html
6// Controller : SSD1680 : https://www.good-display.com/companyfile/101.html
7//
8// Author: Jean-Marc Zingg
9//
10// Version: see library.properties
11//
12// Library: https://github.com/ZinggJM/GxEPD2
13
14#include "GxEPD2_270_T91.h"
15
16GxEPD2_270_T91::GxEPD2_270_T91(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
17 GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
18{
19}
20
21void GxEPD2_270_T91::clearScreen(uint8_t value)
22{
23 writeScreenBuffer(value);
24 refresh(true);
26}
27
29{
30 if (!_using_partial_mode) _Init_Part();
31 if (_initial_write) _writeScreenBuffer(0x26, value); // set previous
32 _writeScreenBuffer(0x24, value); // set current
33 _initial_write = false; // initial full screen buffer clean done
34}
35
37{
38 if (!_using_partial_mode) _Init_Part();
39 _writeScreenBuffer(0x24, value); // set current
40}
41
42void GxEPD2_270_T91::_writeScreenBuffer(uint8_t command, uint8_t value)
43{
44 _writeCommand(command);
45 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
46 {
47 _writeData(value);
48 }
49}
50
51void GxEPD2_270_T91::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
52{
53 _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
54}
55
56void GxEPD2_270_T91::writeImageForFullRefresh(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
57{
58 _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm);
59 _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
60}
61
62
63void GxEPD2_270_T91::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
64{
65 _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
66}
67
68void GxEPD2_270_T91::_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)
69{
70 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
71 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
72 int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
73 x -= x % 8; // byte boundary
74 w = wb * 8; // byte boundary
75 int16_t x1 = x < 0 ? 0 : x; // limit
76 int16_t y1 = y < 0 ? 0 : y; // limit
77 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
78 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
79 int16_t dx = x1 - x;
80 int16_t dy = y1 - y;
81 w1 -= dx;
82 h1 -= dy;
83 if ((w1 <= 0) || (h1 <= 0)) return;
84 if (!_using_partial_mode) _Init_Part();
85 _setPartialRamArea(x1, y1, w1, h1);
86 _writeCommand(command);
87 for (int16_t i = 0; i < h1; i++)
88 {
89 for (int16_t j = 0; j < w1 / 8; j++)
90 {
91 uint8_t data;
92 // use wb, h of bitmap for index!
93 int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
94 if (pgm)
95 {
96#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
97 data = pgm_read_byte(&bitmap[idx]);
98#else
99 data = bitmap[idx];
100#endif
101 }
102 else
103 {
104 data = bitmap[idx];
105 }
106 if (invert) data = ~data;
107 _writeData(data);
108 }
109 }
110 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
111}
112
113void GxEPD2_270_T91::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
114 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
115{
116 _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
117}
118
119void GxEPD2_270_T91::writeImagePartAgain(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
120 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
121{
122 _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
123}
124
125void GxEPD2_270_T91::_writeImagePart(uint8_t command, const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
126 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
127{
128 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
129 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
130 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
131 if ((x_part < 0) || (x_part >= w_bitmap)) return;
132 if ((y_part < 0) || (y_part >= h_bitmap)) return;
133 int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
134 x_part -= x_part % 8; // byte boundary
135 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
136 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
137 x -= x % 8; // byte boundary
138 w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
139 int16_t x1 = x < 0 ? 0 : x; // limit
140 int16_t y1 = y < 0 ? 0 : y; // limit
141 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
142 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
143 int16_t dx = x1 - x;
144 int16_t dy = y1 - y;
145 w1 -= dx;
146 h1 -= dy;
147 if ((w1 <= 0) || (h1 <= 0)) return;
148 if (!_using_partial_mode) _Init_Part();
149 _setPartialRamArea(x1, y1, w1, h1);
150 _writeCommand(command);
151 for (int16_t i = 0; i < h1; i++)
152 {
153 for (int16_t j = 0; j < w1 / 8; j++)
154 {
155 uint8_t data;
156 // use wb_bitmap, h_bitmap of bitmap for index!
157 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;
158 if (pgm)
159 {
160#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
161 data = pgm_read_byte(&bitmap[idx]);
162#else
163 data = bitmap[idx];
164#endif
165 }
166 else
167 {
168 data = bitmap[idx];
169 }
170 if (invert) data = ~data;
171 _writeData(data);
172 }
173 }
174 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
175}
176
177void GxEPD2_270_T91::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)
178{
179 if (black)
180 {
181 writeImage(black, x, y, w, h, invert, mirror_y, pgm);
182 }
183}
184
185void GxEPD2_270_T91::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,
186 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
187{
188 if (black)
189 {
190 writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
191 }
192}
193
194void GxEPD2_270_T91::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)
195{
196 if (data1)
197 {
198 writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
199 }
200}
201
202void GxEPD2_270_T91::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
203{
204 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
205 refresh(x, y, w, h);
206 writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
207}
208
209void GxEPD2_270_T91::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
210 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
211{
212 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
213 refresh(x, y, w, h);
214 writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
215}
216
217void GxEPD2_270_T91::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)
218{
219 if (black)
220 {
221 drawImage(black, x, y, w, h, invert, mirror_y, pgm);
222 }
223}
224
225void GxEPD2_270_T91::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,
226 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
227{
228 if (black)
229 {
230 drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
231 }
232}
233
234void GxEPD2_270_T91::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)
235{
236 if (data1)
237 {
238 drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
239 }
240}
241
242void GxEPD2_270_T91::refresh(bool partial_update_mode)
243{
244 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
245 else
246 {
247 if (_using_partial_mode) _Init_Full();
248 _Update_Full();
249 _initial_refresh = false; // initial full update done
250 }
251}
252
253void GxEPD2_270_T91::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
254{
255 if (_initial_refresh) return refresh(false); // initial update needs be full update
256 // intersection with screen
257 int16_t w1 = x < 0 ? w + x : w; // reduce
258 int16_t h1 = y < 0 ? h + y : h; // reduce
259 int16_t x1 = x < 0 ? 0 : x; // limit
260 int16_t y1 = y < 0 ? 0 : y; // limit
261 w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
262 h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
263 if ((w1 <= 0) || (h1 <= 0)) return;
264 // make x1, w1 multiple of 8
265 w1 += x1 % 8;
266 if (w1 % 8 > 0) w1 += 8 - w1 % 8;
267 x1 -= x1 % 8;
268 if (!_using_partial_mode) _Init_Part();
269 _setPartialRamArea(x1, y1, w1, h1);
270 _Update_Part();
271}
272
274{
275 _PowerOff();
276}
277
279{
280 _PowerOff();
281 if (_rst >= 0)
282 {
283 _writeCommand(0x10); // deep sleep mode
284 _writeData(0x1); // enter deep sleep
285 _hibernating = true;
286 }
287}
288
289void GxEPD2_270_T91::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
290{
291 _writeCommand(0x11); // set ram entry mode
292 _writeData(0x03); // x increase, y increase : normal mode
293 _writeCommand(0x44);
294 _writeData(x / 8);
295 _writeData((x + w - 1) / 8);
296 _writeCommand(0x45);
297 _writeData(y % 256);
298 _writeData(y / 256);
299 _writeData((y + h - 1) % 256);
300 _writeData((y + h - 1) / 256);
301 _writeCommand(0x4e);
302 _writeData(x / 8);
303 _writeCommand(0x4f);
304 _writeData(y % 256);
305 _writeData(y / 256);
306}
307
308void GxEPD2_270_T91::_PowerOn()
309{
310 if (!_power_is_on)
311 {
312 _writeCommand(0x22);
313 _writeData(0xf8);
314 _writeCommand(0x20);
315 _waitWhileBusy("_PowerOn", power_on_time);
316 }
317 _power_is_on = true;
318}
319
320void GxEPD2_270_T91::_PowerOff()
321{
322 if (_power_is_on)
323 {
324 _writeCommand(0x22);
325 _writeData(0x83);
326 _writeCommand(0x20);
327 _waitWhileBusy("_PowerOff", power_off_time);
328 }
329 _power_is_on = false;
330 _using_partial_mode = false;
331}
332
333void GxEPD2_270_T91::_InitDisplay()
334{
335 if (_hibernating) _reset();
336 delay(10); // 10ms according to specs
337 _writeCommand(0x12); //SWRESET
338 delay(10); // 10ms according to specs
339 _writeCommand(0x11); //data entry mode
340 _writeData(0x03);
341 _writeCommand(0x3C); //BorderWavefrom
342 _writeData(0x05);
343 _writeCommand(0x18); //Read built-in temperature sensor
344 _writeData(0x80);
345 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
346}
347
348void GxEPD2_270_T91::_Init_Full()
349{
350 _InitDisplay();
351 _PowerOn();
352 _using_partial_mode = false;
353}
354
355void GxEPD2_270_T91::_Init_Part()
356{
357 _InitDisplay();
358 _PowerOn();
359 _using_partial_mode = true;
360}
361
362void GxEPD2_270_T91::_Update_Full()
363{
364 _writeCommand(0x22);
365 _writeData(0xf4);
366 _writeCommand(0x20);
367 _waitWhileBusy("_Update_Full", full_refresh_time);
368}
369
370void GxEPD2_270_T91::_Update_Part()
371{
372 _writeCommand(0x22);
373 _writeData(0xfc);
374 _writeCommand(0x20);
375 _waitWhileBusy("_Update_Part", partial_refresh_time);
376}
void writeScreenBuffer(uint8_t value=0xFF)
void refresh(bool partial_update_mode=false)
GxEPD2_270_T91(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
void drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
static const uint16_t full_refresh_time
void writeScreenBufferAgain(uint8_t value=0xFF)
void 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=false, bool mirror_y=false, bool pgm=false)
static const uint16_t power_off_time
void drawNative(const uint8_t *data1, const uint8_t *data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
void writeImageForFullRefresh(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
void clearScreen(uint8_t value=0xFF)
void writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
static const uint16_t HEIGHT
void writeNative(const uint8_t *data1, const uint8_t *data2, int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
void writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
static const uint16_t WIDTH
void 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=false, bool mirror_y=false, bool pgm=false)
static const uint16_t power_on_time
static const uint16_t partial_refresh_time
void 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=false, bool mirror_y=false, bool pgm=false)
void _writeCommand(uint8_t c)
void _writeData(uint8_t d)
bool _using_partial_mode
Definition GxEPD2_EPD.h:118
void _waitWhileBusy(const char *comment=0, uint16_t busy_time=5000)
bool _power_is_on
Definition GxEPD2_EPD.h:118
bool _initial_refresh
Definition GxEPD2_EPD.h:117
void _reset()
bool _initial_write
Definition GxEPD2_EPD.h:117
int16_t _rst
Definition GxEPD2_EPD.h:112
bool _hibernating
Definition GxEPD2_EPD.h:118