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