Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_154c.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: IL0376F : http://www.e-paper-display.com/download_detail/downloadsId=541.html
6//
7// Author: Jean-Marc Zingg
8//
9// Version: see library.properties
10//
11// Library: https://github.com/ZinggJM/GxEPD2
12
13#include "GxEPD2_154c.h"
14
15const uint8_t GxEPD2_154c::bw2grey[] =
16{
17 0b00000000, 0b00000011, 0b00001100, 0b00001111,
18 0b00110000, 0b00110011, 0b00111100, 0b00111111,
19 0b11000000, 0b11000011, 0b11001100, 0b11001111,
20 0b11110000, 0b11110011, 0b11111100, 0b11111111,
21};
22
23GxEPD2_154c::GxEPD2_154c(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
24 GxEPD2_EPD(cs, dc, rst, busy, LOW, 20000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
25{
26 _paged = false;
27 _second_phase = false;
28}
29
30void GxEPD2_154c::init(uint32_t serial_diag_bitrate)
31{
32 GxEPD2_EPD::init(serial_diag_bitrate);
33 _paged = false;
34 _second_phase = false;
35}
36
37void GxEPD2_154c::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode)
38{
39 GxEPD2_EPD::init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode);
40 _paged = false;
41 _second_phase = false;
42}
43
44void GxEPD2_154c::clearScreen(uint8_t value)
45{
46 clearScreen(value, 0xFF);
47}
48
49void GxEPD2_154c::clearScreen(uint8_t black_value, uint8_t color_value)
50{
51 _Init_Full();
52 _writeCommand(0x10);
53 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
54 {
55 _writeData(bw2grey[(black_value & 0xF0) >> 4]);
56 _writeData(bw2grey[black_value & 0x0F]);
57 }
58 _writeCommand(0x13);
59 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
60 {
61 _writeData(color_value);
62 }
63 _Update_Full();
64}
65
67{
68 writeScreenBuffer(value, 0xFF);
69}
70
71void GxEPD2_154c::writeScreenBuffer(uint8_t black_value, uint8_t color_value)
72{
73 _Init_Full();
74 _writeCommand(0x10);
75 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
76 {
77 _writeData(bw2grey[(black_value & 0xF0) >> 4]);
78 _writeData(bw2grey[black_value & 0x0F]);
79 }
80 _writeCommand(0x13);
81 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
82 {
83 _writeData(color_value);
84 }
85}
86
87void GxEPD2_154c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
88{
89 writeImage(bitmap, NULL, x, y, w, h, invert, mirror_y, pgm);
90}
91
92void GxEPD2_154c::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)
93{
94 //Serial.print("writeImage("); Serial.print(x); Serial.print(", "); Serial.print(y); Serial.print(", ");
95 //Serial.print(w); Serial.print(", "); Serial.print(h); Serial.println(")");
96 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
97 if (_paged && (x == 0) && (w == int16_t(WIDTH)) && (h < int16_t(HEIGHT)))
98 {
99 //Serial.println("paged");
100 if (!_second_phase)
101 {
102 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
103 {
104 _writeData(bw2grey[(black[i] & 0xF0) >> 4]);
105 _writeData(bw2grey[black[i] & 0x0F]);
106 }
107 if (y + h == HEIGHT) // last page
108 {
109 //Serial.println("phase 1 ended");
110 _second_phase = true;
111 _writeCommand(0x13);
112 }
113 }
114 else
115 {
116 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(h) / 8; i++)
117 {
118 _writeData(color[i]);
119 }
120 if (y + h == HEIGHT) // last page
121 {
122 //Serial.println("phase 2 ended");
123 _second_phase = false;
124 _paged = false;
125 }
126 }
127 }
128 else
129 {
130 _paged = false;
131 uint16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
132 x -= x % 8; // byte boundary
133 w = wb * 8; // byte boundary
134 if ((w <= 0) || (h <= 0)) return;
135 _Init_Full();
136 _writeCommand(0x10);
137 for (int16_t i = 0; i < int16_t(HEIGHT); i++)
138 {
139 for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
140 {
141 uint8_t data = 0xFF;
142 if (black)
143 {
144 if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
145 {
146 uint16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
147 if (pgm)
148 {
149#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
150 data = pgm_read_byte(&black[idx]);
151#else
152 data = black[idx];
153#endif
154 }
155 else
156 {
157 data = black[idx];
158 }
159 if (invert) data = ~data;
160 }
161 }
162 //_writeData(data);
163 _writeData(bw2grey[(data & 0xF0) >> 4]);
164 _writeData(bw2grey[data & 0x0F]);
165 }
166 }
167 _writeCommand(0x13);
168 for (int16_t i = 0; i < int16_t(HEIGHT); i++)
169 {
170 for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
171 {
172 uint8_t data = 0xFF;
173 if (color)
174 {
175 if ((j >= x) && (j <= x + w) && (i >= y) && (i < y + h))
176 {
177 uint16_t idx = mirror_y ? (j - x) / 8 + ((h - 1 - (i - y))) * wb : (j - x) / 8 + (i - y) * wb;
178 if (pgm)
179 {
180#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
181 data = pgm_read_byte(&color[idx]);
182#else
183 data = color[idx];
184#endif
185 }
186 else
187 {
188 data = color[idx];
189 }
190 if (invert) data = ~data;
191 }
192 }
193 _writeData(data);
194 }
195 }
196 }
197 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
198}
199
200void GxEPD2_154c::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
201 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
202{
203 writeImagePart(bitmap, NULL, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
204}
205
206void GxEPD2_154c::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,
207 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
208{
209 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
210 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
211 if ((x_part < 0) || (x_part >= w_bitmap)) return;
212 if ((y_part < 0) || (y_part >= h_bitmap)) return;
213 int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
214 x_part -= x_part % 8; // byte boundary
215 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
216 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
217 x -= x % 8; // byte boundary
218 w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
219 int16_t x1 = x < 0 ? 0 : x; // limit
220 int16_t y1 = y < 0 ? 0 : y; // limit
221 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
222 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
223 int16_t dx = x1 - x;
224 int16_t dy = y1 - y;
225 w1 -= dx;
226 h1 -= dy;
227 if ((w1 <= 0) || (h1 <= 0)) return;
228 _Init_Full();
229 _writeCommand(0x10);
230 for (int16_t i = 0; i < int16_t(HEIGHT); i++)
231 {
232 for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
233 {
234 uint8_t data = 0xFF;
235 if (black)
236 {
237 if ((j >= x1) && (j <= x1 + w) && (i >= y1) && (i < y1 + h))
238 {
239 // use wb_bitmap, h_bitmap of bitmap for index!
240 //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;
241 uint16_t idx = mirror_y ? (x_part + j - x1) / 8 + ((h_bitmap - 1 - (y_part + i - y1))) * wb_bitmap : (x_part + j - x1) / 8 + (y_part + i - y1) * wb_bitmap;
242 if (pgm)
243 {
244#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
245 data = pgm_read_byte(&black[idx]);
246#else
247 data = black[idx];
248#endif
249 }
250 else
251 {
252 data = black[idx];
253 }
254 if (invert) data = ~data;
255 }
256 }
257 //_writeData(data);
258 _writeData(bw2grey[(data & 0xF0) >> 4]);
259 _writeData(bw2grey[data & 0x0F]);
260 }
261 }
262 _writeCommand(0x13);
263 for (int16_t i = 0; i < int16_t(HEIGHT); i++)
264 {
265 for (int16_t j = 0; j < int16_t(WIDTH); j += 8)
266 {
267 uint8_t data = 0xFF;
268 if (color)
269 {
270 if ((j >= x1) && (j <= x1 + w) && (i >= y1) && (i < y1 + h))
271 {
272 // use wb_bitmap, h_bitmap of bitmap for index!
273 uint16_t idx = mirror_y ? (x_part + j - x1) / 8 + ((h_bitmap - 1 - (y_part + i - y1))) * wb_bitmap : (x_part + j - x1) / 8 + (y_part + i - y1) * wb_bitmap;
274 if (pgm)
275 {
276#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
277 data = pgm_read_byte(&color[idx]);
278#else
279 data = color[idx];
280#endif
281 }
282 else
283 {
284 data = color[idx];
285 }
286 if (invert) data = ~data;
287 }
288 }
289 _writeData(data);
290 }
291 }
292 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
293}
294
295void GxEPD2_154c::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)
296{
297 if (data1)
298 {
299 writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
300 }
301}
302
303void GxEPD2_154c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
304{
305 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
306 refresh(x, y, w, h);
307}
308
309void GxEPD2_154c::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
310 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
311{
312 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
313 refresh(x, y, w, h);
314}
315
316void GxEPD2_154c::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)
317{
318 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
319 refresh(x, y, w, h);
320}
321
322void GxEPD2_154c::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,
323 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
324{
325 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
326 refresh(x, y, w, h);
327}
328
329void GxEPD2_154c::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)
330{
331 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
332 refresh(x, y, w, h);
333}
334
335void GxEPD2_154c::refresh(bool partial_update_mode)
336{
337 if (_paged) return;
338 _Update_Full();
339}
340
341void GxEPD2_154c::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
342{
343 _Update_Full();
344}
345
347{
348 _PowerOff();
349}
350
352{
353 _PowerOff();
354 if (_rst >= 0)
355 {
356 // check if it supports this command!
357 _writeCommand(0x07); // deep sleep
358 _writeData(0xA5); // check code
359 _hibernating = true;
360 }
361}
362
363void GxEPD2_154c::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
364{
365}
366
367void GxEPD2_154c::_PowerOn()
368{
369 if (!_power_is_on)
370 {
371 _writeCommand(0x04);
372 _waitWhileBusy("_PowerOn", power_on_time);
373 }
374 _power_is_on = true;
375}
376
377void GxEPD2_154c::_PowerOff()
378{
379 _writeCommand(0x50);
380 _writeData(0x17); //BD floating
381 _writeCommand(0x82); //to solve Vcom drop
382 _writeData(0x00);
383 _writeCommand(0x01); //power setting
384 _writeData(0x02); //gate switch to external
385 _writeData(0x00);
386 _writeData(0x00);
387 _writeData(0x00);
388 delay(1500); //delay 1.5S
389 _writeCommand(0x02); // power off
390 //_waitWhileBusy("_PowerOff", power_off_time);
391 _power_is_on = false;
392}
393
395{
396 _paged = true;
397 _second_phase = false;
398 _Init_Full();
399 _writeCommand(0x10);
400}
401
402void GxEPD2_154c::_InitDisplay()
403{
404 if (_hibernating) _reset();
405 _writeCommand(0x01);
406 _writeData(0x07);
407 _writeData(0x00);
408 _writeData(0x08);
409 _writeData(0x00);
410 _writeCommand(0x06);
411 _writeData(0x07);
412 _writeData(0x07);
413 _writeData(0x07);
414 _PowerOn(); //power on needed here!
415 _writeCommand(0x00);
416 _writeData(0xcf);
417 _writeCommand(0x50);
418 _writeData(0x37);
419 _writeCommand(0x30);
420 _writeData(0x39);
421 _writeCommand(0x61);
422 _writeData(0xC8);
423 _writeData(0x00);
424 _writeData(0xC8);
425 _writeCommand(0x82);
426 _writeData(0x0E);
427}
428
429const uint8_t GxEPD2_154c::lut_20_vcom0[] PROGMEM = { 0x0E , 0x14 , 0x01 , 0x0A , 0x06 , 0x04 , 0x0A , 0x0A , 0x0F , 0x03 , 0x03 , 0x0C , 0x06 , 0x0A , 0x00 };
430const uint8_t GxEPD2_154c::lut_21_w[] PROGMEM = { 0x0E , 0x14 , 0x01 , 0x0A , 0x46 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x86 , 0x0A , 0x04 };
431const uint8_t GxEPD2_154c::lut_22_b[] PROGMEM = { 0x0E , 0x14 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x4A , 0x04 };
432const uint8_t GxEPD2_154c::lut_23_g1[] PROGMEM = { 0x8E , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
433const uint8_t GxEPD2_154c::lut_24_g2[] PROGMEM = { 0x8E , 0x94 , 0x01 , 0x8A , 0x06 , 0x04 , 0x8A , 0x4A , 0x0F , 0x83 , 0x43 , 0x0C , 0x06 , 0x0A , 0x04 };
434const uint8_t GxEPD2_154c::lut_25_vcom1[] PROGMEM = { 0x03 , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
435const uint8_t GxEPD2_154c::lut_26_red0[] PROGMEM = { 0x83 , 0x5D , 0x01 , 0x81 , 0x48 , 0x23 , 0x77 , 0x77 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
436const uint8_t GxEPD2_154c::lut_27_red1[] PROGMEM = { 0x03 , 0x1D , 0x01 , 0x01 , 0x08 , 0x23 , 0x37 , 0x37 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
437
438void GxEPD2_154c::_Init_Full()
439{
440 _InitDisplay();
441 _writeCommand(0x20);
442 _writeDataPGM(lut_20_vcom0, sizeof(lut_20_vcom0));
443 _writeCommand(0x21);
444 _writeDataPGM(lut_21_w, sizeof(lut_21_w));
445 _writeCommand(0x22);
446 _writeDataPGM(lut_22_b, sizeof(lut_22_b));
447 _writeCommand(0x23);
448 _writeDataPGM(lut_23_g1, sizeof(lut_23_g1));
449 _writeCommand(0x24);
450 _writeDataPGM(lut_24_g2, sizeof(lut_24_g2));
451 _writeCommand(0x25);
452 _writeDataPGM(lut_25_vcom1, sizeof(lut_25_vcom1));
453 _writeCommand(0x26);
454 _writeDataPGM(lut_26_red0, sizeof(lut_26_red0));
455 _writeCommand(0x27);
456 _writeDataPGM(lut_27_red1, sizeof(lut_27_red1));
457 _PowerOn();
458}
459
460void GxEPD2_154c::_Init_Part()
461{
462 _InitDisplay();
463 _PowerOn();
464}
465
466void GxEPD2_154c::_Update_Full()
467{
468 _writeCommand(0x12); //display refresh
469 _waitWhileBusy("_Update_Full", full_refresh_time);
470}
471
472void GxEPD2_154c::_Update_Part()
473{
474 _writeCommand(0x12); //display refresh
475 _waitWhileBusy("_Update_Part", partial_refresh_time);
476}
const uint8_t GxEPD2_154c::lut_20_vcom0[] PROGMEM
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 power_on_time
Definition GxEPD2_154c.h:29
void writeScreenBuffer(uint8_t value=0xFF)
void init(uint32_t serial_diag_bitrate=0)
static const uint16_t full_refresh_time
Definition GxEPD2_154c.h:31
static const uint16_t HEIGHT
Definition GxEPD2_154c.h:24
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 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)
GxEPD2_154c(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
static const uint16_t partial_refresh_time
Definition GxEPD2_154c.h:32
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 refresh(bool partial_update_mode=false)
static const uint16_t WIDTH
Definition GxEPD2_154c.h:22
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)
void clearScreen(uint8_t value=0xFF)
void _writeCommand(uint8_t c)
void _writeData(uint8_t d)
virtual void init(uint32_t serial_diag_bitrate=0)
void _waitWhileBusy(const char *comment=0, uint16_t busy_time=5000)
bool _power_is_on
Definition GxEPD2_EPD.h:118
void _reset()
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)