Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_213_Z19c.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: UC8151D : https://v4.cecdn.yun300.cn/100001_1909185148/UC8151D.pdf
6//
7// Author: Jean-Marc Zingg
8//
9// Version: see library.properties
10//
11// Library: https://github.com/ZinggJM/GxEPD2
12
13#include "GxEPD2_213_Z19c.h"
14
15GxEPD2_213_Z19c::GxEPD2_213_Z19c(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
16 GxEPD2_EPD(cs, dc, rst, busy, LOW, 20000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
17{
18}
19
21{
22 clearScreen(value, 0xFF);
23}
24
25void GxEPD2_213_Z19c::clearScreen(uint8_t black_value, uint8_t color_value)
26{
27 _initial_write = false; // initial full screen buffer clean done
28 _Init_Part();
29 _writeCommand(0x91); // partial in
30 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
31 _writeCommand(0x10);
32 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
33 {
34 _writeData(black_value);
35 }
36 _writeCommand(0x13);
37 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
38 {
39 _writeData(color_value);
40 }
41 _Update_Part();
42 _writeCommand(0x92); // partial out
43}
44
46{
47 writeScreenBuffer(value, 0xFF);
48}
49
50void GxEPD2_213_Z19c::writeScreenBuffer(uint8_t black_value, uint8_t color_value)
51{
52 _initial_write = false; // initial full screen buffer clean done
53 _Init_Part();
54 _writeCommand(0x91); // partial in
55 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
56 _writeCommand(0x10);
57 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
58 {
59 _writeData(black_value);
60 }
61 _writeCommand(0x13);
62 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
63 {
64 _writeData(color_value);
65 }
66 _writeCommand(0x92); // partial out
67}
68
69void GxEPD2_213_Z19c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
70{
71 writeImage(bitmap, NULL, x, y, w, h, invert, mirror_y, pgm);
72}
73
74void GxEPD2_213_Z19c::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)
75{
76 _writeImage(0x10, black, x, y, w, h, invert, mirror_y, pgm);
77 _writeImage(0x13, color, x, y, w, h, invert, mirror_y, pgm);
78}
79
80void GxEPD2_213_Z19c::_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)
81{
82 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
83 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
84 int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
85 x -= x % 8; // byte boundary
86 w = wb * 8; // byte boundary
87 int16_t x1 = x < 0 ? 0 : x; // limit
88 int16_t y1 = y < 0 ? 0 : y; // limit
89 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
90 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
91 int16_t dx = x1 - x;
92 int16_t dy = y1 - y;
93 w1 -= dx;
94 h1 -= dy;
95 if ((w1 <= 0) || (h1 <= 0)) return;
96 _Init_Part();
97 _writeCommand(0x91); // partial in
98 _setPartialRamArea(x1, y1, w1, h1);
99 _writeCommand(command);
100 for (int16_t i = 0; i < h1; i++)
101 {
102 for (int16_t j = 0; j < w1 / 8; j++)
103 {
104 uint8_t data = 0xFF;
105 if (bitmap)
106 {
107 // use wb, h of bitmap for index!
108 int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
109 if (pgm)
110 {
111#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
112 data = pgm_read_byte(&bitmap[idx]);
113#else
114 data = bitmap[idx];
115#endif
116 }
117 else
118 {
119 data = bitmap[idx];
120 }
121 if (invert) data = ~data;
122 }
123 _writeData(data);
124 }
125 }
126 _writeCommand(0x92); // partial out
127 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
128}
129
130void GxEPD2_213_Z19c::writeImagePrevious(const uint8_t* black, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
131{
132 _writeImage(0x10, black, x, y, w, h, invert, mirror_y, pgm);
133}
134
135void GxEPD2_213_Z19c::writeImageNew(const uint8_t* black, int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
136{
137 _writeImage(0x13, black, x, y, w, h, invert, mirror_y, pgm);
138}
139
140void GxEPD2_213_Z19c::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
141 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
142{
143 writeImagePart(bitmap, NULL, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
144}
145
146void GxEPD2_213_Z19c::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,
147 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
148{
149 _writeImagePart(0x10, black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
150 _writeImagePart(0x13, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
151}
152
153void GxEPD2_213_Z19c::_writeImagePart(uint8_t command, const uint8_t* bitmap, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
154 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
155{
156 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
157 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
158 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
159 if ((x_part < 0) || (x_part >= w_bitmap)) return;
160 if ((y_part < 0) || (y_part >= h_bitmap)) return;
161 int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
162 x_part -= x_part % 8; // byte boundary
163 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
164 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
165 x -= x % 8; // byte boundary
166 w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
167 int16_t x1 = x < 0 ? 0 : x; // limit
168 int16_t y1 = y < 0 ? 0 : y; // limit
169 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
170 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
171 int16_t dx = x1 - x;
172 int16_t dy = y1 - y;
173 w1 -= dx;
174 h1 -= dy;
175 if ((w1 <= 0) || (h1 <= 0)) return;
176 if (!_using_partial_mode) _Init_Part();
177 _writeCommand(0x91); // partial in
178 _setPartialRamArea(x1, y1, w1, h1);
179 _writeCommand(command);
180 for (int16_t i = 0; i < h1; i++)
181 {
182 for (int16_t j = 0; j < w1 / 8; j++)
183 {
184 uint8_t data;
185 // use wb_bitmap, h_bitmap of bitmap for index!
186 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;
187 if (pgm)
188 {
189#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
190 data = pgm_read_byte(&bitmap[idx]);
191#else
192 data = bitmap[idx];
193#endif
194 }
195 else
196 {
197 data = bitmap[idx];
198 }
199 if (invert) data = ~data;
200 _writeData(data);
201 }
202 }
203 _writeCommand(0x92); // partial out
204 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
205}
206
207void GxEPD2_213_Z19c::writeImagePartPrevious(const uint8_t* black, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
208 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
209{
210 _writeImagePart(0x10, black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
211}
212
213void GxEPD2_213_Z19c::writeImagePartNew(const uint8_t* black, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
214 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
215{
216 _writeImagePart(0x13, black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
217}
218
219void GxEPD2_213_Z19c::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)
220{
221 if (data1)
222 {
223 writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
224 }
225}
226
227void GxEPD2_213_Z19c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
228{
229 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
230 refresh(x, y, w, h);
231}
232
233void GxEPD2_213_Z19c::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
234 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
235{
236 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
237 refresh(x, y, w, h);
238}
239
240void GxEPD2_213_Z19c::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)
241{
242 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
243 refresh(x, y, w, h);
244}
245
246void GxEPD2_213_Z19c::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,
247 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
248{
249 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
250 refresh(x, y, w, h);
251}
252
253void GxEPD2_213_Z19c::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)
254{
255 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
256 refresh(x, y, w, h);
257}
258
259void GxEPD2_213_Z19c::refresh(bool partial_update_mode)
260{
261 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
262 else _Update_Full();
263}
264
265void GxEPD2_213_Z19c::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
266{
267 // intersection with screen
268 int16_t w1 = x < 0 ? w + x : w; // reduce
269 int16_t h1 = y < 0 ? h + y : h; // reduce
270 int16_t x1 = x < 0 ? 0 : x; // limit
271 int16_t y1 = y < 0 ? 0 : y; // limit
272 w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
273 h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
274 if ((w1 <= 0) || (h1 <= 0)) return;
275 // make x1, w1 multiple of 8
276 w1 += x1 % 8;
277 if (w1 % 8 > 0) w1 += 8 - w1 % 8;
278 x1 -= x1 % 8;
279 _Init_Part();
280 if (usePartialUpdateWindow) _writeCommand(0x91); // partial in
281 _setPartialRamArea(x1, y1, w1, h1);
282 _Update_Part();
283 if (usePartialUpdateWindow) _writeCommand(0x92); // partial out
284}
285
287{
288 _PowerOff();
289}
290
292{
293 _PowerOff();
294 if (_rst >= 0)
295 {
296 _writeCommand(0x07); // deep sleep
297 _writeData(0xA5); // check code
298 _hibernating = true;
299 }
300}
301
302void GxEPD2_213_Z19c::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
303{
304 uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
305 uint16_t ye = y + h - 1;
306 x &= 0xFFF8; // byte boundary
307 _writeCommand(0x90); // partial window
308 //_writeData(x / 256);
309 _writeData(x % 256);
310 //_writeData(xe / 256);
311 _writeData(xe % 256);
312 _writeData(y / 256);
313 _writeData(y % 256);
314 _writeData(ye / 256);
315 _writeData(ye % 256);
316 _writeData(0x01); // don't see any difference
317 //_writeData(0x00); // don't see any difference
318}
319
320void GxEPD2_213_Z19c::_PowerOn()
321{
322 if (!_power_is_on)
323 {
324 _writeCommand(0x04);
325 _waitWhileBusy("_PowerOn", power_on_time);
326 }
327 _power_is_on = true;
328}
329
330void GxEPD2_213_Z19c::_PowerOff()
331{
332 _writeCommand(0x02); // power off
333 _waitWhileBusy("_PowerOff", power_off_time);
334 _power_is_on = false;
335}
336
337void GxEPD2_213_Z19c::_InitDisplay()
338{
339 if (_hibernating) _reset();
340 _writeCommand(0x00); // panel setting
341 _writeData(0x8f); // LUT from OTP
342 _writeCommand(0x61); // resolution setting
344 _writeData (HEIGHT >> 8);
345 _writeData (HEIGHT & 0xFF);
346 _writeCommand(0x50); // VCOM AND DATA INTERVAL SETTING
347 _writeData(0x77); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
348}
349
350void GxEPD2_213_Z19c::_Init_Full()
351{
352 _InitDisplay();
353 _PowerOn();
354}
355
356void GxEPD2_213_Z19c::_Init_Part()
357{
358 _InitDisplay();
359 _PowerOn();
360}
361
362void GxEPD2_213_Z19c::_Update_Full()
363{
364 _writeCommand(0x12); //display refresh
365 _waitWhileBusy("_Update_Full", full_refresh_time);
366}
367
368void GxEPD2_213_Z19c::_Update_Part()
369{
370 _writeCommand(0x12); //display refresh
371 _waitWhileBusy("_Update_Part", partial_refresh_time);
372}
373
374const unsigned char GxEPD2_213_Z19c::lut_20_vcomDC_partial[] =
375{
376 0x00, 0x1F, 0x01, 0x00, 0x00, 0x01,
377};
378
379const unsigned char GxEPD2_213_Z19c::lut_21_ww_partial[] =
380{
381 0x00, 0x1F, 0x01, 0x00, 0x00, 0x01,
382};
383
384const unsigned char GxEPD2_213_Z19c::lut_22_bw_partial[] PROGMEM =
385{
386 0x80, 0x1F, 0x01, 0x00, 0x00, 0x01,
387};
388
389const unsigned char GxEPD2_213_Z19c::lut_23_wb_partial[] PROGMEM =
390{
391 0x40, 0x1F, 0x01, 0x00, 0x00, 0x01,
392};
393
394const unsigned char GxEPD2_213_Z19c::lut_24_bb_partial[] PROGMEM =
395{
396 0x00, 0x1F, 0x01, 0x00, 0x00, 0x01,
397};
398
399void GxEPD2_213_Z19c::refresh_bw(int16_t x, int16_t y, int16_t w, int16_t h)
400{
401 x -= x % 8; // byte boundary
402 w -= w % 8; // byte boundary
403 int16_t x1 = x < 0 ? 0 : x; // limit
404 int16_t y1 = y < 0 ? 0 : y; // limit
405 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
406 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
407 w1 -= x1 - x;
408 h1 -= y1 - y;
409 _Init_Part();
410 _writeCommand(0x20);
411 _writeDataPGM(lut_20_vcomDC_partial, sizeof(lut_20_vcomDC_partial), 44 - sizeof(lut_20_vcomDC_partial));
412 _writeCommand(0x21);
413 _writeDataPGM(lut_21_ww_partial, sizeof(lut_21_ww_partial), 42 - sizeof(lut_21_ww_partial));
414 _writeCommand(0x22);
415 _writeDataPGM(lut_22_bw_partial, sizeof(lut_22_bw_partial), 42 - sizeof(lut_22_bw_partial));
416 _writeCommand(0x23);
417 _writeDataPGM(lut_23_wb_partial, sizeof(lut_23_wb_partial), 42 - sizeof(lut_23_wb_partial));
418 _writeCommand(0x24);
419 _writeDataPGM(lut_24_bb_partial, sizeof(lut_24_bb_partial), 42 - sizeof(lut_24_bb_partial));
420 _writeCommand(0x00); // panel setting
421 _writeData(0xbf); // LUT from registers, b/w
422 _writeCommand(0x50); // VCOM AND DATA INTERVAL SETTING
423 _writeData(0xf7); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
424 _writeCommand(0x91); // partial in
425 _setPartialRamArea(x1, y1, w1, h1);
426 _Update_Part();
427 _writeCommand(0x92); // partial out
428 _writeCommand(0x00); // panel setting
429 _writeData(0x8f); // LUT from OTP
430}
const unsigned char GxEPD2_213_Z19c::lut_22_bw_partial[] PROGMEM
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 writeImageNew(const uint8_t *black, 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 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_213_Z19c(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
static const uint16_t power_off_time
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 writeImagePartNew(const uint8_t *black, 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)
static const uint16_t partial_refresh_time
static const uint16_t WIDTH
void writeImagePrevious(const uint8_t *black, 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 writeImagePartPrevious(const uint8_t *black, 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 clearScreen(uint8_t value=0xFF)
static const uint16_t power_on_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 refresh_bw(int16_t x, int16_t y, int16_t w, int16_t h)
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)
static const uint16_t HEIGHT
static const bool usePartialUpdateWindow
void refresh(bool partial_update_mode=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
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)