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