Paperd.Ink Library 0.0.5
Library for interacting with Paperd.Ink devices.
Loading...
Searching...
No Matches
GxEPD2_266c.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: https://www.good-display.com/comp/xcompanyFile/downloadNew.do?appId=24&fid=1047&id=845
5// Panel: GDEY0266Z90 : https://www.good-display.com/product/430.html
6// Controller: SSD1680 : https://v4.cecdn.yun300.cn/100001_1909185148/SSD1680.pdf
7//
8// Author: Jean-Marc Zingg
9//
10// Version: see library.properties
11//
12// Library: https://github.com/ZinggJM/GxEPD2
13
14#include "GxEPD2_266c.h"
15
16GxEPD2_266c::GxEPD2_266c(int16_t cs, int16_t dc, int16_t rst, int16_t busy) :
17 GxEPD2_EPD(cs, dc, rst, busy, HIGH, 30000000, WIDTH, HEIGHT, panel, hasColor, hasPartialUpdate, hasFastPartialUpdate)
18{
19}
20
21void GxEPD2_266c::clearScreen(uint8_t value)
22{
23 clearScreen(value, 0xFF);
24}
25
26void GxEPD2_266c::clearScreen(uint8_t black_value, uint8_t color_value)
27{
28 _initial_write = false; // initial full screen buffer clean done
29 _Init_Part();
30 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
31 _writeCommand(0x24);
32 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
33 {
34 _writeData(black_value);
35 }
36 _writeCommand(0x26);
37 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
38 {
39 _writeData(~color_value);
40 }
41 _Update_Part();
42}
43
45{
46 writeScreenBuffer(value, 0xFF);
47}
48
49void GxEPD2_266c::writeScreenBuffer(uint8_t black_value, uint8_t color_value)
50{
51 _initial_write = false; // initial full screen buffer clean done
52 _Init_Part();
53 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
54 _writeCommand(0x24);
55 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
56 {
57 _writeData(black_value);
58 }
59 _writeCommand(0x26);
60 for (uint32_t i = 0; i < uint32_t(WIDTH) * uint32_t(HEIGHT) / 8; i++)
61 {
62 _writeData(~color_value);
63 }
64}
65
66void GxEPD2_266c::writeImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
67{
68 writeImage(bitmap, NULL, x, y, w, h, invert, mirror_y, pgm);
69}
70
71void GxEPD2_266c::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)
72{
73 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
74 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
75 int16_t wb = (w + 7) / 8; // width bytes, bitmaps are padded
76 x -= x % 8; // byte boundary
77 w = wb * 8; // byte boundary
78 int16_t x1 = x < 0 ? 0 : x; // limit
79 int16_t y1 = y < 0 ? 0 : y; // limit
80 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
81 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
82 int16_t dx = x1 - x;
83 int16_t dy = y1 - y;
84 w1 -= dx;
85 h1 -= dy;
86 if ((w1 <= 0) || (h1 <= 0)) return;
87 _Init_Part();
88 _setPartialRamArea(x1, y1, w1, h1);
89 _writeCommand(0x24);
90 for (int16_t i = 0; i < h1; i++)
91 {
92 for (int16_t j = 0; j < w1 / 8; j++)
93 {
94 uint8_t data = 0xFF;
95 if (black)
96 {
97 // use wb, h of bitmap for index!
98 int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
99 if (pgm)
100 {
101#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
102 data = pgm_read_byte(&black[idx]);
103#else
104 data = black[idx];
105#endif
106 }
107 else
108 {
109 data = black[idx];
110 }
111 if (invert) data = ~data;
112 }
113 _writeData(data);
114 }
115 }
116 _writeCommand(0x26);
117 for (int16_t i = 0; i < h1; i++)
118 {
119 for (int16_t j = 0; j < w1 / 8; j++)
120 {
121 uint8_t data = 0xFF;
122 if (color)
123 {
124 // use wb, h of bitmap for index!
125 int16_t idx = mirror_y ? j + dx / 8 + ((h - 1 - (i + dy))) * wb : j + dx / 8 + (i + dy) * wb;
126 if (pgm)
127 {
128#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
129 data = pgm_read_byte(&color[idx]);
130#else
131 data = color[idx];
132#endif
133 }
134 else
135 {
136 data = color[idx];
137 }
138 if (invert) data = ~data;
139 }
140 _writeData(~data);
141 }
142 }
143 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
144}
145
146void GxEPD2_266c::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 writeImagePart(bitmap, NULL, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
150}
151
152void GxEPD2_266c::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,
153 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
154{
155 if (_initial_write) writeScreenBuffer(); // initial full screen buffer clean
156 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
157 if ((w_bitmap < 0) || (h_bitmap < 0) || (w < 0) || (h < 0)) return;
158 if ((x_part < 0) || (x_part >= w_bitmap)) return;
159 if ((y_part < 0) || (y_part >= h_bitmap)) return;
160 int16_t wb_bitmap = (w_bitmap + 7) / 8; // width bytes, bitmaps are padded
161 x_part -= x_part % 8; // byte boundary
162 w = w_bitmap - x_part < w ? w_bitmap - x_part : w; // limit
163 h = h_bitmap - y_part < h ? h_bitmap - y_part : h; // limit
164 x -= x % 8; // byte boundary
165 w = 8 * ((w + 7) / 8); // byte boundary, bitmaps are padded
166 int16_t x1 = x < 0 ? 0 : x; // limit
167 int16_t y1 = y < 0 ? 0 : y; // limit
168 int16_t w1 = x + w < int16_t(WIDTH) ? w : int16_t(WIDTH) - x; // limit
169 int16_t h1 = y + h < int16_t(HEIGHT) ? h : int16_t(HEIGHT) - y; // limit
170 int16_t dx = x1 - x;
171 int16_t dy = y1 - y;
172 w1 -= dx;
173 h1 -= dy;
174 if ((w1 <= 0) || (h1 <= 0)) return;
175 if (!_using_partial_mode) _Init_Part();
176 _setPartialRamArea(x1, y1, w1, h1);
177 _writeCommand(0x24);
178 for (int16_t i = 0; i < h1; i++)
179 {
180 for (int16_t j = 0; j < w1 / 8; j++)
181 {
182 uint8_t data;
183 // use wb_bitmap, h_bitmap of bitmap for index!
184 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;
185 if (pgm)
186 {
187#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
188 data = pgm_read_byte(&black[idx]);
189#else
190 data = black[idx];
191#endif
192 }
193 else
194 {
195 data = black[idx];
196 }
197 if (invert) data = ~data;
198 _writeData(data);
199 }
200 }
201 _writeCommand(0x26);
202 for (int16_t i = 0; i < h1; i++)
203 {
204 for (int16_t j = 0; j < w1 / 8; j++)
205 {
206 uint8_t data = 0xFF;
207 if (color)
208 {
209 // use wb_bitmap, h_bitmap of bitmap for index!
210 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;
211 if (pgm)
212 {
213#if defined(__AVR) || defined(ESP8266) || defined(ESP32)
214 data = pgm_read_byte(&color[idx]);
215#else
216 data = color[idx];
217#endif
218 }
219 else
220 {
221 data = color[idx];
222 }
223 if (invert) data = ~data;
224 }
225 _writeData(~data);
226 }
227 }
228 delay(1); // yield() to avoid WDT on ESP8266 and ESP32
229}
230
231void GxEPD2_266c::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)
232{
233 if (data1)
234 {
235 writeImage(data1, x, y, w, h, invert, mirror_y, pgm);
236 }
237}
238
239void GxEPD2_266c::drawImage(const uint8_t bitmap[], int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
240{
241 writeImage(bitmap, x, y, w, h, invert, mirror_y, pgm);
242 refresh(x, y, w, h);
243}
244
245void GxEPD2_266c::drawImagePart(const uint8_t bitmap[], int16_t x_part, int16_t y_part, int16_t w_bitmap, int16_t h_bitmap,
246 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
247{
248 writeImagePart(bitmap, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
249 refresh(x, y, w, h);
250}
251
252void GxEPD2_266c::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)
253{
254 writeImage(black, color, x, y, w, h, invert, mirror_y, pgm);
255 refresh(x, y, w, h);
256}
257
258void GxEPD2_266c::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,
259 int16_t x, int16_t y, int16_t w, int16_t h, bool invert, bool mirror_y, bool pgm)
260{
261 writeImagePart(black, color, x_part, y_part, w_bitmap, h_bitmap, x, y, w, h, invert, mirror_y, pgm);
262 refresh(x, y, w, h);
263}
264
265void GxEPD2_266c::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)
266{
267 writeNative(data1, data2, x, y, w, h, invert, mirror_y, pgm);
268 refresh(x, y, w, h);
269}
270
271void GxEPD2_266c::refresh(bool partial_update_mode)
272{
273 if (partial_update_mode) refresh(0, 0, WIDTH, HEIGHT);
274 else _Update_Full();
275}
276
277void GxEPD2_266c::refresh(int16_t x, int16_t y, int16_t w, int16_t h)
278{
279 // intersection with screen
280 int16_t w1 = x < 0 ? w + x : w; // reduce
281 int16_t h1 = y < 0 ? h + y : h; // reduce
282 int16_t x1 = x < 0 ? 0 : x; // limit
283 int16_t y1 = y < 0 ? 0 : y; // limit
284 w1 = x1 + w1 < int16_t(WIDTH) ? w1 : int16_t(WIDTH) - x1; // limit
285 h1 = y1 + h1 < int16_t(HEIGHT) ? h1 : int16_t(HEIGHT) - y1; // limit
286 if ((w1 <= 0) || (h1 <= 0)) return;
287 // make x1, w1 multiple of 8
288 w1 += x1 % 8;
289 if (w1 % 8 > 0) w1 += 8 - w1 % 8;
290 x1 -= x1 % 8;
291 _Init_Part();
292 _setPartialRamArea(x1, y1, w1, h1);
293 _Update_Part();
294}
295
297{
298 _PowerOff();
299}
300
302{
303 _PowerOff();
304 if (_rst >= 0)
305 {
306 _writeCommand(0x10); // deep sleep mode
307 _writeData(0x1); // enter deep sleep
308 _hibernating = true;
309 }
310}
311
312void GxEPD2_266c::_setPartialRamArea(uint16_t x, uint16_t y, uint16_t w, uint16_t h)
313{
314 _writeCommand(0x44);
315 _writeData(x / 8);
316 _writeData((x + w - 1) / 8);
317 _writeCommand(0x45);
318 _writeData(y % 256);
319 _writeData(y / 256);
320 _writeData((y + h - 1) % 256);
321 _writeData((y + h - 1) / 256);
322 _writeCommand(0x4e);
323 _writeData(x / 8);
324 _writeCommand(0x4f);
325 _writeData(y % 256);
326 _writeData(y / 256);
327}
328
329void GxEPD2_266c::_PowerOn()
330{
331 if (!_power_is_on)
332 {
333 _writeCommand(0x22);
334 _writeData(0xf8);
335 _writeCommand(0x20);
336 _waitWhileBusy("_PowerOn", power_on_time);
337 }
338 _power_is_on = true;
339}
340
341void GxEPD2_266c::_PowerOff()
342{
343 if (_power_is_on)
344 {
345 _writeCommand(0x22);
346 _writeData(0x83);
347 _writeCommand(0x20);
348 _waitWhileBusy("_PowerOff", power_off_time);
349 }
350 _power_is_on = false;
351}
352
353void GxEPD2_266c::_InitDisplay()
354{
355 if (_hibernating) _reset();
356 delay(10); // 10ms according to specs
357 _writeCommand(0x12); //SWRESET
358 delay(10); // 10ms according to specs
359 _writeCommand(0x01); //Driver output control
360 _writeData(0x27);
361 _writeData(0x01);
362 _writeData(0x00);
363 _writeCommand(0x11); //data entry mode
364 _writeData(0x03);
365 _writeCommand(0x3C); //BorderWavefrom
366 _writeData(0x05);
367 _writeCommand(0x18); //Read built-in temperature sensor
368 _writeData(0x80);
369 _writeCommand(0x21); // Display update control
370 _writeData(0x00);
371 _writeData(0x80);
372 _setPartialRamArea(0, 0, WIDTH, HEIGHT);
373}
374
375void GxEPD2_266c::_Init_Full()
376{
377 _InitDisplay();
378 _PowerOn();
379}
380
381void GxEPD2_266c::_Init_Part()
382{
383 _InitDisplay();
384 _PowerOn();
385}
386
387void GxEPD2_266c::_Update_Full()
388{
389 _writeCommand(0x22);
390 _writeData(0xf7);
391 _writeCommand(0x20);
392 _waitWhileBusy("_Update_Full", full_refresh_time);
393}
394
395void GxEPD2_266c::_Update_Part()
396{
397 _writeCommand(0x22);
398 _writeData(0xf7);
399 _writeCommand(0x20);
400 _waitWhileBusy("_Update_Part", partial_refresh_time);
401}
void clearScreen(uint8_t value=0xFF)
static const uint16_t partial_refresh_time
Definition GxEPD2_266c.h:33
static const uint16_t power_on_time
Definition GxEPD2_266c.h:30
static const uint16_t HEIGHT
Definition GxEPD2_266c.h:25
void writeScreenBuffer(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 WIDTH
Definition GxEPD2_266c.h:23
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)
GxEPD2_266c(int16_t cs, int16_t dc, int16_t rst, int16_t busy)
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 full_refresh_time
Definition GxEPD2_266c.h:32
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 power_off_time
Definition GxEPD2_266c.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)
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 _reset()
bool _initial_write
Definition GxEPD2_EPD.h:117
int16_t _rst
Definition GxEPD2_EPD.h:112
bool _hibernating
Definition GxEPD2_EPD.h:118