Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_420.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: these e-papers require 3.3V supply AND data lines!
3//
4// based on Demo Example from Good Display: http://www.e-paper-display.com/download_list/downloadcategoryid=34&isMode=false.html
5// Controller: IL0398 : http://www.e-paper-display.com/download_detail/downloadsId=537.html
6//
7// Author: Jean-Marc Zingg
8//
9// Version: see library.properties
10//
11// Library: https://github.com/ZinggJM/GxEPD2
12
13#include "GxEPD2_420.h"
14
15GxEPD2_420::GxEPD2_420(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
16 GxEPD2_EPD(cs, dc, rst, busy, LOW, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
17{
18 _refresh_mode = full_refresh;
19}
20
21void GxEPD2_420::clearScreen(uint8_t value)
22{
23 writeScreenBuffer(value);
24 refresh(true);
25 if (_refresh_mode != grey_refresh) writeScreenBuffer(value);
26}
27
29{
30 _initial_write = false; // initial full screen buffer clean done
31 if (_refresh_mode == full_refresh) _Init_Part();
32 if (_initial_refresh || (_refresh_mode == grey_refresh))
33 {
34 _writeCommand(0x10); // init old data
36 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
37 {
38 _transfer(value);
39 }
41 }
42 _writeCommand(0x13);
44 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
45 {
46 _transfer(value);
47 }
49}
50
51void GxEPD2_420::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_4G(bitmap, GxEPD_BPP, x, y, w, h, invert, mirror_y, pgm);
54
55// if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
56// delay(1); // yield() to avoid WDT on ESP8266 and ESP32
57// int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
58// x -= x % 8; // byte boundary
59// w = wb * 8; // byte boundary
60// int16_t x1 = x < 0 ? 0 : x; // limit
61// int16_t y1 = y < 0 ? 0 : y; // limit
62// int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
63// int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
64// int16_t dx = x1 - x;
65// int16_t dy = y1 - y;
66// w1 -= dx;
67// h1 -= dy;
68// if ((w1 <= 0) || (h1 <= 0)) return;
69// if (_refresh_mode == grey_refresh) _Force_Init_Full();
70// else if (_refresh_mode == full_refresh) _Init_Part();
71// //uint32_t start = micros();
72// _writeCommand(0x91); // partial in
73// _setPartialRamArea(x1, y1, w1, h1);
74// _writeCommand(0x13);
75// _startTransfer();
76// for (int16_t i = 0; i < h1; i++)
77// {
78// for (int16_t j = 0; j < w1 / 8; j++)
79// {
80// uint8_t data;
81// // use wb, h of bitmap for index!
82// int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
83// if (pgm)
84// {
85//#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
86// data = pgm_read_byte(&bitmap[idx]);
87//#else
88// data = bitmap[idx];
89//#endif
90// }
91// else
92// {
93// data = bitmap[idx];
94// }
95// if (invert) data = ~data;
96// _transfer(data);
97// }
98// }
99// _endTransfer();
100// _writeCommand(0x92); // partial out
101// //Serial.print("GxEPD2_420::writeImage took "); Serial.println(micros() - start);
102// delay(1); // yield() to avoid WDT on ESP8266 and ESP32
103}
104
105void GxEPD2_420::writeImage_4G(const uint8_t bitmap[], uint8_t bpp, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
106{
107 uint16_t ppb = (bpp == 2 ? 4 : (bpp == 4 ? 2 : (bpp == 8 ? 1 : 0)));
108 uint8_t mask = (bpp == 2 ? 0xC0 : (bpp == 4 ? 0xF0 : 0xFF));
109 uint8_t grey1 = (bpp == 2 ? 0x80 : 0xA0); // demo limit for 4bpp
110 if (ppb == 0) return;
111 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
112 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
113 int16_t wbc = (w + 7) / 8; // width bytes on controller
114 x -= x % 8; // byte boundary on controller
115 w = wbc * 8; // byte boundary on controller
116 int16_t wb = (w + ppb - 1) / ppb; // width bytes of bitmap, bitmaps are padded
117 int16_t x1 = x < 0 ? 0 : x; // limit
118 int16_t y1 = y < 0 ? 0 : y; // limit
119 uint16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
120 uint16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
121 int16_t dx = x1 - x;
122 int16_t dy = y1 - y;
123 w1 -= dx;
124 h1 -= dy;
125 if ((w1 <= 0) || (h1 <= 0)) return;
126 _Init_4G();
127 _writeCommand(0x91); // partial in
128 _setPartialRamArea(x1, y1, w1, h1);
129 _writeCommand(0x10);
130 for (uint16_t i = 0; i < h1; i++) // lines
131 {
132 for (uint16_t j = 0; j < w1 / ppb; j += bpp) // out bytes
133 {
134 uint8_t out_byte = 0;
135 for (uint16_t k = 0; k < bpp; k++) // in bytes (bpp per out byte)
136 {
137 uint8_t in_byte;
138 // use wb, h of bitmap for index!
139 uint32_t idx = mirror_y ? j + k + dx / ppb + uint32_t((h - 1 - (i + dy))) * wb : j + k + dx / ppb + uint32_t(i + dy) * wb;
140 if (pgm)
141 {
142#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
143 in_byte = pgm_read_byte(&bitmap[idx]);
144#else
145 in_byte = bitmap[idx];
146#endif
147 }
148 else
149 {
150 in_byte = bitmap[idx];
151 }
152 if (invert) in_byte = ~in_byte;
153 for (uint16_t n = 0; n < ppb; n++) // bits, nibbles (ppb per in byte)
154 {
155 out_byte <<= 1;
156 uint8_t nibble = in_byte & mask;
157 if (nibble == mask) out_byte |= 0x01;//white
158 else if (nibble == 0x00) out_byte |= 0x00; //black
159 else if (nibble >= grey1) out_byte |= 0x01; //gray1
160 else out_byte |= 0x00; //gray2
161 in_byte <<= bpp;
162 }
163 }
164 _writeData(out_byte);
165 }
166 }
167 _writeCommand(0x13);
168 for (uint16_t i = 0; i < h1; i++) // lines
169 {
170 for (uint16_t j = 0; j < w1 / ppb; j += bpp) // out bytes
171 {
172 uint8_t out_byte = 0;
173 for (uint16_t k = 0; k < bpp; k++) // in bytes (bpp per out byte)
174 {
175 uint8_t in_byte;
176 // use wb, h of bitmap for index!
177 uint32_t idx = mirror_y ? j + k + dx / ppb + uint32_t((h - 1 - (i + dy))) * wb : j + k + dx / ppb + uint32_t(i + dy) * wb;
178 if (pgm)
179 {
180#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
181 in_byte = pgm_read_byte(&bitmap[idx]);
182#else
183 in_byte = bitmap[idx];
184#endif
185 }
186 else
187 {
188 in_byte = bitmap[idx];
189 }
190 if (invert) in_byte = ~in_byte;
191 for (uint16_t n = 0; n < ppb; n++) // bits, nibbles (ppb per in byte)
192 {
193 out_byte <<= 1;
194 uint8_t nibble = in_byte & mask;
195 if (nibble == mask) out_byte |= 0x01;//white
196 else if (nibble == 0x00) out_byte |= 0x00; //black
197 else if (nibble >= grey1) out_byte |= 0x00; //gray1
198 else out_byte |= 0x01; //gray2
199 in_byte <<= bpp;
200 }
201 }
202 _writeData(out_byte);
203 }
204 }
205 _writeCommand(0x92); // partial out
206 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
207}
208
209void GxEPD2_420::writeImagePart(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_4G(bitmap, GxEPD_BPP, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
213// if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
214// delay(1); // yield() to avoid WDT on ESP8266 and ESP32
215// if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
216// if ((x_part < 0) || (x_part >= w_bitmap)) return;
217// if ((y_part < 0) || (y_part >= h_bitmap)) return;
218// int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
219// x_part -= x_part % 8; // byte boundary
220// w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
221// h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
222// x -= x % 8; // byte boundary
223// w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
224// int16_t x1 = x < 0 ? 0 : x; // limit
225// int16_t y1 = y < 0 ? 0 : y; // limit
226// int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
227// int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
228// int16_t dx = x1 - x;
229// int16_t dy = y1 - y;
230// w1 -= dx;
231// h1 -= dy;
232// if ((w1 <= 0) || (h1 <= 0)) return;
233// if (_refresh_mode == grey_refresh) _Force_Init_Full();
234// else if (_refresh_mode == full_refresh) _Init_Part();
235// _writeCommand(0x91); // partial in
236// _setPartialRamArea(x1, y1, w1, h1);
237// _writeCommand(0x13);
238// _startTransfer();
239// for (int16_t i = 0; i < h1; i++)
240// {
241// for (int16_t j = 0; j < w1 / 8; j++)
242// {
243// uint8_t data;
244// // use wb_bitmap, h_bitmap of bitmap for index!
245// 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;
246// if (pgm)
247// {
248//#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
249// data = pgm_read_byte(&bitmap[idx]);
250//#else
251// data = bitmap[idx];
252//#endif
253// }
254// else
255// {
256// data = bitmap[idx];
257// }
258// if (invert) data = ~data;
259// _transfer(data);
260// }
261// }
262// _endTransfer();
263// _writeCommand(0x92); // partial out
264// delay(1); // yield() to avoid WDT on ESP8266 and ESP32
265}
266
267void GxEPD2_420::writeImagePart_4G(const uint8_t bitmap[], uint8_t bpp, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
268 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
269{
270 uint16_t ppb = (bpp == 2 ? 4 : (bpp == 4 ? 2 : (bpp == 8 ? 1 : 0)));
271 uint8_t mask = (bpp == 2 ? 0xC0 : (bpp == 4 ? 0xF0 : 0xFF));
272 uint8_t grey1 = (bpp == 2 ? 0x80 : 0xA0); // demo limit for 4bpp
273 if (ppb == 0) return;
274 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
275 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
276 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
277 if ((x_part < 0) || (x_part >= w_bitmap)) return;
278 if ((y_part < 0) || (y_part >= h_bitmap)) return;
279 int16_t wb_bitmap = (w_bitmap + ppb - 1) / ppb; // width bytes, bitmaps are padded
280 x_part -= x_part % ppb; // byte boundary
281 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
282 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
283 int16_t wbc = (w + 7) / 8; // width bytes on controller
284 x -= x % 8; // byte boundary on controller
285 w = wbc * 8; // byte boundary on controller
286 int16_t x1 = x < 0 ? 0 : x; // limit
287 int16_t y1 = y < 0 ? 0 : y; // limit
288 uint16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
289 uint16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
290 int16_t dx = x1 - x;
291 int16_t dy = y1 - y;
292 w1 -= dx;
293 h1 -= dy;
294 if ((w1 <= 0) || (h1 <= 0)) return;
295 _Init_4G();
296 _writeCommand(0x91); // partial in
297 _setPartialRamArea(x1, y1, w1, h1);
298 _writeCommand(0x10);
299 for (uint16_t i = 0; i < h1; i++) // lines
300 {
301 for (uint16_t j = 0; j < w1 / ppb; j += bpp) // out bytes
302 {
303 uint8_t out_byte = 0;
304 for (uint16_t k = 0; k < bpp; k++) // in bytes (bpp per out byte)
305 {
306 uint8_t in_byte;
307 // use wb_bitmap, h_bitmap of bitmap for index!
308 uint32_t idx = mirror_y ? x_part / ppb + j + k + dx / ppb + uint32_t((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / ppb + j + k + dx / ppb + uint32_t(y_part + i + dy) * wb_bitmap;
309 if (pgm)
310 {
311#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
312 in_byte = pgm_read_byte(&bitmap[idx]);
313#else
314 in_byte = bitmap[idx];
315#endif
316 }
317 else
318 {
319 in_byte = bitmap[idx];
320 }
321 if (invert) in_byte = ~in_byte;
322 for (uint16_t n = 0; n < ppb; n++) // bits, nibbles (ppb per in byte)
323 {
324 out_byte <<= 1;
325 uint8_t nibble = in_byte & mask;
326 if (nibble == mask) out_byte |= 0x01;//white
327 else if (nibble == 0x00) out_byte |= 0x00; //black
328 else if (nibble >= grey1) out_byte |= 0x01; //gray1
329 else out_byte |= 0x00; //gray2
330 in_byte <<= bpp;
331 }
332 }
333 _writeData(out_byte);
334 }
335 }
336 _writeCommand(0x13);
337 for (uint16_t i = 0; i < h1; i++) // lines
338 {
339 for (uint16_t j = 0; j < w1 / ppb; j += bpp) // out bytes
340 {
341 uint8_t out_byte = 0;
342 for (uint16_t k = 0; k < bpp; k++) // in bytes (bpp per out byte)
343 {
344 uint8_t in_byte;
345 // use wb_bitmap, h_bitmap of bitmap for index!
346 uint32_t idx = mirror_y ? x_part / ppb + j + k + dx / ppb + uint32_t((h_bitmap - 1 - (y_part + i + dy))) * wb_bitmap : x_part / ppb + j + k + dx / ppb + uint32_t(y_part + i + dy) * wb_bitmap;
347 if (pgm)
348 {
349#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
350 in_byte = pgm_read_byte(&bitmap[idx]);
351#else
352 in_byte = bitmap[idx];
353#endif
354 }
355 else
356 {
357 in_byte = bitmap[idx];
358 }
359 if (invert) in_byte = ~in_byte;
360 for (uint16_t n = 0; n < ppb; n++) // bits, nibbles (ppb per in byte)
361 {
362 out_byte <<= 1;
363 uint8_t nibble = in_byte & mask;
364 if (nibble == mask) out_byte |= 0x01;//white
365 else if (nibble == 0x00) out_byte |= 0x00; //black
366 else if (nibble >= grey1) out_byte |= 0x00; //gray1
367 else out_byte |= 0x01; //gray2
368 in_byte <<= bpp;
369 }
370 }
371 _writeData(out_byte);
372 }
373 }
374 _writeCommand(0x92); // partial out
375 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
376}
377
378void GxEPD2_420::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)
379{
380 if (black)
381 {
382 writeImage(black, x, y, w, h, invert, mirror_y, pgm);
383 }
384}
385
386void GxEPD2_420::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,
387 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
388{
389 if (black)
390 {
391 writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
392 }
393}
394
395void GxEPD2_420::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)
396{
397 if (data1)
398 {
399 writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
400 }
401}
402
403void GxEPD2_420::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
404{
405 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
406 refresh(x, y, w, h);
407 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
408}
409
410void GxEPD2_420::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
411 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
412{
413 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
414 refresh(x, y, w, h);
415 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
416}
417
418void GxEPD2_420::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)
419{
420 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
421 refresh(x, y, w, h);
422 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
423}
424
425void GxEPD2_420::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,
426 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
427{
428 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
429 refresh(x, y, w, h);
430 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
431}
432
433void GxEPD2_420::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)
434{
435 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
436 refresh(x, y, w, h);
437 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
438}
439
440void GxEPD2_420::refresh(bool partial_update_mode)
441{
442 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
443 else
444 {
445 if (_refresh_mode == forced_full_refresh) _refresh_mode = full_refresh;
446 if (_refresh_mode == fast_refresh) _Init_Full();
447 if (_refresh_mode == grey_refresh) _Update_4G();
448 else _Update_Full();
449 _initial_refresh = false; // initial full update done
450 }
451}
452
453void GxEPD2_420::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
454{
455 if (_initial_refresh) return refresh(false); // initial update needs be full update
456 if (_refresh_mode == forced_full_refresh) return refresh(false);
457 // intersection with screen
458 int16_t w1 = x < 0 ? w + x : w; // reduce
459 int16_t h1 = y < 0 ? h + y : h; // reduce
460 int16_t x1 = x < 0 ? 0 : x; // limit
461 int16_t y1 = y < 0 ? 0 : y; // limit
462 w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
463 h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
464 if ((w1 <= 0) || (h1 <= 0)) return;
465 // make x1, w1 multiple of 8
466 w1 += x1 % 8;
467 if (w1 % 8 > 0) w1 += 8 - w1 % 8;
468 x1 -= x1 % 8;
469 if (_refresh_mode == full_refresh) _Init_Part();
470 if (usePartialUpdateWindow) _writeCommand(0x91); // partial in
471 _setPartialRamArea(x1, y1, w1, h1);
472 if (_refresh_mode == grey_refresh) _Update_4G();
473 else _Update_Part();
474 if (usePartialUpdateWindow) _writeCommand(0x92); // partial out
475}
476
478{
479 _PowerOff();
480}
481
483{
484 _PowerOff();
485 if (_rst >= 0)
486 {
487 _writeCommand(0x07); // deep sleep
488 _writeData(0xA5); // check code
489 _hibernating = true;
490 }
491}
492
493void GxEPD2_420::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
494{
495 uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
496 uint16_t ye = y + h - 1;
497 x &= 0xFFF8; // byte boundary
498 _writeCommand(0x90); // partial window
499 _writeData(x / 256);
500 _writeData(x % 256);
501 _writeData(xe / 256);
502 _writeData(xe % 256);
503 _writeData(y / 256);
504 _writeData(y % 256);
505 _writeData(ye / 256);
506 _writeData(ye % 256);
507 _writeData(0x01); // don't see any difference
508 //_writeData(0x00); // don't see any difference
509}
510
511void GxEPD2_420::_PowerOn()
512{
513 if (!_power_is_on)
514 {
515 _writeCommand(0x04);
516 _waitWhileBusy("_PowerOn", power_on_time);
517 }
518 _power_is_on = true;
519}
520
521void GxEPD2_420::_PowerOff()
522{
523 _writeCommand(0x02); // power off
524 _waitWhileBusy("_PowerOff", power_off_time);
525 _power_is_on = false;
526 _refresh_mode = full_refresh;
527}
528
529void GxEPD2_420::_InitDisplay()
530{
531 if (_hibernating) _reset();
532 _writeCommand(0x01); // POWER SETTING
533 _writeData (0x03); // VDS_EN, VDG_EN internal
534 _writeData (0x00); // VCOM_HV, VGHL_LV=16V
535 _writeData (0x2b); // VDH=11V
536 _writeData (0x2b); // VDL=11V
537 _writeCommand(0x06); // boost soft start
538 _writeData (0x17); // A
539 _writeData (0x17); // B
540 _writeData (0x17); // C
541 _writeCommand(0x00); // panel setting
542 _writeData(0x3f); // 300x400 B/W mode, LUT set by register
543 _writeCommand(0x30); // PLL setting
544 _writeData (0x3a); // 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
545 _writeCommand(0x61); // resolution setting
546 _writeData (WIDTH / 256);
547 _writeData (WIDTH % 256);
548 _writeData (HEIGHT / 256);
549 _writeData (HEIGHT % 256);
550 _writeCommand(0x82); // vcom_DC setting
551 //_writeData (0x08); // -0.1 + 8 * -0.05 = -0.5V from demo
552 _writeData (0x12); // -0.1 + 18 * -0.05 = -1.0V from OTP, slightly better
553 //_writeData (0x1c); // -0.1 + 28 * -0.05 = -1.5V test, worse
554 _writeCommand(0x50); // VCOM AND DATA INTERVAL SETTING
555 //_writeData(0x97); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
556 _writeData(0xd7); // border floating to avoid flashing
557}
558
559const unsigned char GxEPD2_420::lut_20_vcom0_full[] PROGMEM =
560{
561 0x00, 0x08, 0x00, 0x00, 0x00, 0x02,
562 0x60, 0x28, 0x28, 0x00, 0x00, 0x01,
563 0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
564 0x00, 0x12, 0x12, 0x00, 0x00, 0x01,
565 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
566 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
567 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
568 0x00, 0x00
569};
570
571const unsigned char GxEPD2_420::lut_21_ww_full[] PROGMEM =
572{
573 0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
574 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
575 0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
576 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
577 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
578 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
579 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
580};
581
582const unsigned char GxEPD2_420::lut_22_bw_full[] PROGMEM =
583{
584 0x40, 0x08, 0x00, 0x00, 0x00, 0x02,
585 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
586 0x40, 0x14, 0x00, 0x00, 0x00, 0x01,
587 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01,
588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
589 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
591};
592
593const unsigned char GxEPD2_420::lut_23_wb_full[] PROGMEM =
594{
595 0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
596 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
597 0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
598 0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
601 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
602};
603
604const unsigned char GxEPD2_420::lut_24_bb_full[] PROGMEM =
605{
606 0x80, 0x08, 0x00, 0x00, 0x00, 0x02,
607 0x90, 0x28, 0x28, 0x00, 0x00, 0x01,
608 0x80, 0x14, 0x00, 0x00, 0x00, 0x01,
609 0x50, 0x12, 0x12, 0x00, 0x00, 0x01,
610 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
611 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
612 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
613};
614
615// full screen update LUT 0~3 gray
616const unsigned char GxEPD2_420::lut_20_vcom0_4G[] PROGMEM =
617{
618 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01,
619 0x60, 0x14, 0x14, 0x00, 0x00, 0x01,
620 0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
621 0x00, 0x13, 0x0A, 0x01, 0x00, 0x01,
622 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
623 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
624 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 0x00, 0x00
626};
627//R21
628const unsigned char GxEPD2_420::lut_21_ww_4G[] PROGMEM =
629{
630 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
631 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
632 0x10, 0x14, 0x0A, 0x00, 0x00, 0x01,
633 0xA0, 0x13, 0x01, 0x00, 0x00, 0x01,
634 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
635 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
636 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
637};
638//R22H r
639const unsigned char GxEPD2_420::lut_22_bw_4G[] PROGMEM =
640{
641 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
642 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
643 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
644 0x99, 0x0C, 0x01, 0x03, 0x04, 0x01,
645 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648};
649//R23H w
650const unsigned char GxEPD2_420::lut_23_wb_4G[] PROGMEM =
651{
652 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
653 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
654 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
655 0x99, 0x0B, 0x04, 0x04, 0x01, 0x01,
656 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
658 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659};
660//R24H b
661const unsigned char GxEPD2_420::lut_24_bb_4G[] PROGMEM =
662{
663 0x80, 0x0A, 0x00, 0x00, 0x00, 0x01,
664 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
665 0x20, 0x14, 0x0A, 0x00, 0x00, 0x01,
666 0x50, 0x13, 0x01, 0x00, 0x00, 0x01,
667 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
668 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
670};
671
672// partial update waveform
673
674// same waveform as by demo code from Good Display
675//#define T1 0 // color change charge balance pre-phase
676//#define T2 0 // color change or sustain charge balance pre-phase
677//#define T3 0 // color change or sustain phase
678//#define T4 25 // color change phase
679
680// new waveform created by Jean-Marc Zingg for the actual panel
681#define T1 25 // color change charge balance pre-phase
682#define T2 1 // color change or sustain charge balance pre-phase
683#define T3 4 // color change or sustain phase, was 2 before
684#define T4 25 // color change phase
685
686// for new waveform without sustain phase: uncomment next 2 lines, not good for fat fonts
687//#define T2 0 // color change or sustain charge balance pre-phase // 0 no sustain
688//#define T3 0 // color change or sustain phase // 0 no sustain
689
690// "balanced flash once" variant
691//#define T1 0 // color change charge balance pre-phase
692//#define T2 25 // color change or sustain charge balance pre-phase
693//#define T3 25 // color change or sustain phase
694//#define T4 0 // color change phase
695
696const unsigned char GxEPD2_420::lut_20_vcom0_partial[] PROGMEM =
697{
698 0x00, T1, T2, T3, T4, 1, // 00 00 00 00
699 0x00, 1, 0, 0, 0, 1, // gnd phase
700};
701
702const unsigned char GxEPD2_420::lut_21_ww_partial[] PROGMEM =
703{ // 10 w
704 0x18, T1, T2, T3, T4, 1, // 00 01 10 00
705 0x00, 1, 0, 0, 0, 1, // gnd phase
706};
707
708const unsigned char GxEPD2_420::lut_22_bw_partial[] PROGMEM =
709{ // 10 w
710 0x5A, T1, T2, T3, T4, 1, // 01 01 10 10
711 0x00, 1, 0, 0, 0, 1, // gnd phase
712};
713
714const unsigned char GxEPD2_420::lut_23_wb_partial[] PROGMEM =
715{ // 01 b
716 0xA5, T1, T2, T3, T4, 1, // 10 10 01 01
717 0x00, 1, 0, 0, 0, 1, // gnd phase
718};
719
720const unsigned char GxEPD2_420::lut_24_bb_partial[] PROGMEM =
721{ // 01 b
722 0x24, T1, T2, T3, T4, 1, // 00 10 01 00
723 0x00, 1, 0, 0, 0, 1, // gnd phase
724};
725
726void GxEPD2_420::_Force_Init_Full()
727{
728 _Init_Full();
729 _refresh_mode = forced_full_refresh;
730}
731
732void GxEPD2_420::_Init_Full()
733{
734 _InitDisplay();
735 _writeCommand(0x20);
736 _writeDataPGM(lut_20_vcom0_full, sizeof(lut_20_vcom0_full));
737 _writeCommand(0x21);
738 _writeDataPGM(lut_21_ww_full, sizeof(lut_21_ww_full));
739 _writeCommand(0x22);
740 _writeDataPGM(lut_22_bw_full, sizeof(lut_22_bw_full));
741 _writeCommand(0x23);
742 _writeDataPGM(lut_23_wb_full, sizeof(lut_23_wb_full));
743 _writeCommand(0x24);
744 _writeDataPGM(lut_24_bb_full, sizeof(lut_24_bb_full));
745 _PowerOn();
746 _refresh_mode = full_refresh;
747}
748
749void GxEPD2_420::_Init_4G()
750{
751 Serial.println("_Init_4G");
752 _InitDisplay();
753 _writeCommand(0x20);
754 _writeDataPGM(lut_20_vcom0_4G, sizeof(lut_20_vcom0_4G));
755 _writeCommand(0x21);
756 _writeDataPGM(lut_21_ww_4G, sizeof(lut_21_ww_4G));
757 _writeCommand(0x22);
758 _writeDataPGM(lut_22_bw_4G, sizeof(lut_22_bw_4G));
759 _writeCommand(0x23);
760 _writeDataPGM(lut_23_wb_4G, sizeof(lut_23_wb_4G));
761 _writeCommand(0x24);
762 _writeDataPGM(lut_24_bb_4G, sizeof(lut_24_bb_4G));
763 _PowerOn();
764 _refresh_mode = grey_refresh;
765}
766
767void GxEPD2_420::_Init_Part()
768{
769 Serial.println("_Init_Part");
770 _InitDisplay();
771 _writeCommand(0x20);
772 _writeDataPGM(lut_20_vcom0_partial, sizeof(lut_20_vcom0_partial), 44 - sizeof(lut_20_vcom0_partial));
773 _writeCommand(0x21);
774 _writeDataPGM(lut_21_ww_partial, sizeof(lut_21_ww_partial), 42 - sizeof(lut_21_ww_partial));
775 _writeCommand(0x22);
776 _writeDataPGM(lut_22_bw_partial, sizeof(lut_22_bw_partial), 42 - sizeof(lut_22_bw_partial));
777 _writeCommand(0x23);
778 _writeDataPGM(lut_23_wb_partial, sizeof(lut_23_wb_partial), 42 - sizeof(lut_23_wb_partial));
779 _writeCommand(0x24);
780 _writeDataPGM(lut_24_bb_partial, sizeof(lut_24_bb_partial), 42 - sizeof(lut_24_bb_partial));
781 _PowerOn();
782 _refresh_mode = fast_refresh;
783}
784
785void GxEPD2_420::_Update_Full()
786{
787 _writeCommand(0x12); //display refresh
788 _waitWhileBusy("_Update_Full", full_refresh_time);
789}
790
791void GxEPD2_420::_Update_4G()
792{
793 _writeCommand(0x12); //display refresh
794 _waitWhileBusy("_Update_4G", full_refresh_time);
795}
796
797void GxEPD2_420::_Update_Part()
798{
799 _writeCommand(0x12); //display refresh
800 _waitWhileBusy("_Update_Part", partial_refresh_time);
801}
const unsigned char GxEPD2_420::lut_20_vcom0_full[] PROGMEM
#define T2
#define T3
#define T4
#define T1
#define GxEPD_BPP
Definition GxEPD2_420.h:18
static const bool usePartialUpdateWindow
Definition GxEPD2_420.h:29
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)
GxEPD2_420(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
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 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)
void writeImagePart_4G(const uint8_t bitmap[], uint8_t bpp, 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 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)
void writeScreenBuffer(uint8_t value=0xFF)
void powerOff()
void clearScreen(uint8_t value=0xFF)
static const uint16_t WIDTH
Definition GxEPD2_420.h:24
static const uint16_t partial_refresh_time
Definition GxEPD2_420.h:34
void refresh(bool partial_update_mode=false)
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)
static const uint16_t full_refresh_time
Definition GxEPD2_420.h:33
void writeImage_4G(const uint8_t bitmap[], uint8_t bpp, int16_t x, int16_t y, int16_t w, int16_t h, bool invert=false, bool mirror_y=false, bool pgm=false)
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)
void hibernate()
static const uint16_t power_on_time
Definition GxEPD2_420.h:31
static const uint16_t power_off_time
Definition GxEPD2_420.h:32
static const uint16_t HEIGHT
Definition GxEPD2_420.h:25
void _endTransfer()
void _writeCommand(uint8_t c)
void _writeData(uint8_t d)
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 _startTransfer()
void _transfer(uint8_t value)
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
void _writeDataPGM(const uint8_t *data, uint16_t n, int16_t fill_with_zeroes=0)