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