Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_290_Z13c.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_290_Z13c.h"
14
15GxEPD2_290_Z13c::GxEPD2_290_Z13c(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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::_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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::_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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::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_290_Z13c::refresh(bool partial_update_mode)
260{
261 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
262 else _Update_Full();
263}
264
265void GxEPD2_290_Z13c::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_290_Z13c::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
303{
304 //Serial.print("_setPartialRamArea("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
305 uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
306 uint16_t ye = y + h - 1;
307 x &= 0xFFF8; // byte boundary
308 _writeCommand(0x90); // partial window
309 //_writeData(x / 256);
310 _writeData(x % 256);
311 //_writeData(xe / 256);
312 _writeData(xe % 256);
313 _writeData(y / 256);
314 _writeData(y % 256);
315 _writeData(ye / 256);
316 _writeData(ye % 256);
317 //_writeData(0x01); // don't see any difference
318 _writeData(0x00); // don't see any difference
319}
320
321void GxEPD2_290_Z13c::_PowerOn()
322{
323 if (!_power_is_on)
324 {
325 _writeCommand(0x04);
326 _waitWhileBusy("_PowerOn", power_on_time);
327 }
328 _power_is_on = true;
329}
330
331void GxEPD2_290_Z13c::_PowerOff()
332{
333 _writeCommand(0x50);
334 _writeData(0xf7); // border floating
335 _writeCommand(0x02); // power off
336 _waitWhileBusy("_PowerOff", power_off_time);
337 _power_is_on = false;
338}
339
340void GxEPD2_290_Z13c::_InitDisplay()
341{
342 if (_hibernating) _reset();
343 _writeCommand(0x00); // panel setting
344 _writeData(0x8f); // LUT from OTP
345 _writeCommand(0x61); // resolution setting
347 _writeData (HEIGHT >> 8);
348 _writeData (HEIGHT & 0xFF);
349 _writeCommand(0x50); // VCOM AND DATA INTERVAL SETTING
350 _writeData(0x77); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
351}
352
353void GxEPD2_290_Z13c::_Init_Full()
354{
355 _InitDisplay();
356 _PowerOn();
357}
358
359void GxEPD2_290_Z13c::_Init_Part()
360{
361 _InitDisplay();
362 _PowerOn();
363}
364
365void GxEPD2_290_Z13c::_Update_Full()
366{
367 _writeCommand(0x12); //display refresh
368 _waitWhileBusy("_Update_Full", full_refresh_time);
369}
370
371void GxEPD2_290_Z13c::_Update_Part()
372{
373 _writeCommand(0x12); //display refresh
374 _waitWhileBusy("_Update_Part", partial_refresh_time);
375}
376
377const unsigned char GxEPD2_290_Z13c::lut_20_vcomDC_partial[] =
378{
379 0x00, 0x1F, 0x01, 0x00, 0x00, 0x01,
380};
381
382const unsigned char GxEPD2_290_Z13c::lut_21_ww_partial[] =
383{
384 0x00, 0x1F, 0x01, 0x00, 0x00, 0x01,
385};
386
387const unsigned char GxEPD2_290_Z13c::lut_22_bw_partial[] PROGMEM =
388{
389 0x80, 0x1F, 0x01, 0x00, 0x00, 0x01,
390};
391
392const unsigned char GxEPD2_290_Z13c::lut_23_wb_partial[] PROGMEM =
393{
394 0x40, 0x1F, 0x01, 0x00, 0x00, 0x01,
395};
396
397const unsigned char GxEPD2_290_Z13c::lut_24_bb_partial[] PROGMEM =
398{
399 0x00, 0x1F, 0x01, 0x00, 0x00, 0x01,
400};
401
402void GxEPD2_290_Z13c::refresh_bw(int16_t x, int16_t y, int16_t w, int16_t h)
403{
404 x -= x % 8; // byte boundary
405 w -= w % 8; // byte boundary
406 int16_t x1 = x < 0 ? 0 : x; // limit
407 int16_t y1 = y < 0 ? 0 : y; // limit
408 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
409 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
410 w1 -= x1 - x;
411 h1 -= y1 - y;
412 _Init_Part();
413 _writeCommand(0x20);
414 _writeDataPGM(lut_20_vcomDC_partial, sizeof(lut_20_vcomDC_partial), 44 - sizeof(lut_20_vcomDC_partial));
415 _writeCommand(0x21);
416 _writeDataPGM(lut_21_ww_partial, sizeof(lut_21_ww_partial), 42 - sizeof(lut_21_ww_partial));
417 _writeCommand(0x22);
418 _writeDataPGM(lut_22_bw_partial, sizeof(lut_22_bw_partial), 42 - sizeof(lut_22_bw_partial));
419 _writeCommand(0x23);
420 _writeDataPGM(lut_23_wb_partial, sizeof(lut_23_wb_partial), 42 - sizeof(lut_23_wb_partial));
421 _writeCommand(0x24);
422 _writeDataPGM(lut_24_bb_partial, sizeof(lut_24_bb_partial), 42 - sizeof(lut_24_bb_partial));
423 _writeCommand(0x00); // panel setting
424 _writeData(0xbf); // LUT from registers, b/w
425 _writeCommand(0x50); // VCOM AND DATA INTERVAL SETTING
426 _writeData(0xf7); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
427 _writeCommand(0x91); // partial in
428 _setPartialRamArea(x1, y1, w1, h1);
429 _Update_Part();
430 _writeCommand(0x92); // partial out
431 _writeCommand(0x00); // panel setting
432 _writeData(0x8f); // LUT from OTP
433}
const unsigned char GxEPD2_290_Z13c::lut_22_bw_partial[] PROGMEM
static const uint16_t power_on_time
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 HEIGHT
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 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 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 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)
GxEPD2_290_Z13c(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
void refresh_bw(int16_t x, int16_t y, int16_t w, int16_t h)
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)
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)
static const uint16_t full_refresh_time
void refresh(bool partial_update_mode=false)
void clearScreen(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)
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 power_off_time
static const uint16_t partial_refresh_time
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 WIDTH
void writeScreenBuffer(uint8_t value=0xFF)
static const bool usePartialUpdateWindow
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)