Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_213_B73.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: http://www.e-paper-display.com/download_detail/downloadsId=810.html
5// Panel: GDEH0213B73 : http://www.e-paper-display.com/products_detail/productId=458.html
6// Controller: SSD1675B : http://www.e-paper-display.com/download_detail/downloadsId=820.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_213_B73.h"
15
16GxEPD2_213_B73::GxEPD2_213_B73(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
17 GxEPD2_EPD(cs, dc, rst, busy, HIGH, 10000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
18{
19}
20
21void GxEPD2_213_B73::clearScreen(uint8_t value)
22{
23 writeScreenBuffer(value);
24 refresh(true);
26}
27
29{
30 _initial_write = false; // initial full screen buffer clean done
31 if (!_using_partial_mode) _Init_Part();
32 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
33 _writeCommand(0x24);
34 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
35 {
36 _writeData(value);
37 }
38 if (_initial_refresh) writeScreenBufferAgain(value); // init "old data"
39}
40
42{
43 if (!_using_partial_mode) _Init_Part();
44 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
45 _writeCommand(0x26);
46 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
47 {
48 _writeData(value);
49 }
50}
51
52void GxEPD2_213_B73::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
53{
54 _writeImage(0x24, bitmap, x, y, w, h, invert, mirror_y, pgm);
55}
56
57void GxEPD2_213_B73::writeImageAgain(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
58{
59 _writeImage(0x26, bitmap, x, y, w, h, invert, mirror_y, pgm);
60}
61
62void GxEPD2_213_B73::_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)
63{
64 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
65 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
66 int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
67 x -= x % 8; // byte boundary
68 w = wb * 8; // byte boundary
69 int16_t x1 = x < 0 ? 0 : x; // limit
70 int16_t y1 = y < 0 ? 0 : y; // limit
71 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
72 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
73 int16_t dx = x1 - x;
74 int16_t dy = y1 - y;
75 w1 -= dx;
76 h1 -= dy;
77 if ((w1 <= 0) || (h1 <= 0)) return;
78 if (!_using_partial_mode) _Init_Part();
79 _setPartialRamArea(x1, y1, w1, h1);
80 _writeCommand(command);
81 for (int16_t i = 0; i < h1; i++)
82 {
83 for (int16_t j = 0; j < w1 / 8; j++)
84 {
85 uint8_t data;
86 // use wb, h of bitmap for index!
87 int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
88 if (pgm)
89 {
90#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
91 data = pgm_read_byte(&bitmap[idx]);
92#else
93 data = bitmap[idx];
94#endif
95 }
96 else
97 {
98 data = bitmap[idx];
99 }
100 if (invert) data = ~data;
101 _writeData(data);
102 }
103 }
104 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
105}
106
107void GxEPD2_213_B73::writeImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
108 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
109{
110 _writeImagePart(0x24, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
111}
112
113void GxEPD2_213_B73::writeImagePartAgain(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
114 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
115{
116 _writeImagePart(0x26, bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
117}
118
119void GxEPD2_213_B73::_writeImagePart(uint8_t command, const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
120 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
121{
122 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
123 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
124 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
125 if ((x_part < 0) || (x_part >= w_bitmap)) return;
126 if ((y_part < 0) || (y_part >= h_bitmap)) return;
127 int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
128 x_part -= x_part % 8; // byte boundary
129 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
130 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
131 x -= x % 8; // byte boundary
132 w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
133 int16_t x1 = x < 0 ? 0 : x; // limit
134 int16_t y1 = y < 0 ? 0 : y; // limit
135 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
136 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
137 int16_t dx = x1 - x;
138 int16_t dy = y1 - y;
139 w1 -= dx;
140 h1 -= dy;
141 if ((w1 <= 0) || (h1 <= 0)) return;
142 if (!_using_partial_mode) _Init_Part();
143 _setPartialRamArea(x1, y1, w1, h1);
144 _writeCommand(command);
145 for (int16_t i = 0; i < h1; i++)
146 {
147 for (int16_t j = 0; j < w1 / 8; j++)
148 {
149 uint8_t data;
150 // use wb_bitmap, h_bitmap of bitmap for index!
151 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;
152 if (pgm)
153 {
154#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
155 data = pgm_read_byte(&bitmap[idx]);
156#else
157 data = bitmap[idx];
158#endif
159 }
160 else
161 {
162 data = bitmap[idx];
163 }
164 if (invert) data = ~data;
165 _writeData(data);
166 }
167 }
168 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
169}
170
171void GxEPD2_213_B73::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)
172{
173 if (black)
174 {
175 writeImage(black, x, y, w, h, invert, mirror_y, pgm);
176 }
177}
178
179void GxEPD2_213_B73::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,
180 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
181{
182 if (black)
183 {
184 writeImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
185 }
186}
187
188void GxEPD2_213_B73::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)
189{
190 if (data1)
191 {
192 writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
193 }
194}
195
196void GxEPD2_213_B73::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
197{
198 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
199 refresh(x, y, w, h);
200 writeImageAgain(bitmap, x, y, w, h, invert, mirror_y, pgm);
201}
202
203void GxEPD2_213_B73::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 writeImagePartAgain(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
209}
210
211void GxEPD2_213_B73::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)
212{
213 if (black)
214 {
215 drawImage(black, x, y, w, h, invert, mirror_y, pgm);
216 }
217}
218
219void GxEPD2_213_B73::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 if (black)
223 {
224 drawImagePart(black, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
225 }
226}
227
228void GxEPD2_213_B73::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)
229{
230 if (data1)
231 {
232 drawImage(data1, x, y, w, h, invert, mirror_y, pgm);
233 }
234}
235
236void GxEPD2_213_B73::refresh(bool partial_update_mode)
237{
238 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
239 else
240 {
241 if (_using_partial_mode) _Init_Full();
242 _Update_Full();
243 _initial_refresh = false; // initial full update done
244 }
245}
246
247void GxEPD2_213_B73::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
248{
249 if (_initial_refresh) return refresh(false); // initial update needs be full update
250 // intersection with screen
251 int16_t w1 = x < 0 ? w + x : w; // reduce
252 int16_t h1 = y < 0 ? h + y : h; // reduce
253 int16_t x1 = x < 0 ? 0 : x; // limit
254 int16_t y1 = y < 0 ? 0 : y; // limit
255 w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
256 h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
257 if ((w1 <= 0) || (h1 <= 0)) return;
258 // make x1, w1 multiple of 8
259 w1 += x1 % 8;
260 if (w1 % 8 > 0) w1 += 8 - w1 % 8;
261 x1 -= x1 % 8;
262 if (!_using_partial_mode) _Init_Part();
263 _setPartialRamArea(x1, y1, w1, h1);
264 _Update_Part();
265}
266
268{
269 _PowerOff();
270}
271
273{
274 _PowerOff();
275 if (_rst >= 0)
276 {
277 _writeCommand(0x10); // deep sleep mode
278 _writeData(0x1); // enter deep sleep
279 _hibernating = true;
280 }
281}
282
283void GxEPD2_213_B73::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
284{
285 _writeCommand(0x11); // set ram entry mode
286 _writeData(0x03); // x increase, y increase : normal mode
287 _writeCommand(0x44);
288 _writeData(x / 8);
289 _writeData((x + w - 1) / 8);
290 _writeCommand(0x45);
291 _writeData(y % 256);
292 _writeData(y / 256);
293 _writeData((y + h - 1) % 256);
294 _writeData((y + h - 1) / 256);
295 _writeCommand(0x4e);
296 _writeData(x / 8);
297 _writeCommand(0x4f);
298 _writeData(y % 256);
299 _writeData(y / 256);
300}
301
302void GxEPD2_213_B73::_PowerOn()
303{
304 if (!_power_is_on)
305 {
306 _writeCommand(0x22);
307 _writeData(0xc0);
308 _writeCommand(0x20);
309 _waitWhileBusy("_PowerOn", power_on_time);
310 }
311 _power_is_on = true;
312}
313
314void GxEPD2_213_B73::_PowerOff()
315{
316 _writeCommand(0x22);
317 _writeData(0xc3);
318 _writeCommand(0x20);
319 _waitWhileBusy("_PowerOff", power_off_time);
320 _power_is_on = false;
321 _using_partial_mode = false;
322}
323
324void GxEPD2_213_B73::_InitDisplay()
325{
326 if (_hibernating) _reset();
327 _writeCommand(0x74); //set analog block control
328 _writeData(0x54);
329 _writeCommand(0x7E); //set digital block control
330 _writeData(0x3B);
331 _writeCommand(0x01); //Driver output control
332 _writeData(0xF9);
333 _writeData(0x00);
334 _writeData(0x00);
335 _writeCommand(0x3C); //BorderWavefrom
336 _writeData(0x03);
337 _writeCommand(0x2C); //VCOM Voltage
338 _writeData(0x50); //
339 _writeCommand(0x03); //Gate Driving voltage Control
340 _writeData(0x15); // 19V
341 _writeCommand(0x04); //Source Driving voltage Control
342 _writeData(0x41); // VSH1 15V
343 _writeData(0xA8); // VSH2 5V
344 _writeData(0x32); // VSL -15V
345 _writeCommand(0x3A); //Dummy Line
346 _writeData(0x2C);
347 _writeCommand(0x3B); //Gate time
348 _writeData(0x0B);
349 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
350}
351
352const uint8_t GxEPD2_213_B73::LUT_DATA_full[] PROGMEM =
353{
354 0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
355 0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
359
360 0x0F, 0x0F, 0x00, 0x00, 0x00,
361 0x0F, 0x0F, 0x00, 0x00, 0x03,
362 0x0F, 0x0F, 0x00, 0x00, 0x00,
363 0x00, 0x00, 0x00, 0x00, 0x00,
364 0x00, 0x00, 0x00, 0x00, 0x00,
365 0x00, 0x00, 0x00, 0x00, 0x00,
366 0x00, 0x00, 0x00, 0x00, 0x00,
367 0x00, 0x00, 0x00, 0x00, 0x00,
368 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x00,
370
371 //0x15, 0x41, 0xA8, 0x32, 0x50, 0x2C, 0x0B,
372};
373
374const uint8_t GxEPD2_213_B73::LUT_DATA_part[] PROGMEM =
375{
376 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
377 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
378 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
380 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381
382 0x0A, 0x00, 0x00, 0x00, 0x00,
383 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x00, 0x00,
386 0x00, 0x00, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x00,
388 0x00, 0x00, 0x00, 0x00, 0x00,
389 0x00, 0x00, 0x00, 0x00, 0x00,
390 0x00, 0x00, 0x00, 0x00, 0x00,
391 0x00, 0x00, 0x00, 0x00, 0x00,
392
393 //0x15, 0x41, 0xA8, 0x32, 0x50, 0x2C, 0x0B,
394};
395
396void GxEPD2_213_B73::_Init_Full()
397{
398 _InitDisplay();
399 _writeCommand(0x32);
400 _writeDataPGM(LUT_DATA_full, sizeof(LUT_DATA_full));
401 _PowerOn();
402 _using_partial_mode = false;
403}
404
405void GxEPD2_213_B73::_Init_Part()
406{
407 _InitDisplay();
408 _writeCommand(0x2C); //VCOM Voltage
409 _writeData(0x26); // NA ??
410 _writeCommand(0x32);
411 _writeDataPGM(LUT_DATA_part, sizeof(LUT_DATA_part));
412 _PowerOn();
413 _using_partial_mode = true;
414}
415
416void GxEPD2_213_B73::_Update_Full()
417{
418 _writeCommand(0x22);
419 _writeData(0xc7);
420 _writeCommand(0x20);
421 _waitWhileBusy("_Update_Full", full_refresh_time);
422}
423
424void GxEPD2_213_B73::_Update_Part()
425{
426 _writeCommand(0x22);
427 _writeData(0xc4);
428 _writeCommand(0x20);
429 _waitWhileBusy("_Update_Part", partial_refresh_time);
430}
const uint8_t GxEPD2_213_B73::LUT_DATA_full[] PROGMEM
static const uint16_t HEIGHT
static const uint16_t full_refresh_time
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 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)
void refresh(bool partial_update_mode=false)
void writeScreenBuffer(uint8_t value=0xFF)
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 clearScreen(uint8_t value=0xFF)
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)
static const uint16_t partial_refresh_time
void writeScreenBufferAgain(uint8_t value=0xFF)
static const uint16_t power_on_time
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_213_B73(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
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 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 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)
static const uint16_t power_off_time
static const uint16_t WIDTH
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 _reset()
bool _initial_write
Definition GxEPD2_EPD.h:117
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)