Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_1248c.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:
5// Panel: GDEY1248Z51 : https://www.good-display.com/product/422.html
6// Controller: UC8179 : https://v4.cecdn.yun300.cn/100001_1909185148/UC8179.pdf
7// Connection Module : e.g. DESPI-C1248 : https://buyepaper.com/products/connection-board-for-1248-inch-large-eaper-e-ink-display-demo-despi-c1248
8// Demo Kit : e.g. DESPI-1248 : https://buy-lcd.com/products/demo-kit-driver-development-board-for-1248-inch-large-eaper-e-ink-display
9// Waveshare Kit : https://www.waveshare.com/product/displays/e-paper/epaper-1/12.48inch-e-paper-module-b.htm
10//
11// Author: Jean-Marc Zingg
12//
13// Version: see library.properties
14//
15// Library: https://github.com/ZinggJM/GxEPD2
16
17#include "GxEPD2_1248c.h"
18
19#if defined(ESP32)
20// general constructor for use with all parameters on ESP32, e.g. for Waveshare ESP32 driver board mounted on connection board
21GxEPD2_1248c::GxEPD2_1248c(int16_t sck, int16_t miso, int16_t mosi,
22 int16_t cs_m1, int16_t cs_s1, int16_t cs_m2, int16_t cs_s2,
23 int16_t dc1, int16_t dc2, int16_t rst1, int16_t rst2,
24 int16_t busy_m1, int16_t busy_s1, int16_t busy_m2, int16_t busy_s2) :
25 GxEPD2_EPD(cs_m1, dc1, rst1, busy_m1, LOW, 20000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
26 _sck(sck), _miso(miso), _mosi(mosi), _dc1(dc1), _dc2(dc2), _rst1(rst1), _rst2(rst2),
27 _cs_m1(cs_m1), _cs_s1(cs_s1), _cs_m2(cs_m2), _cs_s2(cs_s2),
28 _busy_m1(busy_m1), _busy_s1(busy_s1), _busy_m2(busy_m2), _busy_s2(busy_s2),
29 _temperature(20),
30 M1(648, 492, false, cs_m1, dc1),
31 S1(656, 492, false, cs_s1, dc1),
32 M2(656, 492, true, cs_m2, dc2),
33 S2(648, 492, true, cs_s2, dc2)
34{
35}
36#endif
37
38// general constructor for use with standard SPI pins, default SCK, MISO and MOSI
39GxEPD2_1248c::GxEPD2_1248c(int16_t cs_m1, int16_t cs_s1, int16_t cs_m2, int16_t cs_s2,
40 int16_t dc1, int16_t dc2, int16_t rst1, int16_t rst2,
41 int16_t busy_m1, int16_t busy_s1, int16_t busy_m2, int16_t busy_s2) :
42 GxEPD2_EPD(cs_m1, dc1, rst1, busy_m1, LOW, 20000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
43 _sck(SCK), _miso(MISO), _mosi(MOSI), _dc1(dc1), _dc2(dc2), _rst1(rst1), _rst2(rst2),
44 _cs_m1(cs_m1), _cs_s1(cs_s1), _cs_m2(cs_m2), _cs_s2(cs_s2),
45 _busy_m1(busy_m1), _busy_s1(busy_s1), _busy_m2(busy_m2), _busy_s2(busy_s2),
46 _temperature(20),
47 M1(648, 492, false, cs_m1, dc1),
48 S1(656, 492, false, cs_s1, dc1),
49 M2(656, 492, true, cs_m2, dc2),
50 S2(648, 492, true, cs_s2, dc2)
51{
52}
53
54// constructor with minimal parameter set, standard SPI, dc1 and dc2, rst1 and rst2 to one pin, one busy used (can be -1)
55GxEPD2_1248c::GxEPD2_1248c(int16_t cs_m1, int16_t cs_s1, int16_t cs_m2, int16_t cs_s2, int16_t dc, int16_t rst, int16_t busy) :
56 GxEPD2_EPD(23, 25, 33, 32, LOW, 20000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate),
57 _sck(SCK), _miso(MISO), _mosi(MOSI), _dc1(dc), _dc2(dc), _rst1(rst), _rst2(rst),
58 _cs_m1(cs_m1), _cs_s1(cs_s1), _cs_m2(cs_m2), _cs_s2(cs_s2),
59 _busy_m1(busy), _busy_s1(busy), _busy_m2(busy), _busy_s2(busy),
60 _temperature(20),
61 M1(648, 492, false, cs_m1, dc),
62 S1(656, 492, false, cs_s1, dc),
63 M2(656, 492, true, cs_m2, dc),
64 S2(648, 492, true, cs_s2, dc)
65{
66}
67
68void GxEPD2_1248c::init(uint32_t serial_diag_bitrate)
69{
70 init(serial_diag_bitrate, true, 20, false);
71}
72
73void GxEPD2_1248c::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode)
74{
75 _initial_write = initial;
76 _initial_refresh = initial;
77 _using_partial_mode = false;
78 if (serial_diag_bitrate > 0)
79 {
80 Serial.begin(serial_diag_bitrate);
81 _diag_enabled = true;
82 Serial.println(); Serial.println("GxEPD2_1248c::init()");
83 }
84 pinMode(_cs_m1, OUTPUT);
85 pinMode(_cs_s1, OUTPUT);
86 pinMode(_cs_m2, OUTPUT);
87 pinMode(_cs_s2, OUTPUT);
88 pinMode(_dc1, OUTPUT);
89 pinMode(_dc2, OUTPUT);
90 pinMode(_rst1, OUTPUT);
91 pinMode(_rst2, OUTPUT);
92 pinMode(_busy_m1, INPUT);
93 pinMode(_busy_s1, INPUT);
94 pinMode(_busy_m2, INPUT);
95 pinMode(_busy_s2, INPUT);
96 digitalWrite(_cs_m1, HIGH);
97 digitalWrite(_cs_s1, HIGH);
98 digitalWrite(_cs_m2, HIGH);
99 digitalWrite(_cs_s2, HIGH);
100 _initSPI();
101 _reset();
102 // only relevant for full refresh, comment out if 20 is ok
103 _getMasterTemperature();
104}
105
106void GxEPD2_1248c::clearScreen(uint8_t value)
107{
108 writeScreenBuffer(value);
109 refresh(true);
110}
111
112void GxEPD2_1248c::_writeScreenBuffer(uint8_t command, uint8_t value)
113{
114 M1.writeScreenBuffer(command, value);
115 S1.writeScreenBuffer(command, value);
116 M2.writeScreenBuffer(command, value);
117 S2.writeScreenBuffer(command, value);
118}
119
121{
122 if (!_using_partial_mode) _Init_Part();
123 _writeScreenBuffer(0x10, value); // black
124 _writeScreenBuffer(0x13, ~value); // color
125 _initial_write = false; // initial full screen buffer clean done
126}
127
128void GxEPD2_1248c::writeScreenBuffer(uint8_t black_value, uint8_t color_value)
129{
130 if (!_using_partial_mode) _Init_Part();
131 _writeScreenBuffer(0x10, black_value); // black
132 _writeScreenBuffer(0x13, color_value); // color
133 _initial_write = false; // initial full screen buffer clean done
134}
135
136void GxEPD2_1248c::_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)
137{
138 if (bitmap)
139 {
140 S2.writeImagePart(command, bitmap, 0, 0, w, h, x, y, w, h, invert, mirror_y, pgm);
141 M2.writeImagePart(command, bitmap, 0, 0, w, h, x - S2.WIDTH, y, w, h, invert, mirror_y, pgm);
142 M1.writeImagePart(command, bitmap, 0, 0, w, h, x, y - S2.HEIGHT, w, h, invert, mirror_y, pgm);
143 S1.writeImagePart(command, bitmap, 0, 0, w, h, x - M1.WIDTH, y - M2.HEIGHT, w, h, invert, mirror_y, pgm);
144 }
145}
146
147void GxEPD2_1248c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
148{
149 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
150 if (!_using_partial_mode) _Init_Part();
151 _writeImage(0x10, bitmap, x, y, w, h, invert, mirror_y, pgm); // black
152 _writeScreenBuffer(0x13, 0x0); // color (white)
153}
154
155void GxEPD2_1248c::_writeImagePart(uint8_t command, const uint8_t* bitmap, int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
156 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
157{
158 if (bitmap)
159 {
160 S2.writeImagePart(command, bitmap, x_part, y_part, w, h, x, y, w, h, invert, mirror_y, pgm);
161 M2.writeImagePart(command, bitmap, x_part, y_part, w, h, x - S2.WIDTH, y, w, h, invert, mirror_y, pgm);
162 M1.writeImagePart(command, bitmap, x_part, y_part, w, h, x, y - S2.HEIGHT, w, h, invert, mirror_y, pgm);
163 S1.writeImagePart(command, bitmap, x_part, y_part, w, h, x - M1.WIDTH, y - M2.HEIGHT, w, h, invert, mirror_y, pgm);
164 }
165}
166
167void GxEPD2_1248c::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
168 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
169{
170 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
171 if (!_using_partial_mode) _Init_Part();
172 _writeImagePart(0x10, bitmap, x_part, y_part, w, h, x, y, w, h, invert, mirror_y, pgm); // black
173}
174
175void GxEPD2_1248c::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)
176{
177 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
178 if (!_using_partial_mode) _Init_Part();
179 _writeImage(0x10, black, x, y, w, h, invert, mirror_y, pgm);
180 _writeImage(0x13, color, x, y, w, h, !invert, mirror_y, pgm);
181}
182
183void GxEPD2_1248c::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,
184 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
185{
186 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
187 if (!_using_partial_mode) _Init_Part();
188 _writeImagePart(0x10, black, x_part, y_part, w, h, x, y, w, h, invert, mirror_y, pgm);
189 _writeImagePart(0x13, color, x_part, y_part, w, h, x, y, w, h, !invert, mirror_y, pgm);
190}
191
192void GxEPD2_1248c::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)
193{
194 writeImage(data1, data2, x, y, w, h, invert, mirror_y, pgm);
195}
196
197void GxEPD2_1248c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
198{
199 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
200 refresh(x, y, w, h);
201}
202
203void GxEPD2_1248c::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
204 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
205{
206 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
207 refresh(x, y, w, h);
208}
209
210void GxEPD2_1248c::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)
211{
212 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
213 refresh(x, y, w, h);
214}
215
216void GxEPD2_1248c::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,
217 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
218{
219 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
220 refresh(x, y, w, h);
221}
222
223void GxEPD2_1248c::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)
224{
225 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
226 refresh(x, y, w, h);
227}
228
229void GxEPD2_1248c::refresh(bool partial_update_mode)
230{
231 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
232 else
233 {
234 if (_using_partial_mode) _Init_Full();
235 _Update_Full();
236 _initial_refresh = false; // initial full update done
237 }
238}
239
240void GxEPD2_1248c::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
241{
242 if (_initial_refresh) return refresh(false); // initial update needs be full update
243 if (!_using_partial_mode) _Init_Part();
244 _Update_Part();
245}
246
248{
249 _PowerOff();
250}
251
253{
254 _PowerOff();
255 if (_rst >= 0)
256 {
257 _writeCommandAll(0x07); // deep sleep
258 _writeDataAll(0xA5); // check code
259 _hibernating = true;
260 }
261}
262
263void GxEPD2_1248c::_reset(void)
264{
265 digitalWrite(_rst1, LOW);
266 digitalWrite(_rst2, LOW);
267 delay(200);
268 digitalWrite(_rst1, HIGH);
269 digitalWrite(_rst2, HIGH);
270 delay(200);
271 _hibernating = false;
272}
273
274void GxEPD2_1248c::_initSPI()
275{
276#if defined(ESP32)
277 if ((SCK != _sck) || (MISO != _miso) || (MOSI != _mosi))
278 {
279 SPI.end();
280 SPI.begin(_sck, _miso, _mosi, _cs_m1);
281 }
282 else SPI.begin();
283#else
284 SPI.begin();
285#endif
286}
287
288void GxEPD2_1248c::_PowerOn()
289{
290 if (!_power_is_on)
291 {
292 _writeCommandMaster(0x04);
293 _waitWhileAnyBusy("_PowerOn", power_on_time);
294 }
295 _power_is_on = true;
296}
297
298void GxEPD2_1248c::_PowerOff()
299{
300 if (_power_is_on)
301 {
302 _writeCommandMaster(0x02); // power off
303 _waitWhileAnyBusy("_PowerOff", power_on_time);
304 }
305 _power_is_on = false;
306 _using_partial_mode = false;
307}
308
309void GxEPD2_1248c::_InitDisplay()
310{
311 if (_hibernating) _reset();
312 //panel setting
313 M1.writeCommand(0x00);
314 M1.writeData(0x0f); //KW-3f KWR-2F BWROTP 0f BWOTP 1f
315 S1.writeCommand(0x00);
316 S1.writeData(0x0f);
317 M2.writeCommand(0x00);
318 M2.writeData(0x03); // reverse scan
319 S2.writeCommand(0x00);
320 S2.writeData(0x03); // reverse scan
321 // booster soft start
322 M1.writeCommand(0x06);
323 M1.writeData(0x27); //A
324 M1.writeData(0x27); //B
325 M1.writeData(0x18); //C
326 M1.writeData(0x17);
327 M2.writeCommand(0x06);
328 M2.writeData(0x27);
329 M2.writeData(0x27);
330 M2.writeData(0x18);
331 M2.writeData(0x17);
332 //resolution setting
333 M1.writeCommand(0x61);
334 M1.writeData(0x02);
335 M1.writeData(0x88); //source 648
336 M1.writeData(0x01); //gate 492
337 M1.writeData(0xEC);
338 S1.writeCommand(0x61);
339 S1.writeData(0x02);
340 S1.writeData(0x90); //source 656
341 S1.writeData(0x01); //gate 492
342 S1.writeData(0xEC);
343 M2.writeCommand(0x61);
344 M2.writeData(0x02);
345 M2.writeData(0x90); //source 656
346 M2.writeData(0x01); //gate 492
347 M2.writeData(0xEC);
348 S2.writeCommand(0x61);
349 S2.writeData(0x02);
350 S2.writeData(0x88); //source 648
351 S2.writeData(0x01); //gate 492
352 S2.writeData(0xEC);
353 _writeCommandAll(0x15); //DUSPI
354 _writeDataAll(0x20); // normal (single DIN) SPI
355 _writeCommandAll(0x50); //Vcom and data interval setting
356 _writeDataAll(0x11); //Border KW
357 _writeDataAll(0x07);
358
359 _writeCommandAll(0x60); //TCON
360 _writeDataAll(0x22);
361
362 _writeCommandAll(0xE3);
363 _writeDataAll(0x00);
364
365 _writeCommandAll(0xe0); //Cascade setting
366 _writeDataAll(0x03);
367
368 _writeCommandAll(0xe5); //Force temperature
369 _writeDataAll(_temperature);
370}
371
372void GxEPD2_1248c::_Init_Full()
373{
374 Serial.println("_Init_Full");
375 _InitDisplay();
376 // LUT from OTP
377 M1.writeCommand(0x00);
378 M1.writeData(0x0f); //KW-3f KWR-2F BWROTP 0f BWOTP 1f
379 S1.writeCommand(0x00);
380 S1.writeData(0x0f);
381 M2.writeCommand(0x00);
382 M2.writeData(0x03); // reverse scan
383 S2.writeCommand(0x00);
384 S2.writeData(0x03); // reverse scan
385 _PowerOn();
386 _using_partial_mode = false;
387}
388
389void GxEPD2_1248c::_Init_Part()
390{
391 Serial.println("_Init_Part");
392 _InitDisplay();
393 // LUT from OTP
394 M1.writeCommand(0x00);
395 M1.writeData(0x0f); //KW-3f KWR-2F BWROTP 0f BWOTP 1f
396 S1.writeCommand(0x00);
397 S1.writeData(0x0f);
398 M2.writeCommand(0x00);
399 M2.writeData(0x03); // reverse scan
400 S2.writeCommand(0x00);
401 S2.writeData(0x03); // reverse scan
402 _PowerOn();
403 _using_partial_mode = true;
404}
405
406void GxEPD2_1248c::_Update_Full()
407{
408 _writeCommandAll(0x12); //display refresh
409 _waitWhileAnyBusy("_Update_Full", full_refresh_time);
410}
411
412void GxEPD2_1248c::_Update_Part()
413{
414 _writeCommandAll(0x12); //display refresh
415 _waitWhileAnyBusy("_Update_Part", partial_refresh_time);
416}
417
418void GxEPD2_1248c::_writeCommandMaster(uint8_t c)
419{
420 SPI.beginTransaction(_spi_settings);
421 digitalWrite(_dc1, LOW);
422 digitalWrite(_dc2, LOW);
423 digitalWrite(_cs_m1, LOW);
424 digitalWrite(_cs_m2, LOW);
425 SPI.transfer(c);
426 digitalWrite(_cs_m1, HIGH);
427 digitalWrite(_cs_m2, HIGH);
428 digitalWrite(_dc1, HIGH);
429 digitalWrite(_dc2, HIGH);
430 SPI.endTransaction();
431}
432
433void GxEPD2_1248c::_writeDataMaster(uint8_t d)
434{
435 SPI.beginTransaction(_spi_settings);
436 digitalWrite(_cs_m1, LOW);
437 digitalWrite(_cs_m2, LOW);
438 SPI.transfer(d);
439 digitalWrite(_cs_m1, HIGH);
440 digitalWrite(_cs_m2, HIGH);
441 SPI.endTransaction();
442}
443
444void GxEPD2_1248c::_writeCommandAll(uint8_t c)
445{
446 SPI.beginTransaction(_spi_settings);
447 digitalWrite(_dc1, LOW);
448 digitalWrite(_dc2, LOW);
449 digitalWrite(_cs_m1, LOW);
450 digitalWrite(_cs_s1, LOW);
451 digitalWrite(_cs_m2, LOW);
452 digitalWrite(_cs_s2, LOW);
453 SPI.transfer(c);
454 digitalWrite(_cs_m1, HIGH);
455 digitalWrite(_cs_s1, HIGH);
456 digitalWrite(_cs_m2, HIGH);
457 digitalWrite(_cs_s2, HIGH);
458 digitalWrite(_dc1, HIGH);
459 digitalWrite(_dc2, HIGH);
460 SPI.endTransaction();
461}
462
463void GxEPD2_1248c::_writeDataAll(uint8_t d)
464{
465 SPI.beginTransaction(_spi_settings);
466 digitalWrite(_cs_m1, LOW);
467 digitalWrite(_cs_s1, LOW);
468 digitalWrite(_cs_m2, LOW);
469 digitalWrite(_cs_s2, LOW);
470 SPI.transfer(d);
471 digitalWrite(_cs_m1, HIGH);
472 digitalWrite(_cs_s1, HIGH);
473 digitalWrite(_cs_m2, HIGH);
474 digitalWrite(_cs_s2, HIGH);
475 SPI.endTransaction();
476}
477
478void GxEPD2_1248c::_writeDataPGM_All(const uint8_t* data, uint16_t n, int16_t fill_with_zeroes)
479{
480 SPI.beginTransaction(_spi_settings);
481 digitalWrite(_cs_m1, LOW);
482 digitalWrite(_cs_s1, LOW);
483 digitalWrite(_cs_m2, LOW);
484 digitalWrite(_cs_s2, LOW);
485 for (uint16_t i = 0; i < n; i++)
486 {
487 SPI.transfer(pgm_read_byte(&*data++));
488 }
489 while (fill_with_zeroes > 0)
490 {
491 SPI.transfer(0x00);
492 fill_with_zeroes--;
493 }
494 digitalWrite(_cs_m1, HIGH);
495 digitalWrite(_cs_s1, HIGH);
496 digitalWrite(_cs_m2, HIGH);
497 digitalWrite(_cs_s2, HIGH);
498 SPI.endTransaction();
499}
500
501void GxEPD2_1248c::_waitWhileAnyBusy(const char* comment, uint16_t busy_time)
502{
503 if (_busy_m1 >= 0)
504 {
505 delay(1); // add some margin to become active
506 unsigned long start = micros();
507 while (1)
508 {
509 delay(1); // add some margin to become active
510 bool nb_m1 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_m1) : true;
511 bool nb_s1 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_s1) : true;
512 bool nb_m2 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_m2) : true;
513 bool nb_s2 = _busy_m1 >= 0 ? _busy_level != digitalRead(_busy_s2) : true;
514 if (nb_m1 && nb_s1 && nb_m2 && nb_s2) break;
515 delay(1);
516 if (micros() - start > _busy_timeout)
517 {
518 Serial.println("Busy Timeout!");
519 break;
520 }
521 }
522 if (comment)
523 {
524 if (_diag_enabled)
525 {
526 unsigned long elapsed = micros() - start;
527 Serial.print(comment);
528 Serial.print(" : ");
529 Serial.println(elapsed);
530 }
531 }
532 (void) start;
533 }
534 else delay(busy_time);
535}
536
537void GxEPD2_1248c::_getMasterTemperature()
538{
539 uint8_t value = 0;
540 M1.writeCommand(0x40);
541 _waitWhileAnyBusy("getMasterTemperature", 300);
542 SPI.end();
543 pinMode(_mosi, INPUT);
544 delay(100);
545 digitalWrite(_sck, HIGH);
546 pinMode(_sck, OUTPUT);
547 digitalWrite(_cs_m1, LOW);
548 pinMode(_mosi, INPUT);
549 for (uint16_t i = 0; i < 8; i++)
550 {
551 digitalWrite(_sck, LOW);
552 value <<= 1;
553 delayMicroseconds(2);
554 if (digitalRead(_mosi)) value |= 0x01;
555 delayMicroseconds(2);
556 digitalWrite(_sck, HIGH);
557 delayMicroseconds(2);
558 }
559 digitalWrite(_cs_m1, HIGH);
560 pinMode(_sck, INPUT);
561 _temperature = value;
562 _initSPI();
563 if (_diag_enabled)
564 {
565 Serial.print("Master Temperature is "); Serial.println(value);
566 }
567}
568
569void GxEPD2_1248c::_readController(uint8_t cmd, uint8_t* data, uint16_t n, int8_t cs, int8_t dc)
570{
571 if (cs < 0) cs = _cs_m1;
572 if (dc < 0) dc = _dc1;
573 SPI.beginTransaction(_spi_settings);
574 digitalWrite(cs, LOW);
575 digitalWrite(dc, LOW);
576 SPI.transfer(cmd);
577 digitalWrite(dc, HIGH);
578 digitalWrite(cs, HIGH);
579 SPI.endTransaction();
580 _waitWhileAnyBusy("_readController", 300);
581 SPI.end();
582 pinMode(_mosi, INPUT);
583 delay(100);
584 digitalWrite(_sck, HIGH);
585 pinMode(_sck, OUTPUT);
586 digitalWrite(cs, LOW);
587 pinMode(_mosi, INPUT);
588 for (uint16_t j = 0; j < n; j++)
589 {
590 uint8_t value = 0;
591 for (uint16_t i = 0; i < 8; i++)
592 {
593 digitalWrite(_sck, LOW);
594 value <<= 1;
595 delayMicroseconds(2);
596 if (digitalRead(_mosi)) value |= 0x01;
597 delayMicroseconds(2);
598 digitalWrite(_sck, HIGH);
599 delayMicroseconds(2);
600 }
601 data[j] = value;
602 }
603 digitalWrite(cs, HIGH);
604 pinMode(_sck, INPUT);
605 _initSPI();
606}
607
608GxEPD2_1248c::ScreenPart::ScreenPart(uint16_t width, uint16_t height, bool rev_scan, int16_t cs, int16_t dc) :
609 WIDTH(width), HEIGHT(height), _rev_scan(rev_scan),
610 _cs(cs), _dc(dc), _spi_settings(4000000, MSBFIRST, SPI_MODE0)
611{
612}
613
614void GxEPD2_1248c::ScreenPart::writeScreenBuffer(uint8_t command, uint8_t value)
615{
616 writeCommand(command); // set current or previous
617 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
618 {
619 writeData(value);
620 }
621}
622
623void GxEPD2_1248c::ScreenPart::writeImagePart(uint8_t command, const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
624 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
625{
626 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
627 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
628 if ((x_part < 0) || (x_part >= w_bitmap)) return;
629 if ((y_part < 0) || (y_part >= h_bitmap)) return;
630 int32_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
631 x_part -= x_part % 8; // byte boundary
632 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
633 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
634 x -= x % 8; // byte boundary
635 w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
636 int16_t x1 = x < 0 ? 0 : x; // limit
637 int16_t y1 = y < 0 ? 0 : y; // limit
638 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
639 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
640 int16_t dx = x1 - x;
641 int16_t dy = y1 - y;
642 w1 -= dx;
643 h1 -= dy;
644 if ((w1 <= 0) || (h1 <= 0)) return;
645 //Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", "); Serial.print(w); Serial.print(", "); Serial.println(h);
646 //Serial.print("->"); Serial.print(x1); Serial.print(", "); Serial.print(y1); Serial.print(", "); Serial.print(w1); Serial.print(", "); Serial.println(h1);
647 writeCommand(0x91); // partial in
648 delay(1);
649 _setPartialRamArea(x1, y1, w1, h1);
650 writeCommand(command);
652 for (int16_t i = 0; i < h1; i++)
653 {
654 for (int16_t j = 0; j < w1 / 8; j++)
655 {
656 uint8_t data;
657 // use wb_bitmap, h_bitmap of bitmap for index!
658 int32_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;
659 if (pgm)
660 {
661#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
662 data = pgm_read_byte(&bitmap[idx]);
663#else
664 data = bitmap[idx];
665#endif
666 }
667 else
668 {
669 data = bitmap[idx];
670 }
671 if (invert) data = ~data;
672 _transfer(data);
673 }
674 }
675 _endTransfer();
676 writeCommand(0x92); // partial out
677 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
678}
679
680void GxEPD2_1248c::ScreenPart::writeCommand(uint8_t c)
681{
682 SPI.beginTransaction(_spi_settings);
683 if (_dc >= 0) digitalWrite(_dc, LOW);
684 if (_cs >= 0) digitalWrite(_cs, LOW);
685 SPI.transfer(c);
686 if (_cs >= 0) digitalWrite(_cs, HIGH);
687 if (_dc >= 0) digitalWrite(_dc, HIGH);
688 SPI.endTransaction();
689}
690
691void GxEPD2_1248c::ScreenPart::writeData(uint8_t d)
692{
693 SPI.beginTransaction(_spi_settings);
694 if (_cs >= 0) digitalWrite(_cs, LOW);
695 SPI.transfer(d);
696 if (_cs >= 0) digitalWrite(_cs, HIGH);
697 SPI.endTransaction();
698}
699
700void GxEPD2_1248c::ScreenPart::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
701{
702 if (_rev_scan) x = WIDTH - w - x;
703 uint16_t xe = (x + w - 1) | 0x0007; // byte boundary inclusive (last byte)
704 uint16_t ye = y + h - 1;
705 x &= 0xFFF8; // byte boundary
706 writeCommand(0x90); // partial window
707 writeData(x / 256);
708 writeData(x % 256);
709 writeData(xe / 256);
710 writeData(xe % 256);
711 writeData(y / 256);
712 writeData(y % 256);
713 writeData(ye / 256);
714 writeData(ye % 256);
715 writeData(0x01);
716}
717
718void GxEPD2_1248c::ScreenPart::_startTransfer()
719{
720 SPI.beginTransaction(_spi_settings);
721 if (_cs >= 0) digitalWrite(_cs, LOW);
722}
723
724void GxEPD2_1248c::ScreenPart::_transfer(uint8_t value)
725{
726 SPI.transfer(value);
727}
728
729void GxEPD2_1248c::ScreenPart::_endTransfer()
730{
731 if (_cs >= 0) digitalWrite(_cs, HIGH);
732 SPI.endTransaction();
733}
void refresh(bool partial_update_mode=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)
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_on_time
static const uint16_t full_refresh_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 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)
GxEPD2_1248c(int16_t cs_m1, int16_t cs_s1, int16_t cs_m2, int16_t cs_s2, int16_t dc1, int16_t dc2, int16_t rst1, int16_t rst2, int16_t busy_m1, int16_t busy_s1, int16_t busy_m2, int16_t busy_s2)
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 partial_refresh_time
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 clearScreen(uint8_t value=0xFF)
static const uint16_t WIDTH
void init(uint32_t serial_diag_bitrate=0)
static const uint16_t HEIGHT
void writeScreenBuffer(uint8_t value=0xFF)
bool _diag_enabled
Definition GxEPD2_EPD.h:114
void _endTransfer()
int16_t _busy_level
Definition GxEPD2_EPD.h:112
bool _using_partial_mode
Definition GxEPD2_EPD.h:118
bool _power_is_on
Definition GxEPD2_EPD.h:118
bool _initial_refresh
Definition GxEPD2_EPD.h:117
void _startTransfer()
void _transfer(uint8_t value)
int16_t _dc
Definition GxEPD2_EPD.h:112
bool _initial_write
Definition GxEPD2_EPD.h:117
uint32_t _busy_timeout
Definition GxEPD2_EPD.h:113
int16_t _rst
Definition GxEPD2_EPD.h:112
SPISettings _spi_settings
Definition GxEPD2_EPD.h:116
bool _hibernating
Definition GxEPD2_EPD.h:118
int16_t _cs
Definition GxEPD2_EPD.h:112