Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_154.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 : IL3829 : http://www.e-paper-display.com/download_detail/downloadsId=534.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_154.h"
14
15GxEPD2_154::GxEPD2_154(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
16 GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
17{
18}
19
20void GxEPD2_154::clearScreen(uint8_t value)
21{
22 _initial_write = false; // initial full screen buffer clean done
24 {
25 _Init_Full();
26 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
27 _writeCommand(0x24);
28 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
29 {
30 _writeData(value);
31 }
32 _Update_Full();
33 _initial_refresh = false; // initial full update done
34 }
35 else
36 {
37 if (!_using_partial_mode) _Init_Part();
38 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
39 _writeCommand(0x24);
40 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
41 {
42 _writeData(value);
43 }
44 _Update_Part();
45 }
46 if (!_using_partial_mode) _Init_Part();
47 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
48 _writeCommand(0x24);
49 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
50 {
51 _writeData(value);
52 }
53 _Update_Part();
54}
55
57{
58 _initial_write = false; // initial full screen buffer clean done
59 // this controller has no command to write "old data"
60 if (_initial_refresh) clearScreen(value);
61 else _writeScreenBuffer(value);
62}
63
64void GxEPD2_154::_writeScreenBuffer(uint8_t value)
65{
66 if (!_using_partial_mode) _Init_Part();
67 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
68 _writeCommand(0x24);
69 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
70 {
71 _writeData(value);
72 }
73}
74
75void GxEPD2_154::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
76{
77 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
78 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
79 int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
80 x -= x % 8; // byte boundary
81 w = wb * 8; // byte boundary
82 int16_t x1 = x < 0 ? 0 : x; // limit
83 int16_t y1 = y < 0 ? 0 : y; // limit
84 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
85 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
86 int16_t dx = x1 - x;
87 int16_t dy = y1 - y;
88 w1 -= dx;
89 h1 -= dy;
90 if ((w1 <= 0) || (h1 <= 0)) return;
91 if (!_using_partial_mode) _Init_Part();
92 _setPartialRamArea(x1, y1, w1, h1);
93 _writeCommand(0x24);
94 for (int16_t i = 0; i < h1; i++)
95 {
96 for (int16_t j = 0; j < w1 / 8; j++)
97 {
98 uint8_t data;
99 // use wb, h of bitmap for index!
100 int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
101 if (pgm)
102 {
103#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
104 data = pgm_read_byte(&bitmap[idx]);
105#else
106 data = bitmap[idx];
107#endif
108 }
109 else
110 {
111 data = bitmap[idx];
112 }
113 if (invert) data = ~data;
114 _writeData(data);
115 }
116 }
117 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
118}
119
120void GxEPD2_154::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
121 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
122{
123 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
124 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
125 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
126 if ((x_part < 0) || (x_part >= w_bitmap)) return;
127 if ((y_part < 0) || (y_part >= h_bitmap)) return;
128 int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
129 x_part -= x_part % 8; // byte boundary
130 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
131 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
132 x -= x % 8; // byte boundary
133 w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
134 int16_t x1 = x < 0 ? 0 : x; // limit
135 int16_t y1 = y < 0 ? 0 : y; // limit
136 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
137 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
138 int16_t dx = x1 - x;
139 int16_t dy = y1 - y;
140 w1 -= dx;
141 h1 -= dy;
142 if ((w1 <= 0) || (h1 <= 0)) return;
143 if (!_using_partial_mode) _Init_Part();
144 _setPartialRamArea(x1, y1, w1, h1);
145 _writeCommand(0x24);
146 for (int16_t i = 0; i < h1; i++)
147 {
148 for (int16_t j = 0; j < w1 / 8; j++)
149 {
150 uint8_t data;
151 // use wb_bitmap, h_bitmap of bitmap for index!
152 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;
153 if (pgm)
154 {
155#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
156 data = pgm_read_byte(&bitmap[idx]);
157#else
158 data = bitmap[idx];
159#endif
160 }
161 else
162 {
163 data = bitmap[idx];
164 }
165 if (invert) data = ~data;
166 _writeData(data);
167 }
168 }
169 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
170}
171
172void GxEPD2_154::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)
173{
174 if (black)
175 {
176 writeImage(black, x, y, w, h, invert, mirror_y, pgm);
177 }
178}
179
180void GxEPD2_154::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,
181 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
182{
183 if (black)
184 {
185 writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
186 }
187}
188
189void GxEPD2_154::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)
190{
191 if (data1)
192 {
193 writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
194 }
195}
196
197void GxEPD2_154::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 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
202}
203
204void GxEPD2_154::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
205 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
206{
207 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
208 refresh(x, y, w, h);
209 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
210}
211
212void GxEPD2_154::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)
213{
214 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
215 refresh(x, y, w, h);
216 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
217}
218
219void GxEPD2_154::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,
220 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
221{
222 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
223 refresh(x, y, w, h);
224 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
225}
226
227void GxEPD2_154::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)
228{
229 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
230 refresh(x, y, w, h);
231 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
232}
233
234void GxEPD2_154::refresh(bool partial_update_mode)
235{
236 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
237 else
238 {
239 if (_using_partial_mode) _Init_Full();
240 _Update_Full();
241 _initial_refresh = false; // initial full update done
242 }
243}
244
245void GxEPD2_154::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
246{
247 if (_initial_refresh) return refresh(false); // initial update needs be full update
248 // intersection with screen
249 int16_t w1 = x < 0 ? w + x : w; // reduce
250 int16_t h1 = y < 0 ? h + y : h; // reduce
251 int16_t x1 = x < 0 ? 0 : x; // limit
252 int16_t y1 = y < 0 ? 0 : y; // limit
253 w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
254 h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
255 if ((w1 <= 0) || (h1 <= 0)) return;
256 // make x1, w1 multiple of 8
257 w1 += x1 % 8;
258 if (w1 % 8 > 0) w1 += 8 - w1 % 8;
259 x1 -= x1 % 8;
260 if (!_using_partial_mode) _Init_Part();
261 _setPartialRamArea(x1, y1, w1, h1);
262 _Update_Part();
263}
264
266{
267 _PowerOff();
268}
269
271{
272 _PowerOff();
273 if (_rst >= 0)
274 {
275 _writeCommand(0x10); // deep sleep mode
276 _writeData(0x1); // enter deep sleep
277 _hibernating = true;
278 }
279}
280
281void GxEPD2_154::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
282{
283 _writeCommand(0x11); // set ram entry mode
284 _writeData(0x03); // x increase, y increase : normal mode
285 _writeCommand(0x44);
286 _writeData(x / 8);
287 _writeData((x + w - 1) / 8);
288 _writeCommand(0x45);
289 _writeData(y % 256);
290 _writeData(y / 256);
291 _writeData((y + h - 1) % 256);
292 _writeData((y + h - 1) / 256);
293 _writeCommand(0x4e);
294 _writeData(x / 8);
295 _writeCommand(0x4f);
296 _writeData(y % 256);
297 _writeData(y / 256);
298}
299
300void GxEPD2_154::_PowerOn()
301{
302 if (!_power_is_on)
303 {
304 _writeCommand(0x22);
305 _writeData(0xc0);
306 _writeCommand(0x20);
307 _waitWhileBusy("_PowerOn", power_on_time);
308 }
309 _power_is_on = true;
310}
311
312void GxEPD2_154::_PowerOff()
313{
314 _writeCommand(0x22);
315 _writeData(0xc3);
316 _writeCommand(0x20);
317 _waitWhileBusy("_PowerOff", power_off_time);
318 _power_is_on = false;
319 _using_partial_mode = false;
320}
321
322void GxEPD2_154::_InitDisplay()
323{
324 if (_hibernating) _reset();
325 _writeCommand(0x01); // Panel configuration, Gate selection
326 _writeData((HEIGHT - 1) % 256);
327 _writeData((HEIGHT - 1) / 256);
328 _writeData(0x00);
329 _writeCommand(0x0c); // softstart
330 _writeData(0xd7);
331 _writeData(0xd6);
332 _writeData(0x9d);
333 _writeCommand(0x2c); // VCOM setting
334 _writeData(0x9b);
335 _writeCommand(0x3a); // DummyLine
336 _writeData(0x1a); // 4 dummy line per gate
337 _writeCommand(0x3b); // Gatetime
338 _writeData(0x08); // 2us per line
339 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
340}
341
342const uint8_t GxEPD2_154::LUTDefault_full[] PROGMEM =
343{
344 0x32, // command
345 0x50, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
346 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
347};
348
349const uint8_t GxEPD2_154::LUTDefault_part[] PROGMEM =
350{
351 0x32, // command
352 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
353 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
354};
355
356void GxEPD2_154::_Init_Full()
357{
358 _InitDisplay();
359 _writeCommandDataPGM(LUTDefault_full, sizeof(LUTDefault_full));
360 _PowerOn();
361 _using_partial_mode = false;
362}
363
364void GxEPD2_154::_Init_Part()
365{
366 _InitDisplay();
367 _writeCommandDataPGM(LUTDefault_part, sizeof(LUTDefault_part));
368 _PowerOn();
369 _using_partial_mode = true;
370}
371
372void GxEPD2_154::_Update_Full()
373{
374 _writeCommand(0x22);
375 _writeData(0xc4);
376 _writeCommand(0x20);
377 _waitWhileBusy("_Update_Full", full_refresh_time);
378 _writeCommand(0xff);
379}
380
381void GxEPD2_154::_Update_Part()
382{
383 _writeCommand(0x22);
384 _writeData(0x04);
385 _writeCommand(0x20);
386 _waitWhileBusy("_Update_Part", partial_refresh_time);
387 _writeCommand(0xff);
388}
const uint8_t GxEPD2_154::LUTDefault_full[] PROGMEM
static const uint16_t power_on_time
Definition GxEPD2_154.h:28
void clearScreen(uint8_t value=0xFF)
static const uint16_t power_off_time
Definition GxEPD2_154.h:29
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 hibernate()
void refresh(bool partial_update_mode=false)
GxEPD2_154(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
static const uint16_t WIDTH
Definition GxEPD2_154.h:22
static const uint16_t full_refresh_time
Definition GxEPD2_154.h:30
static const uint16_t HEIGHT
Definition GxEPD2_154.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 powerOff()
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 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 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 partial_refresh_time
Definition GxEPD2_154.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 writeScreenBuffer(uint8_t value=0xFF)
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
bool _initial_refresh
Definition GxEPD2_EPD.h:117
void _writeCommandDataPGM(const uint8_t *pCommandData, uint8_t datalen)
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