ESPHome 2025.5.0
Loading...
Searching...
No Matches
waveshare_epaper.cpp
Go to the documentation of this file.
1#include "waveshare_epaper.h"
2#include "esphome/core/log.h"
5#include <cinttypes>
6#include <bitset>
7
8namespace esphome {
9namespace waveshare_epaper {
10
11static const char *const TAG = "waveshare_epaper";
12
13static const uint8_t LUT_SIZE_WAVESHARE = 30;
14
15static const uint8_t FULL_UPDATE_LUT[LUT_SIZE_WAVESHARE] = {0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22, 0x66, 0x69,
16 0x69, 0x59, 0x58, 0x99, 0x99, 0x88, 0x00, 0x00, 0x00, 0x00,
17 0xF8, 0xB4, 0x13, 0x51, 0x35, 0x51, 0x51, 0x19, 0x01, 0x00};
18
19static const uint8_t PARTIAL_UPDATE_LUT[LUT_SIZE_WAVESHARE] = {
20 0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
21 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
22
23static const uint8_t LUT_SIZE_TTGO = 70;
24
25static const uint8_t FULL_UPDATE_LUT_TTGO[LUT_SIZE_TTGO] = {
26 0x80, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, // LUT0: BB: VS 0 ~7
27 0x10, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, // LUT1: BW: VS 0 ~7
28 0x80, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, // LUT2: WB: VS 0 ~7
29 0x10, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, // LUT3: WW: VS 0 ~7
30 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT4: VCOM: VS 0 ~7
31 0x03, 0x03, 0x00, 0x00, 0x02, // TP0 A~D RP0
32 0x09, 0x09, 0x00, 0x00, 0x02, // TP1 A~D RP1
33 0x03, 0x03, 0x00, 0x00, 0x02, // TP2 A~D RP2
34 0x00, 0x00, 0x00, 0x00, 0x00, // TP3 A~D RP3
35 0x00, 0x00, 0x00, 0x00, 0x00, // TP4 A~D RP4
36 0x00, 0x00, 0x00, 0x00, 0x00, // TP5 A~D RP5
37 0x00, 0x00, 0x00, 0x00, 0x00, // TP6 A~D RP6
38};
39
40static const uint8_t PARTIAL_UPDATE_LUT_TTGO[LUT_SIZE_TTGO] = {
41 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT0: BB: VS 0 ~7
42 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT1: BW: VS 0 ~7
43 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT2: WB: VS 0 ~7
44 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT3: WW: VS 0 ~7
45 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT4: VCOM: VS 0 ~7
46 0x0A, 0x00, 0x00, 0x00, 0x00, // TP0 A~D RP0
47 0x00, 0x00, 0x00, 0x00, 0x00, // TP1 A~D RP1
48 0x00, 0x00, 0x00, 0x00, 0x00, // TP2 A~D RP2
49 0x00, 0x00, 0x00, 0x00, 0x00, // TP3 A~D RP3
50 0x00, 0x00, 0x00, 0x00, 0x00, // TP4 A~D RP4
51 0x00, 0x00, 0x00, 0x00, 0x00, // TP5 A~D RP5
52 0x00, 0x00, 0x00, 0x00, 0x00, // TP6 A~D RP6
53};
54
55static const uint8_t LUT_SIZE_TTGO_B73 = 100;
56
57static const uint8_t FULL_UPDATE_LUT_TTGO_B73[LUT_SIZE_TTGO_B73] = {
58 0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00,
59 0x00, 0x00, 0x00, 0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0xA0, 0x00,
60 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61
62 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
63 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65};
66
67static const uint8_t PARTIAL_UPDATE_LUT_TTGO_B73[LUT_SIZE_TTGO_B73] = {
68 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
69 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
70 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71
72 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
73 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75};
76
77static const uint8_t LUT_SIZE_TTGO_B1 = 29;
78
79static const uint8_t FULL_UPDATE_LUT_TTGO_B1[LUT_SIZE_TTGO_B1] = {
80 0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81 0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x01, 0x00, 0x00, 0x00, 0x00};
82
83static const uint8_t PARTIAL_UPDATE_LUT_TTGO_B1[LUT_SIZE_TTGO_B1] = {
84 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
85 0x00, 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
86
87// clang-format off
88// Disable formatting to preserve the same look as in Waveshare examples
89static const uint8_t PARTIAL_UPD_2IN9_LUT_SIZE = 159;
90static const uint8_t PARTIAL_UPD_2IN9_LUT[PARTIAL_UPD_2IN9_LUT_SIZE] =
91{
92 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
98 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00,
110 0x22, 0x17, 0x41, 0xB0, 0x32, 0x36,
111};
112// clang-format on
113
115 this->init_internal_(this->get_buffer_length_());
116 this->setup_pins_();
117 this->spi_setup();
118 this->reset_();
119 this->initialize();
120}
122 this->dc_pin_->setup(); // OUTPUT
123 this->dc_pin_->digital_write(false);
124 if (this->reset_pin_ != nullptr) {
125 this->reset_pin_->setup(); // OUTPUT
126 this->reset_pin_->digital_write(true);
127 }
128 if (this->busy_pin_ != nullptr) {
129 this->busy_pin_->setup(); // INPUT
130 }
131}
133void WaveshareEPaperBase::command(uint8_t value) {
134 this->start_command_();
135 this->write_byte(value);
136 this->end_command_();
137}
138void WaveshareEPaperBase::data(uint8_t value) {
139 this->start_data_();
140 this->write_byte(value);
141 this->end_data_();
142}
143
144// write a command followed by one or more bytes of data.
145// The command is the first byte, length is the total including cmd.
146void WaveshareEPaperBase::cmd_data(const uint8_t *c_data, size_t length) {
147 this->dc_pin_->digital_write(false);
148 this->enable();
149 this->write_byte(c_data[0]);
150 this->dc_pin_->digital_write(true);
151 this->write_array(c_data + 1, length - 1);
152 this->disable();
153}
154
156 if (this->busy_pin_ == nullptr || !this->busy_pin_->digital_read()) {
157 return true;
158 }
159
160 const uint32_t start = millis();
161 while (this->busy_pin_->digital_read()) {
162 if (millis() - start > this->idle_timeout_()) {
163 ESP_LOGE(TAG, "Timeout while displaying image!");
164 return false;
165 }
166 delay(1);
167 }
168 return true;
169}
171 this->do_update_();
172 this->display();
173}
175 // flip logic
176 const uint8_t fill = color.is_on() ? 0x00 : 0xFF;
177 for (uint32_t i = 0; i < this->get_buffer_length_(); i++)
178 this->buffer_[i] = fill;
179}
182 this->setup_pins_();
183 this->spi_setup();
184 this->reset_();
185 this->initialize();
186}
187void WaveshareEPaper7C::init_internal_7c_(uint32_t buffer_length) {
189 uint32_t small_buffer_length = buffer_length / NUM_BUFFERS;
190
191 for (int i = 0; i < NUM_BUFFERS; i++) {
192 this->buffers_[i] = allocator.allocate(small_buffer_length);
193 if (this->buffers_[i] == nullptr) {
194 ESP_LOGE(TAG, "Could not allocate buffer %d for display!", i);
195 for (auto &buffer : this->buffers_) {
196 allocator.deallocate(buffer, small_buffer_length);
197 buffer = nullptr;
198 }
199 return;
200 }
201 }
202 this->clear();
203}
205 uint8_t hex_code;
206 if (color.red > 127) {
207 if (color.green > 170) {
208 if (color.blue > 127) {
209 hex_code = 0x1; // White
210 } else {
211 hex_code = 0x5; // Yellow
212 }
213 } else if (color.green > 85) {
214 hex_code = 0x6; // Orange
215 } else {
216 hex_code = 0x4; // Red (or Magenta)
217 }
218 } else {
219 if (color.green > 127) {
220 if (color.blue > 127) {
221 hex_code = 0x3; // Cyan -> Blue
222 } else {
223 hex_code = 0x2; // Green
224 }
225 } else {
226 if (color.blue > 127) {
227 hex_code = 0x3; // Blue
228 } else {
229 hex_code = 0x0; // Black
230 }
231 }
232 }
233
234 return hex_code;
235}
237 uint8_t pixel_color;
238 if (color.is_on()) {
239 pixel_color = this->color_to_hex(color);
240 } else {
241 pixel_color = 0x1;
242 }
243
244 if (this->buffers_[0] == nullptr) {
245 ESP_LOGE(TAG, "Buffer unavailable!");
246 } else {
247 uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
248 for (auto &buffer : this->buffers_) {
249 for (uint32_t buffer_pos = 0; buffer_pos < small_buffer_length; buffer_pos += 3) {
250 // We store 8 bitset<3> in 3 bytes
251 // | byte 1 | byte 2 | byte 3 |
252 // |aaabbbaa|abbbaaab|bbaaabbb|
253 buffer[buffer_pos + 0] = pixel_color << 5 | pixel_color << 2 | pixel_color >> 1;
254 buffer[buffer_pos + 1] = pixel_color << 7 | pixel_color << 4 | pixel_color << 1 | pixel_color >> 2;
255 buffer[buffer_pos + 2] = pixel_color << 6 | pixel_color << 3 | pixel_color << 0;
256 }
257 App.feed_wdt();
258 }
259 }
260}
262 if (this->buffers_[0] == nullptr) {
263 ESP_LOGE(TAG, "Buffer unavailable!");
264 return;
265 }
266
267 uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
268 uint8_t byte_to_send;
269 for (auto &buffer : this->buffers_) {
270 for (uint32_t buffer_pos = 0; buffer_pos < small_buffer_length; buffer_pos += 3) {
271 std::bitset<24> triplet =
272 buffer[buffer_pos + 0] << 16 | buffer[buffer_pos + 1] << 8 | buffer[buffer_pos + 2] << 0;
273 // 8 bitset<3> are stored in 3 bytes
274 // |aaabbbaa|abbbaaab|bbaaabbb|
275 // | byte 1 | byte 2 | byte 3 |
276 byte_to_send = ((triplet >> 17).to_ulong() & 0b01110000) | ((triplet >> 18).to_ulong() & 0b00000111);
277 this->data(byte_to_send);
278
279 byte_to_send = ((triplet >> 11).to_ulong() & 0b01110000) | ((triplet >> 12).to_ulong() & 0b00000111);
280 this->data(byte_to_send);
281
282 byte_to_send = ((triplet >> 5).to_ulong() & 0b01110000) | ((triplet >> 6).to_ulong() & 0b00000111);
283 this->data(byte_to_send);
284
285 byte_to_send = ((triplet << 1).to_ulong() & 0b01110000) | ((triplet << 0).to_ulong() & 0b00000111);
286 this->data(byte_to_send);
287 }
288 App.feed_wdt();
289 }
290}
292 if (this->reset_pin_ != nullptr) {
293 this->reset_pin_->digital_write(true);
294 delay(20);
295 this->reset_pin_->digital_write(false);
296 delay(1);
297 this->reset_pin_->digital_write(true);
298 delay(20);
299 }
300}
301
303 if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
304 return;
305
306 const uint32_t pos = (x + y * this->get_width_controller()) / 8u;
307 const uint8_t subpos = x & 0x07;
308 // flip logic
309 if (!color.is_on()) {
310 this->buffer_[pos] |= 0x80 >> subpos;
311 } else {
312 this->buffer_[pos] &= ~(0x80 >> subpos);
313 }
314}
315
317 return this->get_width_controller() * this->get_height_internal() / 8u;
318} // just a black buffer
320 return this->get_width_controller() * this->get_height_internal() / 4u;
321} // black and red buffer
323 return this->get_width_controller() * this->get_height_internal() / 8u * 3u;
324} // 7 colors buffer, 1 pixel = 3 bits, we will store 8 pixels in 24 bits = 3 bytes
325
327 this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color);
328}
330 if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
331 return;
332
333 const uint32_t buf_half_len = this->get_buffer_length_() / 2u;
334
335 const uint32_t pos = (x + y * this->get_width_internal()) / 8u;
336 const uint8_t subpos = x & 0x07;
337 // flip logic
338 if (color.is_on()) {
339 this->buffer_[pos] |= 0x80 >> subpos;
340 } else {
341 this->buffer_[pos] &= ~(0x80 >> subpos);
342 }
343
344 // draw red pixels only, if the color contains red only
345 if (((color.red > 0) && (color.green == 0) && (color.blue == 0))) {
346 this->buffer_[pos + buf_half_len] |= 0x80 >> subpos;
347 } else {
348 this->buffer_[pos + buf_half_len] &= ~(0x80 >> subpos);
349 }
350}
352 if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
353 return;
354
355 uint8_t pixel_bits = this->color_to_hex(color);
356 uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
357 uint32_t pixel_position = x + y * this->get_width_controller();
358 uint32_t first_bit_position = pixel_position * 3;
359 uint32_t byte_position = first_bit_position / 8u;
360 uint32_t byte_subposition = first_bit_position % 8u;
361 uint32_t buffer_position = byte_position / small_buffer_length;
362 uint32_t buffer_subposition = byte_position % small_buffer_length;
363
364 if (byte_subposition <= 5) {
365 this->buffers_[buffer_position][buffer_subposition] =
366 (this->buffers_[buffer_position][buffer_subposition] & (0xFF ^ (0b111 << (5 - byte_subposition)))) |
367 (pixel_bits << (5 - byte_subposition));
368 } else {
369 this->buffers_[buffer_position][buffer_subposition + 0] =
370 (this->buffers_[buffer_position][buffer_subposition + 0] & (0xFF ^ (0b111 >> (byte_subposition - 5)))) |
371 (pixel_bits >> (byte_subposition - 5));
372
373 this->buffers_[buffer_position][buffer_subposition + 1] = (this->buffers_[buffer_position][buffer_subposition + 1] &
374 (0xFF ^ (0xFF & (0b111 << (13 - byte_subposition))))) |
375 (pixel_bits << (13 - byte_subposition));
376 }
377}
379 this->dc_pin_->digital_write(false);
380 this->enable();
381}
384 this->dc_pin_->digital_write(true);
385 this->enable();
386}
389
390// ========================================================
391// Type A
392// ========================================================
393
395 // Achieve display intialization
396 this->init_display_();
397 // If a reset pin is configured, eligible displays can be set to deep sleep
398 // between updates, as recommended by the hardware provider
399 if (this->reset_pin_ != nullptr) {
400 switch (this->model_) {
401 // More models can be added here to enable deep sleep if eligible
404 this->deep_sleep_between_updates_ = true;
405 ESP_LOGI(TAG, "Set the display to deep sleep");
406 this->deep_sleep();
407 break;
408 default:
409 break;
410 }
411 }
412}
415 if (this->reset_pin_ != nullptr) {
416 this->reset_pin_->digital_write(false);
417 delay(10);
418 this->reset_pin_->digital_write(true);
419 delay(10);
420 this->wait_until_idle_();
421 }
422
423 this->command(0x12); // SWRESET
424 this->wait_until_idle_();
425 }
426
427 // COMMAND DRIVER OUTPUT CONTROL
428 this->command(0x01);
429 this->data(this->get_height_internal() - 1);
430 this->data((this->get_height_internal() - 1) >> 8);
431 this->data(0x00); // ? GD = 0, SM = 0, TB = 0
432
433 // COMMAND BOOSTER SOFT START CONTROL
434 this->command(0x0C);
435 this->data(0xD7);
436 this->data(0xD6);
437 this->data(0x9D);
438
439 // COMMAND WRITE VCOM REGISTER
440 this->command(0x2C);
441 this->data(0xA8);
442
443 // COMMAND SET DUMMY LINE PERIOD
444 this->command(0x3A);
445 this->data(0x1A);
446
447 // COMMAND SET GATE TIME
448 this->command(0x3B);
449 this->data(0x08); // 2µs per row
450
451 // COMMAND DATA ENTRY MODE SETTING
452 this->command(0x11);
453 switch (this->model_) {
455 this->data(0x01); // x increase, y decrease : as in demo code
456 break;
459 this->data(0x03); // from top left to bottom right
460 // RAM content option for Display Update
461 this->command(0x21);
462 this->data(0x00);
463 this->data(0x80);
464 break;
465 default:
466 this->data(0x03); // from top left to bottom right
467 }
468}
470 LOG_DISPLAY("", "Waveshare E-Paper", this);
471 switch (this->model_) {
473 ESP_LOGCONFIG(TAG, " Model: 1.54in");
474 break;
476 ESP_LOGCONFIG(TAG, " Model: 1.54inV2");
477 break;
479 ESP_LOGCONFIG(TAG, " Model: 2.13in");
480 break;
482 ESP_LOGCONFIG(TAG, " Model: 2.13inV2");
483 break;
485 ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO)");
486 break;
488 ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO B73)");
489 break;
491 ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO B74)");
492 break;
494 ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO B1)");
495 break;
497 ESP_LOGCONFIG(TAG, " Model: 2.9in");
498 break;
500 ESP_LOGCONFIG(TAG, " Model: 2.9inV2");
501 break;
502 }
503 ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
504 LOG_PIN(" Reset Pin: ", this->reset_pin_);
505 LOG_PIN(" DC Pin: ", this->dc_pin_);
506 LOG_PIN(" Busy Pin: ", this->busy_pin_);
507 LOG_UPDATE_INTERVAL(this);
508}
510 bool full_update = this->at_update_ == 0;
511 bool prev_full_update = this->at_update_ == 1;
512
513 if (this->deep_sleep_between_updates_) {
514 ESP_LOGI(TAG, "Wake up the display");
515 this->reset_();
516 this->wait_until_idle_();
517 this->init_display_();
518 }
519
520 if (!this->wait_until_idle_()) {
521 this->status_set_warning();
522 return;
523 }
524
525 if (this->full_update_every_ >= 1) {
526 if (full_update != prev_full_update) {
527 switch (this->model_) {
530 // Waveshare 2.13" V2 uses the same LUTs as TTGO
531 this->write_lut_(full_update ? FULL_UPDATE_LUT_TTGO : PARTIAL_UPDATE_LUT_TTGO, LUT_SIZE_TTGO);
532 break;
534 this->write_lut_(full_update ? FULL_UPDATE_LUT_TTGO_B73 : PARTIAL_UPDATE_LUT_TTGO_B73, LUT_SIZE_TTGO_B73);
535 break;
537 // there is no LUT
538 break;
540 this->write_lut_(full_update ? FULL_UPDATE_LUT_TTGO_B1 : PARTIAL_UPDATE_LUT_TTGO_B1, LUT_SIZE_TTGO_B1);
541 break;
542 default:
543 this->write_lut_(full_update ? FULL_UPDATE_LUT : PARTIAL_UPDATE_LUT, LUT_SIZE_WAVESHARE);
544 }
545 }
546 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
547 }
548
549 if (this->model_ == WAVESHARE_EPAPER_2_13_IN_V2) {
550 // Set VCOM for full or partial update
551 this->command(0x2C);
552 this->data(full_update ? 0x55 : 0x26);
553
554 if (!full_update) {
555 // Enable "ping-pong"
556 this->command(0x37);
557 this->data(0x00);
558 this->data(0x00);
559 this->data(0x00);
560 this->data(0x00);
561 this->data(0x40);
562 this->data(0x00);
563 this->data(0x00);
564 this->command(0x22);
565 this->data(0xc0);
566 this->command(0x20);
567 }
568 }
569
570 // Border waveform
571 switch (this->model_) {
573 this->command(0x3C);
574 this->data(full_update ? 0x05 : 0x80);
575 break;
577 this->command(0x3C);
578 this->data(full_update ? 0x03 : 0x01);
579 break;
580 default:
581 break;
582 }
583
584 // Set x & y regions we want to write to (full)
585 switch (this->model_) {
587 // COMMAND SET RAM X ADDRESS START END POSITION
588 this->command(0x44);
589 this->data(0x00);
590 this->data((this->get_width_controller() - 1) >> 3);
591 // COMMAND SET RAM Y ADDRESS START END POSITION
592 this->command(0x45);
593 this->data(this->get_height_internal() - 1);
594 this->data((this->get_height_internal() - 1) >> 8);
595 this->data(0x00);
596 this->data(0x00);
597
598 // COMMAND SET RAM X ADDRESS COUNTER
599 this->command(0x4E);
600 this->data(0x00);
601 // COMMAND SET RAM Y ADDRESS COUNTER
602 this->command(0x4F);
603 this->data(this->get_height_internal() - 1);
604 this->data((this->get_height_internal() - 1) >> 8);
605
606 break;
607 default:
608 // COMMAND SET RAM X ADDRESS START END POSITION
609 this->command(0x44);
610 this->data(0x00);
611 this->data((this->get_width_internal() - 1) >> 3);
612 // COMMAND SET RAM Y ADDRESS START END POSITION
613 this->command(0x45);
614 this->data(0x00);
615 this->data(0x00);
616 this->data(this->get_height_internal() - 1);
617 this->data((this->get_height_internal() - 1) >> 8);
618
619 // COMMAND SET RAM X ADDRESS COUNTER
620 this->command(0x4E);
621 this->data(0x00);
622 // COMMAND SET RAM Y ADDRESS COUNTER
623 this->command(0x4F);
624 this->data(0x00);
625 this->data(0x00);
626 }
627
628 if (!this->wait_until_idle_()) {
629 this->status_set_warning();
630 return;
631 }
632
633 // COMMAND WRITE RAM
634 this->command(0x24);
635 this->start_data_();
636 switch (this->model_) {
637 case TTGO_EPAPER_2_13_IN_B1: { // block needed because of variable initializations
638 int16_t wb = ((this->get_width_controller()) >> 3);
639 for (int i = 0; i < this->get_height_internal(); i++) {
640 for (int j = 0; j < wb; j++) {
641 int idx = j + (this->get_height_internal() - 1 - i) * wb;
642 this->write_byte(this->buffer_[idx]);
643 }
644 }
645 break;
646 }
647 default:
648 this->write_array(this->buffer_, this->get_buffer_length_());
649 }
650 this->end_data_();
651
652 if (this->model_ == WAVESHARE_EPAPER_2_13_IN_V2 && full_update) {
653 // Write base image again on full refresh
654 this->command(0x26);
655 this->start_data_();
656 this->write_array(this->buffer_, this->get_buffer_length_());
657 this->end_data_();
658 }
659
660 // COMMAND DISPLAY UPDATE CONTROL 2
661 this->command(0x22);
662 switch (this->model_) {
666 this->data(full_update ? 0xF7 : 0xFF);
667 break;
669 this->data(0xC7);
670 break;
672 this->data(full_update ? 0xC7 : 0x0C);
673 break;
674 default:
675 this->data(0xC4);
676 break;
677 }
678
679 // COMMAND MASTER ACTIVATION
680 this->command(0x20);
681 // COMMAND TERMINATE FRAME READ WRITE
682 this->command(0xFF);
683
684 this->status_clear_warning();
685
686 if (this->deep_sleep_between_updates_) {
687 ESP_LOGI(TAG, "Set the display back to deep sleep");
688 this->deep_sleep();
689 }
690}
692 switch (this->model_) {
695 return 200;
702 return 122;
705 return 128;
706 }
707 return 0;
708}
709// The controller of the 2.13" displays has a buffer larger than screen size
711 switch (this->model_) {
718 return 128;
719 default:
720 return this->get_width_internal();
721 }
722}
724 switch (this->model_) {
727 return 200;
734 return 250;
737 return 296;
738 }
739 return 0;
740}
741void WaveshareEPaperTypeA::write_lut_(const uint8_t *lut, const uint8_t size) {
742 // COMMAND WRITE LUT REGISTER
743 this->command(0x32);
744 for (uint8_t i = 0; i < size; i++)
745 this->data(lut[i]);
746}
748void WaveshareEPaperTypeA::set_full_update_every(uint32_t full_update_every) {
749 this->full_update_every_ = full_update_every;
750}
751
753 switch (this->model_) {
758 return 2500;
759 default:
761 }
762}
763
764// ========================================================
765// Type B
766// ========================================================
767// Datasheet:
768// - https://www.waveshare.com/w/upload/7/7f/4.2inch-e-paper-b-specification.pdf
769// - https://github.com/soonuse/epd-library-arduino/blob/master/4.2inch_e-paper/epd4in2/
770
771static const uint8_t LUT_VCOM_DC_2_7[44] = {
772 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x00, 0x32, 0x32, 0x00, 0x00, 0x02, 0x00,
773 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
774 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775};
776
777static const uint8_t LUT_WHITE_TO_WHITE_2_7[42] = {
778 0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0xA0, 0x0F,
779 0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781};
782
783static const uint8_t LUT_BLACK_TO_WHITE_2_7[42] = {
784 0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0xA0, 0x0F,
785 0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
786 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
787};
788
789static const uint8_t LUT_WHITE_TO_BLACK_2_7[] = {
790 0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0x50, 0x0F,
791 0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
792 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
793};
794
795static const uint8_t LUT_BLACK_TO_BLACK_2_7[42] = {
796 0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0x50, 0x0F,
797 0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
798 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
799};
800
802 // command power setting
803 this->command(0x01);
804 this->data(0x03); // VDS_EN, VDG_EN
805 this->data(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
806 this->data(0x2B); // VDH
807 this->data(0x2B); // VDL
808 this->data(0x09); // VDHR
809
810 // command booster soft start
811 this->command(0x06);
812 this->data(0x07);
813 this->data(0x07);
814 this->data(0x17);
815
816 // Power optimization - ???
817 this->command(0xF8);
818 this->data(0x60);
819 this->data(0xA5);
820 this->command(0xF8);
821 this->data(0x89);
822 this->data(0xA5);
823 this->command(0xF8);
824 this->data(0x90);
825 this->data(0x00);
826 this->command(0xF8);
827 this->data(0x93);
828 this->data(0x2A);
829 this->command(0xF8);
830 this->data(0xA0);
831 this->data(0xA5);
832 this->command(0xF8);
833 this->data(0xA1);
834 this->data(0x00);
835 this->command(0xF8);
836 this->data(0x73);
837 this->data(0x41);
838
839 // command partial display refresh
840 this->command(0x16);
841 this->data(0x00);
842
843 // command power on
844 this->command(0x04);
845 this->wait_until_idle_();
846 delay(10);
847
848 // Command panel setting
849 this->command(0x00);
850 this->data(0xAF); // KW-BF KWR-AF BWROTP 0f
851 // command pll control
852 this->command(0x30);
853 this->data(0x3A); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
854 // COMMAND VCM DC SETTING
855 this->command(0x82);
856 this->data(0x12);
857
858 delay(2);
859 // COMMAND LUT FOR VCOM
860 this->command(0x20);
861 for (uint8_t i : LUT_VCOM_DC_2_7)
862 this->data(i);
863
864 // COMMAND LUT WHITE TO WHITE
865 this->command(0x21);
866 for (uint8_t i : LUT_WHITE_TO_WHITE_2_7)
867 this->data(i);
868 // COMMAND LUT BLACK TO WHITE
869 this->command(0x22);
870 for (uint8_t i : LUT_BLACK_TO_WHITE_2_7)
871 this->data(i);
872 // COMMAND LUT WHITE TO BLACK
873 this->command(0x23);
874 for (uint8_t i : LUT_WHITE_TO_BLACK_2_7)
875 this->data(i);
876 // COMMAND LUT BLACK TO BLACK
877 this->command(0x24);
878 for (uint8_t i : LUT_BLACK_TO_BLACK_2_7)
879 this->data(i);
880}
882 uint32_t buf_len = this->get_buffer_length_();
883
884 // COMMAND DATA START TRANSMISSION 1
885 this->command(0x10);
886 delay(2);
887 for (uint32_t i = 0; i < buf_len; i++) {
888 this->data(this->buffer_[i]);
889 }
890 delay(2);
891
892 // COMMAND DATA START TRANSMISSION 2
893 this->command(0x13);
894 delay(2);
895 for (uint32_t i = 0; i < buf_len; i++) {
896 this->data(this->buffer_[i]);
897 }
898
899 // COMMAND DISPLAY REFRESH
900 this->command(0x12);
901}
905 LOG_DISPLAY("", "Waveshare E-Paper", this);
906 ESP_LOGCONFIG(TAG, " Model: 2.7in");
907 LOG_PIN(" Reset Pin: ", this->reset_pin_);
908 LOG_PIN(" DC Pin: ", this->dc_pin_);
909 LOG_PIN(" Busy Pin: ", this->busy_pin_);
910 LOG_UPDATE_INTERVAL(this);
911}
912
914 this->reset_();
915 this->wait_until_idle_();
916
917 this->command(0x12); // SWRESET
918 this->wait_until_idle_();
919
920 // SET WINDOWS
921 // XRAM_START_AND_END_POSITION
922 this->command(0x44);
923 this->data(0x00);
924 this->data(((this->get_width_controller() - 1) >> 3) & 0xFF);
925 // YRAM_START_AND_END_POSITION
926 this->command(0x45);
927 this->data(0x00);
928 this->data(0x00);
929 this->data((get_height_internal() - 1) & 0xFF);
930 this->data(((get_height_internal() - 1) >> 8) & 0xFF);
931
932 // SET CURSOR
933 // XRAM_ADDRESS
934 this->command(0x4E);
935 this->data(0x00);
936 // YRAM_ADDRESS
937 this->command(0x4F);
938 this->data(0x00);
939 this->data(0x00);
940
941 this->command(0x11); // data entry mode
942 this->data(0x03);
943}
945 this->command(0x24);
946 this->start_data_();
947 this->write_array(this->buffer_, this->get_buffer_length_());
948 this->end_data_();
949
950 // COMMAND DISPLAY REFRESH
951 this->command(0x22);
952 this->data(0xF7);
953 this->command(0x20);
954}
958 LOG_DISPLAY("", "Waveshare E-Paper", this);
959 ESP_LOGCONFIG(TAG, " Model: 2.7in V2");
960 LOG_PIN(" Reset Pin: ", this->reset_pin_);
961 LOG_PIN(" DC Pin: ", this->dc_pin_);
962 LOG_PIN(" Busy Pin: ", this->busy_pin_);
963 LOG_UPDATE_INTERVAL(this);
964}
965
966// ========================================================
967// 1.54inch_v2_e-paper_b
968// ========================================================
969// Datasheet:
970// - https://files.waveshare.com/upload/9/9e/1.54inch-e-paper-b-v2-specification.pdf
971// - https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B)_Manual
972
974 this->reset_();
975
976 this->wait_until_idle_();
977
978 this->command(0x12);
979 this->wait_until_idle_();
980
981 this->command(0x01);
982 this->data(0xC7);
983 this->data(0x00);
984 this->data(0x01);
985
986 this->command(0x11); // data entry mode
987 this->data(0x01);
988
989 this->command(0x44); // set Ram-X address start/end position
990 this->data(0x00);
991 this->data(0x18); // 0x18-->(24+1)*8=200
992
993 this->command(0x45); // set Ram-Y address start/end position
994 this->data(0xC7); // 0xC7-->(199+1)=200
995 this->data(0x00);
996 this->data(0x00);
997 this->data(0x00);
998
999 this->command(0x3C); // BorderWavefrom
1000 this->data(0x05);
1001
1002 this->command(0x18); // Read built-in temperature sensor
1003 this->data(0x80);
1004
1005 this->command(0x4E); // set RAM x address count to 0;
1006 this->data(0x00);
1007 this->command(0x4F); // set RAM y address count to 0x199;
1008 this->data(0xC7);
1009 this->data(0x00);
1010
1011 this->wait_until_idle_();
1012}
1013
1015 uint32_t buf_len_half = this->get_buffer_length_() >> 1;
1016 this->initialize();
1017
1018 // COMMAND DATA START TRANSMISSION 1 (BLACK)
1019 this->command(0x24);
1020 delay(2);
1021 for (uint32_t i = 0; i < buf_len_half; i++) {
1022 this->data(~this->buffer_[i]);
1023 }
1024 delay(2);
1025
1026 // COMMAND DATA START TRANSMISSION 2 (RED)
1027 this->command(0x26);
1028 delay(2);
1029 for (uint32_t i = buf_len_half; i < buf_len_half * 2u; i++) {
1030 this->data(this->buffer_[i]);
1031 }
1032 this->command(0x22);
1033 this->data(0xf7);
1034 this->command(0x20);
1035 this->wait_until_idle_();
1036
1037 this->deep_sleep();
1038}
1042 LOG_DISPLAY("", "Waveshare E-Paper", this);
1043 ESP_LOGCONFIG(TAG, " Model: 1.54in V2 B");
1044 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1045 LOG_PIN(" DC Pin: ", this->dc_pin_);
1046 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1047 LOG_UPDATE_INTERVAL(this);
1048}
1049
1050// ========================================================
1051// 2.7inch_e-paper_b
1052// ========================================================
1053// Datasheet:
1054// - https://www.waveshare.com/w/upload/d/d8/2.7inch-e-paper-b-specification.pdf
1055// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_2in7b.c
1056
1057static const uint8_t LUT_VCOM_DC_2_7B[44] = {0x00, 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x0A,
1058 0x00, 0x00, 0x08, 0x00, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x00, 0x0A,
1059 0x0A, 0x00, 0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00,
1060 0x03, 0x0E, 0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
1061
1062static const uint8_t LUT_WHITE_TO_WHITE_2_7B[42] = {0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x40, 0x0A, 0x0A, 0x00, 0x00,
1063 0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x80, 0x0A, 0x0A, 0x00,
1064 0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00, 0x03, 0x0E,
1065 0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
1066
1067static const uint8_t LUT_BLACK_TO_WHITE_2_7B[42] = {0xA0, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x0A, 0x00, 0x00,
1068 0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x90, 0x0A, 0x0A, 0x00,
1069 0x00, 0x08, 0xB0, 0x04, 0x10, 0x00, 0x00, 0x05, 0xB0, 0x03, 0x0E,
1070 0x00, 0x00, 0x0A, 0xC0, 0x23, 0x00, 0x00, 0x00, 0x01};
1071
1072static const uint8_t LUT_WHITE_TO_BLACK_2_7B[] = {0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x20, 0x0A, 0x0A, 0x00, 0x00,
1073 0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x10, 0x0A, 0x0A, 0x00,
1074 0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00, 0x03, 0x0E,
1075 0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
1076
1077static const uint8_t LUT_BLACK_TO_BLACK_2_7B[42] = {0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x40, 0x0A, 0x0A, 0x00, 0x00,
1078 0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x80, 0x0A, 0x0A, 0x00,
1079 0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00, 0x03, 0x0E,
1080 0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
1081
1083 this->reset_();
1084
1085 // command power on
1086 this->command(0x04);
1087 this->wait_until_idle_();
1088 delay(10);
1089
1090 // Command panel setting
1091 this->command(0x00);
1092 this->data(0xAF); // KW-BF KWR-AF BWROTP 0f
1093 // command pll control
1094 this->command(0x30);
1095 this->data(0x3A); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
1096
1097 // command power setting
1098 this->command(0x01);
1099 this->data(0x03); // VDS_EN, VDG_EN
1100 this->data(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
1101 this->data(0x2B); // VDH
1102 this->data(0x2B); // VDL
1103 this->data(0x09); // VDHR
1104
1105 // command booster soft start
1106 this->command(0x06);
1107 this->data(0x07);
1108 this->data(0x07);
1109 this->data(0x17);
1110
1111 // Power optimization - ???
1112 this->command(0xF8);
1113 this->data(0x60);
1114 this->data(0xA5);
1115 this->command(0xF8);
1116 this->data(0x89);
1117 this->data(0xA5);
1118 this->command(0xF8);
1119 this->data(0x90);
1120 this->data(0x00);
1121 this->command(0xF8);
1122 this->data(0x93);
1123 this->data(0x2A);
1124 this->command(0xF8);
1125 this->data(0x73);
1126 this->data(0x41);
1127
1128 // COMMAND VCM DC SETTING
1129 this->command(0x82);
1130 this->data(0x12);
1131
1132 // VCOM_AND_DATA_INTERVAL_SETTING
1133 this->command(0x50);
1134 this->data(0x87); // define by OTP
1135
1136 delay(2);
1137 // COMMAND LUT FOR VCOM
1138 this->command(0x20);
1139 for (uint8_t i : LUT_VCOM_DC_2_7B)
1140 this->data(i);
1141 // COMMAND LUT WHITE TO WHITE
1142 this->command(0x21);
1143 for (uint8_t i : LUT_WHITE_TO_WHITE_2_7B)
1144 this->data(i);
1145 // COMMAND LUT BLACK TO WHITE
1146 this->command(0x22);
1147 for (uint8_t i : LUT_BLACK_TO_WHITE_2_7B)
1148 this->data(i);
1149 // COMMAND LUT WHITE TO BLACK
1150 this->command(0x23);
1151 for (uint8_t i : LUT_WHITE_TO_BLACK_2_7B) {
1152 this->data(i);
1153 }
1154 // COMMAND LUT BLACK TO BLACK
1155 this->command(0x24);
1156
1157 for (uint8_t i : LUT_BLACK_TO_BLACK_2_7B) {
1158 this->data(i);
1159 }
1160
1161 delay(2);
1162}
1163
1165 uint32_t buf_len_half = this->get_buffer_length_() >> 1;
1166 this->initialize();
1167
1168 // TCON_RESOLUTION
1169 this->command(0x61);
1170 this->data(this->get_width_controller() >> 8);
1171 this->data(this->get_width_controller() & 0xff); // 176
1172 this->data(this->get_height_internal() >> 8);
1173 this->data(this->get_height_internal() & 0xff); // 264
1174
1175 // COMMAND DATA START TRANSMISSION 1 (BLACK)
1176 this->command(0x10);
1177 delay(2);
1178 for (uint32_t i = 0; i < buf_len_half; i++) {
1179 this->data(this->buffer_[i]);
1180 }
1181 this->command(0x11);
1182 delay(2);
1183
1184 // COMMAND DATA START TRANSMISSION 2 (RED)
1185 this->command(0x13);
1186 delay(2);
1187 for (uint32_t i = buf_len_half; i < buf_len_half * 2u; i++) {
1188 this->data(this->buffer_[i]);
1189 }
1190 this->command(0x11);
1191
1192 delay(2);
1193
1194 // COMMAND DISPLAY REFRESH
1195 this->command(0x12);
1196 this->wait_until_idle_();
1197
1198 this->deep_sleep();
1199}
1203 LOG_DISPLAY("", "Waveshare E-Paper", this);
1204 ESP_LOGCONFIG(TAG, " Model: 2.7in B");
1205 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1206 LOG_PIN(" DC Pin: ", this->dc_pin_);
1207 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1208 LOG_UPDATE_INTERVAL(this);
1209}
1210
1211// ========================================================
1212// 2.7inch_e-paper_b_v2
1213// ========================================================
1214// Datasheet:
1215// - https://www.waveshare.com/w/upload/7/7b/2.7inch-e-paper-b-v2-specification.pdf
1216// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_2in7b_V2.c
1217
1219 this->reset_();
1220
1221 this->wait_until_idle_();
1222 this->command(0x12);
1223 this->wait_until_idle_();
1224
1225 this->command(0x00);
1226 this->data(0x27);
1227 this->data(0x01);
1228 this->data(0x00);
1229
1230 this->command(0x11);
1231 this->data(0x03);
1232
1233 // self.SetWindows(0, 0, self.width-1, self.height-1)
1234 // SetWindows(self, Xstart, Ystart, Xend, Yend):
1235
1236 uint32_t xend = this->get_width_controller() - 1;
1237 uint32_t yend = this->get_height_internal() - 1;
1238 this->command(0x44);
1239 this->data(0x00);
1240 this->data((xend >> 3) & 0xff);
1241
1242 this->command(0x45);
1243 this->data(0x00);
1244 this->data(0x00);
1245 this->data(yend & 0xff);
1246 this->data((yend >> 8) & 0xff);
1247
1248 // SetCursor(self, Xstart, Ystart):
1249 this->command(0x4E);
1250 this->data(0x00);
1251 this->command(0x4F);
1252 this->data(0x00);
1253 this->data(0x00);
1254}
1255
1257 uint32_t buf_len = this->get_buffer_length_();
1258 // COMMAND DATA START TRANSMISSION 1 (BLACK)
1259 this->command(0x24);
1260 delay(2);
1261 for (uint32_t i = 0; i < buf_len; i++) {
1262 this->data(this->buffer_[i]);
1263 }
1264 delay(2);
1265
1266 // COMMAND DATA START TRANSMISSION 2 (RED)
1267 this->command(0x26);
1268 delay(2);
1269 for (uint32_t i = 0; i < buf_len; i++) {
1270 this->data(this->buffer_[i]);
1271 }
1272
1273 delay(2);
1274
1275 this->command(0x20);
1276
1277 this->wait_until_idle_();
1278}
1282 LOG_DISPLAY("", "Waveshare E-Paper", this);
1283 ESP_LOGCONFIG(TAG, " Model: 2.7in B V2");
1284 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1285 LOG_PIN(" DC Pin: ", this->dc_pin_);
1286 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1287 LOG_UPDATE_INTERVAL(this);
1288}
1289
1290// ========================================================
1291// 2.90in Type B (LUT from OTP)
1292// Datasheet:
1293// - https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf
1294// - https://github.com/soonuse/epd-library-arduino/blob/master/2.9inch_e-paper_b/epd2in9b/epd2in9b.cpp
1295// ========================================================
1296
1298 // from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37
1299 // EPD hardware init start
1300 this->reset_();
1301
1302 // COMMAND BOOSTER SOFT START
1303 this->command(0x06);
1304 this->data(0x17);
1305 this->data(0x17);
1306 this->data(0x17);
1307
1308 // COMMAND POWER ON
1309 this->command(0x04);
1310 this->wait_until_idle_();
1311
1312 // COMMAND PANEL SETTING
1313 this->command(0x00);
1314 // 128x296 resolution: 10
1315 // LUT from OTP: 0
1316 // B/W mode (doesn't work): 1
1317 // scan-up: 1
1318 // shift-right: 1
1319 // booster ON: 1
1320 // no soft reset: 1
1321 this->data(0x9F);
1322
1323 // COMMAND RESOLUTION SETTING
1324 // set to 128x296 by COMMAND PANEL SETTING
1325
1326 // COMMAND VCOM AND DATA INTERVAL SETTING
1327 // use defaults for white border and ESPHome image polarity
1328
1329 // EPD hardware init end
1330}
1332 // COMMAND DATA START TRANSMISSION 1 (B/W data)
1333 this->command(0x10);
1334 delay(2);
1335 this->start_data_();
1336 this->write_array(this->buffer_, this->get_buffer_length_());
1337 this->end_data_();
1338 delay(2);
1339
1340 // COMMAND DATA START TRANSMISSION 2 (RED data)
1341 this->command(0x13);
1342 delay(2);
1343 this->start_data_();
1344 for (size_t i = 0; i < this->get_buffer_length_(); i++)
1345 this->write_byte(0x00);
1346 this->end_data_();
1347 delay(2);
1348
1349 // COMMAND DISPLAY REFRESH
1350 this->command(0x12);
1351 delay(2);
1352 this->wait_until_idle_();
1353
1354 // COMMAND POWER OFF
1355 // NOTE: power off < deep sleep
1356 this->command(0x02);
1357}
1361 LOG_DISPLAY("", "Waveshare E-Paper", this);
1362 ESP_LOGCONFIG(TAG, " Model: 2.9in (B)");
1363 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1364 LOG_PIN(" DC Pin: ", this->dc_pin_);
1365 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1366 LOG_UPDATE_INTERVAL(this);
1367}
1368
1369// ========================================================
1370// Waveshare 2.9-inch E-Paper (Type D)
1371// Waveshare WIKI: https://www.waveshare.com/wiki/Pico-ePaper-2.9-D
1372// Datasheet: https://www.waveshare.com/w/upload/b/b5/2.9inch_e-Paper_(D)_Specification.pdf
1373// ========================================================
1374
1376 // EPD hardware init start
1377 this->reset_();
1378
1379 // Booster Soft Start
1380 this->command(0x06); // Command: BTST
1381 this->data(0x17); // Soft start configuration Phase A
1382 this->data(0x17); // Soft start configuration Phase B
1383 this->data(0x17); // Soft start configuration Phase C
1384
1385 // Power Setting
1386 this->command(0x01); // Command: PWR
1387 this->data(0x03); // Intern DC/DC for VDH/VDL and VGH/VGL
1388 this->data(0x00); // Default configuration VCOM_HV and VGHL_LV
1389 this->data(0x2b); // VDH = 10.8 V
1390 this->data(0x2b); // VDL = -10.8 V
1391
1392 // Power ON
1393 this->command(0x04); // Command: PON
1394 this->wait_until_idle_();
1395
1396 // Panel settings
1397 this->command(0x00); // Command: PSR
1398 this->data(0x1F); // LUT from OTP, black and white mode, default scan
1399
1400 // PLL Control
1401 this->command(0x30); // Command: PLL
1402 this->data(0x3A); // Default PLL frequency
1403
1404 // Resolution settings
1405 this->command(0x61); // Command: TRES
1406 this->data(0x80); // Width: 128
1407 this->data(0x01); // Height MSB: 296
1408 this->data(0x28); // Height LSB: 296
1409
1410 // VCOM and data interval settings
1411 this->command(0x50); // Command: CDI
1412 this->data(0x77);
1413
1414 // VCOM_DC settings
1415 this->command(0x82); // Command: VDCS
1416 this->data(0x12); // Dafault VCOM_DC
1417}
1418
1420 // Start transmitting old data (clearing buffer)
1421 this->command(0x10); // Command: DTM1 (OLD frame data)
1422 this->start_data_();
1423 this->write_array(this->buffer_, this->get_buffer_length_());
1424 this->end_data_();
1425
1426 // Start transmitting new data (updated content)
1427 this->command(0x13); // Command: DTM2 (NEW frame data)
1428 this->start_data_();
1429 this->write_array(this->buffer_, this->get_buffer_length_());
1430 this->end_data_();
1431
1432 // Refresh Display
1433 this->command(0x12); // Command: DRF
1434 this->wait_until_idle_();
1435
1436 // Enter Power Off
1437 this->command(0x02); // Command: POF
1438 this->wait_until_idle_();
1439
1440 // Enter Deep Sleep
1441 this->command(0x07); // Command: DSLP
1442 this->data(0xA5);
1443}
1444
1448 LOG_DISPLAY("", "Waveshare E-Paper", this);
1449 ESP_LOGCONFIG(TAG, " Model: 2.9in (D)");
1450 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1451 LOG_PIN(" DC Pin: ", this->dc_pin_);
1452 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1453 LOG_UPDATE_INTERVAL(this);
1454}
1455
1456// DKE 2.9
1457// https://www.badge.team/docs/badges/sha2017/hardware/#e-ink-display-the-dke-group-depg0290b1
1458// https://www.badge.team/docs/badges/sha2017/hardware/DEPG0290B01V3.0.pdf
1459static const uint8_t LUT_SIZE_DKE = 70;
1460static const uint8_t UPDATE_LUT_DKE[LUT_SIZE_DKE] = {
1461 0xA0, 0x90, 0x50, 0x0, 0x0, 0x0, 0x0, 0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0, 0xA0, 0x90, 0x50, 0x0,
1462 0x0, 0x0, 0x0, 0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0xF,
1463 0xF, 0x0, 0x0, 0x0, 0xF, 0xF, 0x0, 0x0, 0x02, 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1464 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
1465};
1466static const uint8_t PART_UPDATE_LUT_DKE[LUT_SIZE_DKE] = {
1467 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00,
1468 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
1469 0x05, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1470 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1471static const uint8_t FULL_UPDATE_LUT_DKE[LUT_SIZE_DKE] = {
1472 0x90, 0x50, 0xa0, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0xa0, 0x80, 0x00, 0x90, 0x50, 0xa0, 0x50,
1473 0x50, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
1474 0x04, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00,
1475 0x00, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1476
1478 // Hardware reset
1479 delay(10);
1480 this->reset_pin_->digital_write(false);
1481 delayMicroseconds(200);
1482 this->reset_pin_->digital_write(true);
1483 delayMicroseconds(200);
1484 // Wait for busy low
1485 this->wait_until_idle_();
1486 // Software reset
1487 this->command(0x12);
1488 // Wait for busy low
1489 this->wait_until_idle_();
1490 // Set Analog Block Control
1491 this->command(0x74);
1492 this->data(0x54);
1493 // Set Digital Block Control
1494 this->command(0x7E);
1495 this->data(0x3B);
1496 // Set display size and driver output control
1497 this->command(0x01);
1498 // this->data(0x27);
1499 // this->data(0x01);
1500 // this->data(0x00);
1501 this->data(this->get_height_internal() - 1);
1502 this->data((this->get_height_internal() - 1) >> 8);
1503 this->data(0x00); // ? GD = 0, SM = 0, TB = 0
1504 // Ram data entry mode
1505 this->command(0x11);
1506 this->data(0x03);
1507 // Set Ram X address
1508 this->command(0x44);
1509 this->data(0x00);
1510 this->data(0x0F);
1511 // Set Ram Y address
1512 this->command(0x45);
1513 this->data(0x00);
1514 this->data(0x00);
1515 this->data(0x27);
1516 this->data(0x01);
1517 // Set border
1518 this->command(0x3C);
1519 // this->data(0x80);
1520 this->data(0x01);
1521 // Set VCOM value
1522 this->command(0x2C);
1523 this->data(0x26);
1524 // Gate voltage setting
1525 this->command(0x03);
1526 this->data(0x17);
1527 // Source voltage setting
1528 this->command(0x04);
1529 this->data(0x41);
1530 this->data(0x00);
1531 this->data(0x32);
1532 // Frame setting 50hz
1533 this->command(0x3A);
1534 this->data(0x30);
1535 this->command(0x3B);
1536 this->data(0x0A);
1537 // Load LUT
1538 this->command(0x32);
1539 for (uint8_t v : FULL_UPDATE_LUT_DKE)
1540 this->data(v);
1541}
1542
1544 ESP_LOGI(TAG, "Performing e-paper update.");
1545 // Set Ram X address counter
1546 this->command(0x4e);
1547 this->data(0);
1548 // Set Ram Y address counter
1549 this->command(0x4f);
1550 this->data(0);
1551 this->data(0);
1552 // Load image (128/8*296)
1553 this->command(0x24);
1554 this->start_data_();
1555 this->write_array(this->buffer_, this->get_buffer_length_());
1556 this->end_data_();
1557 // Image update
1558 this->command(0x22);
1559 this->data(0xC7);
1560 this->command(0x20);
1561 // Wait for busy low
1562 this->wait_until_idle_();
1563 // Enter deep sleep mode
1564 this->command(0x10);
1565 this->data(0x01);
1566}
1570 LOG_DISPLAY("", "Waveshare E-Paper", this);
1571 ESP_LOGCONFIG(TAG, " Model: 2.9in DKE");
1572 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1573 LOG_PIN(" DC Pin: ", this->dc_pin_);
1574 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1575 LOG_UPDATE_INTERVAL(this);
1576}
1577void WaveshareEPaper2P9InDKE::set_full_update_every(uint32_t full_update_every) {
1578 this->full_update_every_ = full_update_every;
1579}
1580
1581// ========================================================
1582// 2.90in Type B (LUT from OTP)
1583// Datasheet:
1584// - https://files.waveshare.com/upload/a/af/2.9inch-e-paper-b-v3-specification.pdf
1585// ========================================================
1586
1588 // from https://github.com/waveshareteam/e-Paper/blob/master/Arduino/epd2in9b_V3/epd2in9b_V3.cpp
1589 this->reset_();
1590
1591 // COMMAND POWER ON
1592 this->command(0x04);
1593 this->wait_until_idle_();
1594
1595 // COMMAND PANEL SETTING
1596 this->command(0x00);
1597 this->data(0x0F);
1598 this->data(0x89);
1599
1600 // COMMAND RESOLUTION SETTING
1601 this->command(0x61);
1602 this->data(0x80);
1603 this->data(0x01);
1604 this->data(0x28);
1605
1606 // COMMAND VCOM AND DATA INTERVAL SETTING
1607 this->command(0x50);
1608 this->data(0x77);
1609}
1611 // COMMAND DATA START TRANSMISSION 1 (B/W data)
1612 this->command(0x10);
1613 delay(2);
1614 this->start_data_();
1615 this->write_array(this->buffer_, this->get_buffer_length_());
1616 this->end_data_();
1617 this->command(0x92);
1618 delay(2);
1619
1620 // COMMAND DATA START TRANSMISSION 2 (RED data)
1621 this->command(0x13);
1622 delay(2);
1623 this->start_data_();
1624 for (size_t i = 0; i < this->get_buffer_length_(); i++)
1625 this->write_byte(0xFF);
1626 this->end_data_();
1627 this->command(0x92);
1628 delay(2);
1629
1630 // COMMAND DISPLAY REFRESH
1631 this->command(0x12);
1632 delay(2);
1633 this->wait_until_idle_();
1634
1635 // COMMAND POWER OFF
1636 // NOTE: power off < deep sleep
1637 this->command(0x02);
1638}
1642 LOG_DISPLAY("", "Waveshare E-Paper", this);
1643 ESP_LOGCONFIG(TAG, " Model: 2.9in (B) V3");
1644 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1645 LOG_PIN(" DC Pin: ", this->dc_pin_);
1646 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1647 LOG_UPDATE_INTERVAL(this);
1648}
1649
1650// ========================================================
1651// 2.90in v2 rev2
1652// based on SDK and examples in ZIP file from:
1653// https://www.waveshare.com/pico-epaper-2.9.htm
1654// ========================================================
1655
1657 this->reset_();
1658 this->wait_until_idle_();
1659
1660 this->command(0x12); // SWRESET
1661 this->wait_until_idle_();
1662
1663 this->command(0x01);
1664 this->data(0x27);
1665 this->data(0x01);
1666 this->data(0x00);
1667
1668 this->command(0x11);
1669 this->data(0x03);
1670
1671 // SetWindows(0, 0, w, h)
1672 this->command(0x44);
1673 this->data(0x00);
1674 this->data(((this->get_width_controller() - 1) >> 3) & 0xFF);
1675
1676 this->command(0x45);
1677 this->data(0x00);
1678 this->data(0x00);
1679 this->data((this->get_height_internal() - 1) & 0xFF);
1680 this->data(((this->get_height_internal() - 1) >> 8) & 0xFF);
1681
1682 this->command(0x21);
1683 this->data(0x00);
1684 this->data(0x80);
1685
1686 // SetCursor(0, 0)
1687 this->command(0x4E);
1688 this->data(0x00);
1689 this->command(0x4f);
1690 this->data(0x00);
1691 this->data(0x00);
1692
1693 this->wait_until_idle_();
1694}
1695
1697
1698void WaveshareEPaper2P9InV2R2::reset_() {
1699 if (this->reset_pin_ != nullptr) {
1700 this->reset_pin_->digital_write(false);
1701 delay(reset_duration_); // NOLINT
1702 this->reset_pin_->digital_write(true);
1703 delay(reset_duration_); // NOLINT
1704 }
1705}
1706
1708 if (!this->wait_until_idle_()) {
1709 this->status_set_warning();
1710 ESP_LOGE(TAG, "fail idle 1");
1711 return;
1712 }
1713
1714 if (this->full_update_every_ == 1) {
1715 // do single full update
1716 this->command(0x24);
1717 this->start_data_();
1718 this->write_array(this->buffer_, this->get_buffer_length_());
1719 this->end_data_();
1720
1721 // TurnOnDisplay
1722 this->command(0x22);
1723 this->data(0xF7);
1724 this->command(0x20);
1725 return;
1726 }
1727
1728 // if (this->full_update_every_ == 1 ||
1729 if (this->at_update_ == 0) {
1730 // do base update
1731 this->command(0x24);
1732 this->start_data_();
1733 this->write_array(this->buffer_, this->get_buffer_length_());
1734 this->end_data_();
1735
1736 this->command(0x26);
1737 this->start_data_();
1738 this->write_array(this->buffer_, this->get_buffer_length_());
1739 this->end_data_();
1740
1741 // TurnOnDisplay
1742 this->command(0x22);
1743 this->data(0xF7);
1744 this->command(0x20);
1745 } else {
1746 // do partial update
1747 this->reset_();
1748
1749 this->write_lut_(PARTIAL_UPD_2IN9_LUT, PARTIAL_UPD_2IN9_LUT_SIZE);
1750
1751 this->command(0x37);
1752 this->data(0x00);
1753 this->data(0x00);
1754 this->data(0x00);
1755 this->data(0x00);
1756 this->data(0x00);
1757 this->data(0x40);
1758 this->data(0x00);
1759 this->data(0x00);
1760 this->data(0x00);
1761 this->data(0x00);
1762
1763 this->command(0x3C);
1764 this->data(0x80);
1765
1766 this->command(0x22);
1767 this->data(0xC0);
1768 this->command(0x20);
1769
1770 if (!this->wait_until_idle_()) {
1771 ESP_LOGE(TAG, "fail idle 2");
1772 }
1773
1774 // SetWindows(0, 0, w, h)
1775 this->command(0x44);
1776 this->data(0x00);
1777 this->data(((this->get_width_controller() - 1) >> 3) & 0xFF);
1778
1779 this->command(0x45);
1780 this->data(0x00);
1781 this->data(0x00);
1782 this->data((this->get_height_internal() - 1) & 0xFF);
1783 this->data(((this->get_height_internal() - 1) >> 8) & 0xFF);
1784
1785 // SetCursor(0, 0)
1786 this->command(0x4E);
1787 this->data(0x00);
1788 this->command(0x4f);
1789 this->data(0x00);
1790 this->data(0x00);
1791
1792 // write b/w
1793 this->command(0x24);
1794 this->start_data_();
1795 this->write_array(this->buffer_, this->get_buffer_length_());
1796 this->end_data_();
1797
1798 // TurnOnDisplayPartial
1799 this->command(0x22);
1800 this->data(0x0F);
1801 this->command(0x20);
1802 }
1803
1804 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
1805}
1806
1807void WaveshareEPaper2P9InV2R2::write_lut_(const uint8_t *lut, const uint8_t size) {
1808 // COMMAND WRITE LUT REGISTER
1809 this->command(0x32);
1810 for (uint8_t i = 0; i < size; i++)
1811 this->data(lut[i]);
1812}
1813
1815 LOG_DISPLAY("", "Waveshare E-Paper", this);
1816 ESP_LOGCONFIG(TAG, " Model: 2.9inV2R2");
1817 ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
1818 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1819 LOG_PIN(" DC Pin: ", this->dc_pin_);
1820 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1821 LOG_UPDATE_INTERVAL(this);
1822}
1823
1825 this->command(0x10);
1826 this->data(0x01);
1827}
1828
1832void WaveshareEPaper2P9InV2R2::set_full_update_every(uint32_t full_update_every) {
1833 this->full_update_every_ = full_update_every;
1834}
1835// ========================================================
1836// Good Display 2.9in black/white
1837// Datasheet:
1838// - https://files.seeedstudio.com/wiki/Other_Display/29-epaper/GDEY029T94.pdf
1839// -
1840// https://github.com/Allen-Kuang/e-ink_Demo/blob/main/2.9%20inch%20E-paper%20-%20monocolor%20128x296/example/Display_EPD_W21.cpp
1841// ========================================================
1842
1844 // EPD hardware init start
1845 this->reset_();
1846
1847 this->wait_until_idle_();
1848 this->command(0x12); // SWRESET
1849 this->wait_until_idle_();
1850
1851 this->command(0x01); // Driver output control
1852 this->data((this->get_height_internal() - 1) % 256);
1853 this->data((this->get_height_internal() - 1) / 256);
1854 this->data(0x00);
1855
1856 this->command(0x11); // data entry mode
1857 this->data(0x03);
1858
1859 this->command(0x44); // set Ram-X address start/end position
1860 this->data(0x00);
1861 this->data(this->get_width_internal() / 8 - 1);
1862
1863 this->command(0x45); // set Ram-Y address start/end position
1864 this->data(0x00);
1865 this->data(0x00);
1866 this->data((this->get_height_internal() - 1) % 256);
1867 this->data((this->get_height_internal() - 1) / 256);
1868
1869 this->command(0x3C); // BorderWavefrom
1870 this->data(0x05);
1871
1872 this->command(0x21); // Display update control
1873 this->data(0x00);
1874 this->data(0x80);
1875
1876 this->command(0x18); // Read built-in temperature sensor
1877 this->data(0x80);
1878
1879 this->command(0x4E); // set RAM x address count to 0;
1880 this->data(0x00);
1881 this->command(0x4F); // set RAM y address count to 0x199;
1882 this->command(0x00);
1883 this->command(0x00);
1884 this->wait_until_idle_();
1885}
1887 this->command(0x24); // write RAM for black(0)/white (1)
1888 this->start_data_();
1889 for (uint32_t i = 0; i < this->get_buffer_length_(); i++) {
1890 this->write_byte(this->buffer_[i]);
1891 }
1892 this->end_data_();
1893 this->command(0x22); // Display Update Control
1894 this->data(0xF7);
1895 this->command(0x20); // Activate Display Update Sequence
1896 this->wait_until_idle_();
1897}
1901 LOG_DISPLAY("", "E-Paper (Good Display)", this);
1902 ESP_LOGCONFIG(TAG, " Model: 2.9in GDEY029T94");
1903 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1904 LOG_PIN(" DC Pin: ", this->dc_pin_);
1905 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1906 LOG_UPDATE_INTERVAL(this);
1907}
1908
1909// ========================================================
1910// Good Display 2.9in black/white
1911// Datasheet:
1912// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1680.pdf
1913// - https://github.com/adafruit/Adafruit_EPD/blob/master/src/panels/ThinkInk_290_Grayscale4_T5.h
1914// - https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
1915// - http://www.e-paper-display.com/GDEW029T5%20V3.1%20Specification5c22.pdf?
1916// ========================================================
1917
1918// full screen update LUT
1919static const uint8_t LUT_20_VCOMDC_29_5[] = {
1920 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x60, 0x28, 0x28, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00,
1921 0x00, 0x00, 0x01, 0x00, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1922 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1923};
1924
1925static const uint8_t LUT_21_WW_29_5[] = {
1926 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
1927 0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1928 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1929};
1930
1931static const uint8_t LUT_22_BW_29_5[] = {
1932 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
1933 0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1934 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1935};
1936
1937static const uint8_t LUT_23_WB_29_5[] = {
1938 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
1939 0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1940 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1941};
1942
1943static const uint8_t LUT_24_BB_29_5[] = {
1944 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
1945 0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1946 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1947};
1948
1949// partial screen update LUT
1950static const uint8_t LUT_20_VCOMDC_PARTIAL_29_5[] = {
1951 0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1952 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1953 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1954};
1955
1956static const uint8_t LUT_21_WW_PARTIAL_29_5[] = {
1957 0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1958 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1959 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1960};
1961
1962static const uint8_t LUT_22_BW_PARTIAL_29_5[] = {
1963 0x80, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1964 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1965 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1966};
1967
1968static const uint8_t LUT_23_WB_PARTIAL_29_5[] = {
1969 0x40, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1970 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1971 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1972};
1973
1974static const uint8_t LUT_24_BB_PARTIAL_29_5[] = {
1975 0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1976 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1977 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1978};
1979
1981 if (!this->power_is_on_) {
1982 this->command(0x04);
1983 this->wait_until_idle_();
1984 }
1985 this->power_is_on_ = true;
1986}
1987
1989 this->command(0x02);
1990 this->wait_until_idle_();
1991 this->power_is_on_ = false;
1992}
1993
1995 this->power_off_();
1996 if (this->deep_sleep_between_updates_) {
1997 this->command(0x07); // deep sleep
1998 this->data(0xA5); // check code
1999 ESP_LOGD(TAG, "go to deep sleep");
2000 this->is_deep_sleep_ = true;
2001 }
2002}
2003
2005 // from https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
2006
2007 // Hardware Initialization
2008 if (this->deep_sleep_between_updates_ && this->is_deep_sleep_) {
2009 ESP_LOGI(TAG, "wake up from deep sleep");
2010 this->reset_();
2011 this->is_deep_sleep_ = false;
2012 }
2013
2014 // COMMAND POWER SETTINGS
2015 this->command(0x01);
2016 this->data(0x03);
2017 this->data(0x00);
2018 this->data(0x2b);
2019 this->data(0x2b);
2020 this->data(0x03); /* for b/w */
2021
2022 // COMMAND BOOSTER SOFT START
2023 this->command(0x06);
2024 this->data(0x17);
2025 this->data(0x17);
2026 this->data(0x17);
2027
2028 this->power_on_();
2029
2030 // COMMAND PANEL SETTING
2031 this->command(0x00);
2032 // 128x296 resolution: 10
2033 // LUT from register: 1
2034 // B/W mode (doesn't work): 1
2035 // scan-up: 1
2036 // shift-right: 1
2037 // booster ON: 1
2038 // no soft reset: 1
2039 this->data(0b10111111);
2040 this->data(0x0d); // VCOM to 0V fast
2041 this->command(0x30); // PLL setting
2042 this->data(0x3a); // 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
2043 this->command(0x61); // resolution setting
2044 this->data(this->get_width_internal());
2045 this->data(this->get_height_internal() >> 8);
2046 this->data(this->get_height_internal() & 0xFF);
2047
2048 ESP_LOGD(TAG, "panel setting done");
2049}
2050
2052 // from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37
2053 if (this->reset_pin_ != nullptr)
2054 this->deep_sleep_between_updates_ = true;
2055
2056 // old buffer for partial update
2058 this->old_buffer_ = allocator.allocate(this->get_buffer_length_());
2059 if (this->old_buffer_ == nullptr) {
2060 ESP_LOGE(TAG, "Could not allocate old buffer for display!");
2061 return;
2062 }
2063 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2064 this->old_buffer_[i] = 0xFF;
2065 }
2066}
2067
2068// initialize for full(normal) update
2070 this->init_display_();
2071 this->command(0x82); // vcom_DC setting
2072 this->data(0x08);
2073 this->command(0x50); // VCOM AND DATA INTERVAL SETTING
2074 this->data(0x97); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
2075 this->command(0x20);
2076 this->write_lut_(LUT_20_VCOMDC_29_5, sizeof(LUT_20_VCOMDC_29_5));
2077 this->command(0x21);
2078 this->write_lut_(LUT_21_WW_29_5, sizeof(LUT_21_WW_29_5));
2079 this->command(0x22);
2080 this->write_lut_(LUT_22_BW_29_5, sizeof(LUT_22_BW_29_5));
2081 this->command(0x23);
2082 this->write_lut_(LUT_23_WB_29_5, sizeof(LUT_23_WB_29_5));
2083 this->command(0x24);
2084 this->write_lut_(LUT_24_BB_29_5, sizeof(LUT_24_BB_29_5));
2085 ESP_LOGD(TAG, "initialized full update");
2086}
2087
2088// initialzie for partial update
2090 this->init_display_();
2091 this->command(0x82); // vcom_DC setting
2092 this->data(0x08);
2093 this->command(0x50); // VCOM AND DATA INTERVAL SETTING
2094 this->data(0x17); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
2095 this->command(0x20);
2096 this->write_lut_(LUT_20_VCOMDC_PARTIAL_29_5, sizeof(LUT_20_VCOMDC_PARTIAL_29_5));
2097 this->command(0x21);
2098 this->write_lut_(LUT_21_WW_PARTIAL_29_5, sizeof(LUT_21_WW_PARTIAL_29_5));
2099 this->command(0x22);
2100 this->write_lut_(LUT_22_BW_PARTIAL_29_5, sizeof(LUT_22_BW_PARTIAL_29_5));
2101 this->command(0x23);
2102 this->write_lut_(LUT_23_WB_PARTIAL_29_5, sizeof(LUT_23_WB_PARTIAL_29_5));
2103 this->command(0x24);
2104 this->write_lut_(LUT_24_BB_PARTIAL_29_5, sizeof(LUT_24_BB_PARTIAL_29_5));
2105 ESP_LOGD(TAG, "initialized partial update");
2106}
2107
2109 bool full_update = this->at_update_ == 0;
2110 if (full_update) {
2111 this->init_full_();
2112 } else {
2113 this->init_partial_();
2114 this->command(0x91); // partial in
2115 // set partial window
2116 this->command(0x90);
2117 // this->data(0);
2118 this->data(0);
2119 // this->data(0);
2120 this->data((this->get_width_internal() - 1) % 256);
2121 this->data(0);
2122 this->data(0);
2123 this->data(((this->get_height_internal() - 1)) / 256);
2124 this->data(((this->get_height_internal() - 1)) % 256);
2125 this->data(0x01);
2126 }
2127 // input old buffer data
2128 this->command(0x10);
2129 delay(2);
2130 this->start_data_();
2131 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2132 this->write_byte(this->old_buffer_[i]);
2133 }
2134 this->end_data_();
2135 delay(2);
2136
2137 // COMMAND DATA START TRANSMISSION 2 (B/W only)
2138 this->command(0x13);
2139 delay(2);
2140 this->start_data_();
2141 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2142 this->write_byte(this->buffer_[i]);
2143 this->old_buffer_[i] = this->buffer_[i];
2144 }
2145 this->end_data_();
2146 delay(2);
2147
2148 // COMMAND DISPLAY REFRESH
2149 this->command(0x12);
2150 delay(2);
2151 this->wait_until_idle_();
2152
2153 if (full_update) {
2154 ESP_LOGD(TAG, "full update done");
2155 } else {
2156 this->command(0x92); // partial out
2157 ESP_LOGD(TAG, "partial update done");
2158 }
2159
2160 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
2161 // COMMAND deep sleep
2162 this->deep_sleep();
2163}
2164
2165void GDEW029T5::write_lut_(const uint8_t *lut, const uint8_t size) {
2166 // COMMAND WRITE LUT REGISTER
2167 this->start_data_();
2168 for (uint8_t i = 0; i < size; i++)
2169 this->write_byte(lut[i]);
2170 this->end_data_();
2171}
2172
2173void GDEW029T5::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
2174
2178 LOG_DISPLAY("", "Waveshare E-Paper (Good Display)", this);
2179 ESP_LOGCONFIG(TAG, " Model: 2.9in Greyscale GDEW029T5");
2180 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2181 LOG_PIN(" DC Pin: ", this->dc_pin_);
2182 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2183 ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
2184 LOG_UPDATE_INTERVAL(this);
2185}
2186
2187// ========================================================
2188// Good Display 1.54in black/white/grey GDEW0154M09
2189// As used in M5Stack Core Ink
2190// Datasheet:
2191// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEW0154M09-200709.pdf
2192// - https://github.com/m5stack/M5Core-Ink
2193// Reference code from GoodDisplay:
2194// - https://github.com/GoodDisplay/E-paper-Display-Library-of-GoodDisplay/
2195// -> /Monochrome_E-paper-Display/1.54inch_JD79653_GDEW0154M09_200x200/ESP32-Arduino%20IDE/GDEW0154M09_Arduino.ino
2196// M5Stack Core Ink spec:
2197// - https://docs.m5stack.com/en/core/coreink
2198// ========================================================
2199
2201 this->init_internal_();
2203 this->lastbuff_ = allocator.allocate(this->get_buffer_length_());
2204 if (this->lastbuff_ != nullptr) {
2205 memset(this->lastbuff_, 0xff, sizeof(uint8_t) * this->get_buffer_length_());
2206 }
2207 this->clear_();
2208}
2209
2210void GDEW0154M09::reset_() {
2211 // RST is inverse from other einks in this project
2212 if (this->reset_pin_ != nullptr) {
2213 this->reset_pin_->digital_write(false);
2214 delay(10);
2215 this->reset_pin_->digital_write(true);
2216 delay(10);
2217 }
2218}
2219
2220void GDEW0154M09::init_internal_() {
2221 this->reset_();
2222
2223 // clang-format off
2224 // 200x200 resolution: 11
2225 // LUT from OTP: 0
2226 // B/W mode (doesn't work): 1
2227 // scan-up: 1
2228 // shift-right: 1
2229 // booster ON: 1
2230 // no soft reset: 1
2231 const uint8_t panel_setting_1 = 0b11011111;
2232
2233 // VCOM status off 0
2234 // Temp sensing default 1
2235 // VGL Power Off Floating 1
2236 // NORG expect refresh 1
2237 // VCOM Off on displ off 0
2238 const uint8_t panel_setting_2 = 0b01110;
2239
2240 const uint8_t wf_t0154_cz_b3_list[] = {
2241 11, // 11 commands in list
2242 CMD_PSR_PANEL_SETTING, 2, panel_setting_1, panel_setting_2,
2243 CMD_UNDOCUMENTED_0x4D, 1, 0x55,
2244 CMD_UNDOCUMENTED_0xAA, 1, 0x0f,
2245 CMD_UNDOCUMENTED_0xE9, 1, 0x02,
2246 CMD_UNDOCUMENTED_0xB6, 1, 0x11,
2247 CMD_UNDOCUMENTED_0xF3, 1, 0x0a,
2248 CMD_TRES_RESOLUTION_SETTING, 3, 0xc8, 0x00, 0xc8,
2249 CMD_TCON_TCONSETTING, 1, 0x00,
2250 CMD_CDI_VCOM_DATA_INTERVAL, 1, 0xd7,
2251 CMD_PWS_POWER_SAVING, 1, 0x00,
2252 CMD_PON_POWER_ON, 0
2253 };
2254 // clang-format on
2255
2256 this->write_init_list_(wf_t0154_cz_b3_list);
2257 delay(100); // NOLINT
2258 this->wait_until_idle_();
2259}
2260
2261void GDEW0154M09::write_init_list_(const uint8_t *list) {
2262 uint8_t list_limit = list[0];
2263 uint8_t *start_ptr = ((uint8_t *) list + 1);
2264 for (uint8_t i = 0; i < list_limit; i++) {
2265 this->command(*(start_ptr + 0));
2266 for (uint8_t dnum = 0; dnum < *(start_ptr + 1); dnum++) {
2267 this->data(*(start_ptr + 2 + dnum));
2268 }
2269 start_ptr += (*(start_ptr + 1) + 2);
2270 }
2271}
2272
2273void GDEW0154M09::clear_() {
2274 uint32_t pixsize = this->get_buffer_length_();
2275 for (uint8_t j = 0; j < 2; j++) {
2276 this->command(CMD_DTM1_DATA_START_TRANS);
2277 for (int count = 0; count < pixsize; count++) {
2278 this->data(0x00);
2279 }
2280 this->command(CMD_DTM2_DATA_START_TRANS2);
2281 for (int count = 0; count < pixsize; count++) {
2282 this->data(0xff);
2283 }
2284 this->command(CMD_DISPLAY_REFRESH);
2285 delay(10);
2286 this->wait_until_idle_();
2287 }
2288}
2289
2291 this->init_internal_();
2292 // "Mode 0 display" for now
2293 this->command(CMD_DTM1_DATA_START_TRANS);
2294 for (int i = 0; i < this->get_buffer_length_(); i++) {
2295 this->data(0xff);
2296 }
2297 this->command(CMD_DTM2_DATA_START_TRANS2); // write 'new' data to SRAM
2298 for (int i = 0; i < this->get_buffer_length_(); i++) {
2299 this->data(this->buffer_[i]);
2300 }
2301 this->command(CMD_DISPLAY_REFRESH);
2302 delay(10);
2303 this->wait_until_idle_();
2304 this->deep_sleep();
2305}
2306
2308 // COMMAND DEEP SLEEP
2309 this->command(CMD_POF_POWER_OFF);
2310 this->wait_until_idle_();
2311 delay(1000); // NOLINT
2312 this->command(CMD_DSLP_DEEP_SLEEP);
2313 this->data(DATA_DSLP_DEEP_SLEEP);
2314}
2315
2319 LOG_DISPLAY("", "M5Stack CoreInk E-Paper (Good Display)", this);
2320 ESP_LOGCONFIG(TAG, " Model: 1.54in Greyscale GDEW0154M09");
2321 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2322 LOG_PIN(" DC Pin: ", this->dc_pin_);
2323 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2324 LOG_UPDATE_INTERVAL(this);
2325}
2326
2327// ========================================================
2328// Good Display 4.2in black/white GDEY042T81 (SSD1683)
2329// Product page:
2330// - https://www.good-display.com/product/386.html
2331// Datasheet:
2332// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf
2333// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF
2334// Reference code from GoodDisplay:
2335// - https://www.good-display.com/companyfile/1572.html (2024-08-01 15:40:41)
2336// Other reference code:
2337// - https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp
2338// ========================================================
2339
2341 this->init_display_();
2342 ESP_LOGD(TAG, "Initialization complete, set the display to deep sleep");
2343 this->deep_sleep();
2344}
2345
2346// conflicting documentation / examples regarding reset timings
2347// https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF -> 10ms
2348// GD sample code (Display_EPD_W21.cpp, see above) -> 10 ms
2349// https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf (section 14.2) -> 0.2ms (200us)
2350// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L351
2351// -> 10ms
2352// 10 ms seems to work, so we use this
2354
2355void GDEY042T81::reset_() {
2356 if (this->reset_pin_ != nullptr) {
2357 this->reset_pin_->digital_write(false);
2358 delay(reset_duration_); // NOLINT
2359 this->reset_pin_->digital_write(true);
2360 delay(reset_duration_); // NOLINT
2361 }
2362}
2363
2364void GDEY042T81::init_display_() {
2365 this->reset_();
2366
2367 this->wait_until_idle_();
2368 this->command(0x12); // SWRESET
2369 this->wait_until_idle_();
2370
2371 // Specify number of lines for the driver: 300 (MUX 300)
2372 // https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF (section 8.1)
2373 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L354
2374 this->command(0x01); // driver output control
2375 this->data(0x2B); // (height - 1) % 256
2376 this->data(0x01); // (height - 1) / 256
2377 this->data(0x00);
2378
2379 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L360
2380 this->command(0x3C); // BorderWaveform
2381 this->data(0x01);
2382 this->command(0x18); // Read built-in temperature sensor
2383 this->data(0x80);
2384
2385 // GD sample code (Display_EPD_W21.cpp@90ff)
2386 this->command(0x11); // data entry mode
2387 this->data(0x03);
2388 // set windows (0,0,400,300)
2389 this->command(0x44); // set Ram-X address start/end position
2390 this->data(0);
2391 this->data(0x31); // (width / 8 -1)
2392
2393 this->command(0x45); // set Ram-y address start/end position
2394 this->data(0);
2395 this->data(0);
2396 this->data(0x2B); // (height - 1) % 256
2397 this->data(0x01); // (height - 1) / 256
2398
2399 // set cursor (0,0)
2400 this->command(0x4E); // set RAM x address count to 0;
2401 this->data(0);
2402 this->command(0x4F); // set RAM y address count to 0;
2403 this->data(0);
2404 this->data(0);
2405
2406 this->wait_until_idle_();
2407}
2408
2409// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L366
2410void GDEY042T81::update_full_() {
2411 this->command(0x21); // display update control
2412 this->data(0x40); // bypass RED as 0
2413 this->data(0x00); // single chip application
2414
2415 // only ever do a fast update because slow updates are only relevant
2416 // for lower operating temperatures
2417 // see
2418 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_290_GDEY029T94.h#L30
2419 //
2420 // Should slow/fast updates be made configurable similar to how GxEPD2 does it? No idea if anyone would need it...
2421 this->command(0x1A); // Write to temperature register
2422 this->data(0x6E);
2423 this->command(0x22);
2424 this->data(0xd7);
2425
2426 this->command(0x20);
2427 this->wait_until_idle_();
2428}
2429
2430// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L389
2431void GDEY042T81::update_part_() {
2432 this->command(0x21); // display update control
2433 this->data(0x00); // RED normal
2434 this->data(0x00); // single chip application
2435
2436 this->command(0x22);
2437 this->data(0xfc);
2438
2439 this->command(0x20);
2440 this->wait_until_idle_();
2441}
2442
2444 ESP_LOGD(TAG, "Wake up the display");
2445 this->init_display_();
2446
2447 if (!this->wait_until_idle_()) {
2448 this->status_set_warning();
2449 ESP_LOGE(TAG, "Failed to perform update, display is busy");
2450 return;
2451 }
2452
2453 // basic code structure copied from WaveshareEPaper2P9InV2R2
2454 if (this->full_update_every_ == 1) {
2455 ESP_LOGD(TAG, "Full update");
2456 // do single full update
2457 this->command(0x24);
2458 this->start_data_();
2459 this->write_array(this->buffer_, this->get_buffer_length_());
2460 this->end_data_();
2461
2462 // TurnOnDisplay
2463 this->update_full_();
2464 return;
2465 }
2466
2467 // if (this->full_update_every_ == 1 ||
2468 if (this->at_update_ == 0) {
2469 ESP_LOGD(TAG, "Update");
2470 // do base update
2471 this->command(0x24);
2472 this->start_data_();
2473 this->write_array(this->buffer_, this->get_buffer_length_());
2474 this->end_data_();
2475
2476 this->command(0x26);
2477 this->start_data_();
2478 this->write_array(this->buffer_, this->get_buffer_length_());
2479 this->end_data_();
2480
2481 // TurnOnDisplay;
2482 this->update_full_();
2483 } else {
2484 // do partial update (full screen)
2485 // no need to load a LUT for GoodDisplays as they seem to have the LUT onboard
2486 // GD example code (Display_EPD_W21.cpp@283ff)
2487 //
2488 // not setting the BorderWaveform here again (contrary to the GD example) because according to
2489 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L358
2490 // it seems to be enough to set it during display initialization
2491 ESP_LOGD(TAG, "Partial update");
2492 this->reset_();
2493 if (!this->wait_until_idle_()) {
2494 this->status_set_warning();
2495 ESP_LOGE(TAG, "Failed to perform partial update, display is busy");
2496 return;
2497 }
2498
2499 this->command(0x24);
2500 this->start_data_();
2501 this->write_array(this->buffer_, this->get_buffer_length_());
2502 this->end_data_();
2503
2504 // TurnOnDisplay
2505 this->update_part_();
2506 }
2507
2508 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
2509 this->wait_until_idle_();
2510 ESP_LOGD(TAG, "Set the display back to deep sleep");
2511 this->deep_sleep();
2512}
2513void GDEY042T81::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
2516uint32_t GDEY042T81::idle_timeout_() { return 5000; }
2518 LOG_DISPLAY("", "GoodDisplay E-Paper", this);
2519 ESP_LOGCONFIG(TAG, " Model: 4.2in B/W GDEY042T81");
2520 ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
2521 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2522 LOG_PIN(" DC Pin: ", this->dc_pin_);
2523 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2524 LOG_UPDATE_INTERVAL(this);
2525}
2526
2527static const uint8_t LUT_VCOM_DC_4_2[] = {
2528 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x01,
2529 0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2530 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2531};
2532static const uint8_t LUT_WHITE_TO_WHITE_4_2[] = {
2533 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
2534 0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2535 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2536};
2537static const uint8_t LUT_BLACK_TO_WHITE_4_2[] = {
2538 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
2539 0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2540 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2541};
2542
2543static const uint8_t LUT_BLACK_TO_BLACK_4_2[] = {
2544 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
2545 0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2547};
2548
2549static const uint8_t LUT_WHITE_TO_BLACK_4_2[] = {
2550 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
2551 0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2552 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2553};
2554
2556 // https://www.waveshare.com/w/upload/7/7f/4.2inch-e-paper-b-specification.pdf - page 8
2557
2558 // COMMAND POWER SETTING
2559 this->command(0x01);
2560 this->data(0x03); // VDS_EN, VDG_EN
2561 this->data(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
2562 this->data(0x2B); // VDH
2563 this->data(0x2B); // VDL
2564 this->data(0xFF); // VDHR
2565
2566 // COMMAND BOOSTER SOFT START
2567 this->command(0x06);
2568 this->data(0x17); // PHA
2569 this->data(0x17); // PHB
2570 this->data(0x17); // PHC
2571
2572 // COMMAND POWER ON
2573 this->command(0x04);
2574 this->wait_until_idle_();
2575 delay(10);
2576 // COMMAND PANEL SETTING
2577 this->command(0x00);
2578 this->data(0xBF); // KW-BF KWR-AF BWROTP 0f
2579 this->data(0x0B);
2580 // COMMAND PLL CONTROL
2581 this->command(0x30);
2582 this->data(0x3C); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
2583
2584 delay(2);
2585 // COMMAND LUT FOR VCOM
2586 this->command(0x20);
2587 for (uint8_t i : LUT_VCOM_DC_4_2)
2588 this->data(i);
2589 // COMMAND LUT WHITE TO WHITE
2590 this->command(0x21);
2591 for (uint8_t i : LUT_WHITE_TO_WHITE_4_2)
2592 this->data(i);
2593 // COMMAND LUT BLACK TO WHITE
2594 this->command(0x22);
2595 for (uint8_t i : LUT_BLACK_TO_WHITE_4_2)
2596 this->data(i);
2597 // COMMAND LUT WHITE TO BLACK
2598 this->command(0x23);
2599 for (uint8_t i : LUT_WHITE_TO_BLACK_4_2)
2600 this->data(i);
2601 // COMMAND LUT BLACK TO BLACK
2602 this->command(0x24);
2603 for (uint8_t i : LUT_BLACK_TO_BLACK_4_2)
2604 this->data(i);
2605}
2607 // COMMAND RESOLUTION SETTING
2608 this->command(0x61);
2609 this->data(0x01);
2610 this->data(0x90);
2611 this->data(0x01);
2612 this->data(0x2C);
2613
2614 // COMMAND VCM DC SETTING REGISTER
2615 this->command(0x82);
2616 this->data(0x12);
2617
2618 // COMMAND VCOM AND DATA INTERVAL SETTING
2619 this->command(0x50);
2620 this->data(0x97);
2621
2622 // COMMAND DATA START TRANSMISSION 1
2623 this->command(0x10);
2624 delay(2);
2625 this->start_data_();
2626 this->write_array(this->buffer_, this->get_buffer_length_());
2627 this->end_data_();
2628 delay(2);
2629 // COMMAND DATA START TRANSMISSION 2
2630 this->command(0x13);
2631 delay(2);
2632 this->start_data_();
2633 this->write_array(this->buffer_, this->get_buffer_length_());
2634 this->end_data_();
2635 // COMMAND DISPLAY REFRESH
2636 this->command(0x12);
2637}
2641 LOG_DISPLAY("", "Waveshare E-Paper", this);
2642 ESP_LOGCONFIG(TAG, " Model: 4.2in");
2643 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2644 LOG_PIN(" DC Pin: ", this->dc_pin_);
2645 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2646 LOG_UPDATE_INTERVAL(this);
2647}
2648
2649// ========================================================
2650// 4.20in Type B (LUT from OTP)
2651// Datasheet:
2652// - https://www.waveshare.com/w/upload/2/20/4.2inch-e-paper-module-user-manual-en.pdf
2653// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_4in2b_V2.c
2654// ========================================================
2656 // these exact timings are required for a proper reset/init
2657 this->reset_pin_->digital_write(false);
2658 delay(2);
2659 this->reset_pin_->digital_write(true);
2660 delay(200); // NOLINT
2661
2662 // COMMAND POWER ON
2663 this->command(0x04);
2664 this->wait_until_idle_();
2665
2666 // COMMAND PANEL SETTING
2667 this->command(0x00);
2668 this->data(0x0f); // LUT from OTP
2669}
2670
2672 // COMMAND DATA START TRANSMISSION 1 (B/W data)
2673 this->command(0x10);
2674 this->start_data_();
2675 this->write_array(this->buffer_, this->get_buffer_length_());
2676 this->end_data_();
2677
2678 // COMMAND DATA START TRANSMISSION 2 (RED data)
2679 this->command(0x13);
2680 this->start_data_();
2681 for (size_t i = 0; i < this->get_buffer_length_(); i++)
2682 this->write_byte(0xFF);
2683 this->end_data_();
2684 delay(2);
2685
2686 // COMMAND DISPLAY REFRESH
2687 this->command(0x12);
2688 this->wait_until_idle_();
2689
2690 // COMMAND POWER OFF
2691 // NOTE: power off < deep sleep
2692 this->command(0x02);
2693}
2697 LOG_DISPLAY("", "Waveshare E-Paper", this);
2698 ESP_LOGCONFIG(TAG, " Model: 4.2in (B V2)");
2699 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2700 LOG_PIN(" DC Pin: ", this->dc_pin_);
2701 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2702 LOG_UPDATE_INTERVAL(this);
2703}
2704
2705// ========================================================
2706// 4.20in Type B With Red colour support (LUT from OTP)
2707// Datasheet:
2708// - https://www.waveshare.com/w/upload/2/20/4.2inch-e-paper-module-user-manual-en.pdf
2709// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_4in2b_V2.c
2710// The implementation is an adaptation of WaveshareEPaper4P2InBV2 class
2711// ========================================================
2713 // these exact timings are required for a proper reset/init
2714 this->reset_pin_->digital_write(false);
2715 delay(2);
2716 this->reset_pin_->digital_write(true);
2717 delay(200); // NOLINT
2718
2719 // COMMAND POWER ON
2720 this->command(0x04);
2721 this->wait_until_idle_();
2722
2723 // COMMAND PANEL SETTING
2724 this->command(0x00);
2725 this->data(0x0f); // LUT from OTP
2726}
2727
2729 const uint32_t buf_len = this->get_buffer_length_() / 2u;
2730
2731 this->command(0x10); // Send BW data Transmission
2732 delay(2); // Delay to prevent Watchdog error
2733 for (uint32_t i = 0; i < buf_len; ++i) {
2734 this->data(this->buffer_[i]);
2735 }
2736
2737 this->command(0x13); // Send red data Transmission
2738 delay(2); // Delay to prevent Watchdog error
2739 for (uint32_t i = 0; i < buf_len; ++i) {
2740 // Red color need to flip bit from the buffer. Otherwise, red will conqure the screen!
2741 this->data(~this->buffer_[buf_len + i]);
2742 }
2743
2744 // COMMAND DISPLAY REFRESH
2745 this->command(0x12);
2746 this->wait_until_idle_();
2747
2748 // COMMAND POWER OFF
2749 // NOTE: power off < deep sleep
2750 this->command(0x02);
2751}
2755 LOG_DISPLAY("", "Waveshare E-Paper", this);
2756 ESP_LOGCONFIG(TAG, " Model: 4.2in (B V2) BWR-Mode");
2757 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2758 LOG_PIN(" DC Pin: ", this->dc_pin_);
2759 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2760 LOG_UPDATE_INTERVAL(this);
2761}
2762
2764 // COMMAND POWER SETTING
2765 this->command(0x01);
2766 this->data(0x37);
2767 this->data(0x00);
2768
2769 // COMMAND PANEL SETTING
2770 this->command(0x00);
2771 this->data(0xCF);
2772 this->data(0x0B);
2773
2774 // COMMAND BOOSTER SOFT START
2775 this->command(0x06);
2776 this->data(0xC7);
2777 this->data(0xCC);
2778 this->data(0x28);
2779
2780 // COMMAND POWER ON
2781 this->command(0x04);
2782 this->wait_until_idle_();
2783 delay(10);
2784
2785 // COMMAND PLL CONTROL
2786 this->command(0x30);
2787 this->data(0x3C);
2788
2789 // COMMAND TEMPERATURE SENSOR CALIBRATION
2790 this->command(0x41);
2791 this->data(0x00);
2792
2793 // COMMAND VCOM AND DATA INTERVAL SETTING
2794 this->command(0x50);
2795 this->data(0x77);
2796
2797 // COMMAND TCON SETTING
2798 this->command(0x60);
2799 this->data(0x22);
2800
2801 // COMMAND RESOLUTION SETTING
2802 this->command(0x61);
2803 this->data(0x02);
2804 this->data(0x58);
2805 this->data(0x01);
2806 this->data(0xC0);
2807
2808 // COMMAND VCM DC SETTING REGISTER
2809 this->command(0x82);
2810 this->data(0x1E);
2811
2812 this->command(0xE5);
2813 this->data(0x03);
2814}
2816 // COMMAND DATA START TRANSMISSION 1
2817 this->command(0x10);
2818
2819 this->start_data_();
2820 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2821 uint8_t temp1 = this->buffer_[i];
2822 for (uint8_t j = 0; j < 8; j++) {
2823 uint8_t temp2;
2824 if (temp1 & 0x80) {
2825 temp2 = 0x03;
2826 } else {
2827 temp2 = 0x00;
2828 }
2829
2830 temp2 <<= 4;
2831 temp1 <<= 1;
2832 j++;
2833 if (temp1 & 0x80) {
2834 temp2 |= 0x03;
2835 } else {
2836 temp2 |= 0x00;
2837 }
2838 temp1 <<= 1;
2839 this->write_byte(temp2);
2840 }
2841
2842 App.feed_wdt();
2843 }
2844 this->end_data_();
2845
2846 // COMMAND DISPLAY REFRESH
2847 this->command(0x12);
2848}
2852 LOG_DISPLAY("", "Waveshare E-Paper", this);
2853 ESP_LOGCONFIG(TAG, " Model: 5.83in");
2854 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2855 LOG_PIN(" DC Pin: ", this->dc_pin_);
2856 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2857 LOG_UPDATE_INTERVAL(this);
2858}
2859
2860// ========================================================
2861// 5.83in V2
2862// Datasheet/Specification/Reference:
2863// - https://www.waveshare.com/w/upload/3/37/5.83inch_e-Paper_V2_Specification.pdf
2864// - https://github.com/waveshare/e-Paper/blob/master/Arduino/epd5in83_V2/epd5in83_V2.cpp
2865// ========================================================
2867 // COMMAND POWER SETTING
2868 this->command(0x01);
2869 this->data(0x07);
2870 this->data(0x07);
2871 this->data(0x3f);
2872 this->data(0x3f);
2873
2874 // COMMAND POWER ON
2875 this->command(0x04);
2876 delay(10);
2877 this->wait_until_idle_();
2878
2879 // PANNEL SETTING
2880 this->command(0x00);
2881 this->data(0x1F);
2882
2883 // COMMAND RESOLUTION SETTING
2884 this->command(0x61);
2885 this->data(0x02);
2886 this->data(0x88);
2887 this->data(0x01);
2888 this->data(0xE0);
2889
2890 this->command(0x15);
2891 this->data(0x00);
2892
2893 // COMMAND TCON SETTING
2894 this->command(0x60);
2895 this->data(0x22);
2896
2897 // Do we need this?
2898 // COMMAND PLL CONTROL
2899 this->command(0x30);
2900 this->data(0x3C); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
2901}
2903 // Reuse the code from WaveshareEPaper4P2In::display()
2904 // COMMAND VCM DC SETTING REGISTER
2905 this->command(0x82);
2906 this->data(0x12);
2907
2908 // COMMAND VCOM AND DATA INTERVAL SETTING
2909 this->command(0x50);
2910 this->data(0x97);
2911
2912 // COMMAND DATA START TRANSMISSION 1
2913 this->command(0x10);
2914 delay(2);
2915 this->start_data_();
2916 this->write_array(this->buffer_, this->get_buffer_length_());
2917 this->end_data_();
2918 delay(2);
2919
2920 // COMMAND DATA START TRANSMISSION 2
2921 this->command(0x13);
2922 delay(2);
2923 this->start_data_();
2924 this->write_array(this->buffer_, this->get_buffer_length_());
2925 this->end_data_();
2926
2927 // COMMAND DISPLAY REFRESH
2928 this->command(0x12);
2929}
2933 LOG_DISPLAY("", "Waveshare E-Paper", this);
2934 ESP_LOGCONFIG(TAG, " Model: 5.83inv2");
2935 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2936 LOG_PIN(" DC Pin: ", this->dc_pin_);
2937 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2938 LOG_UPDATE_INTERVAL(this);
2939}
2940
2941// ========================================================
2942// Good Display 5.83in black/white GDEY0583T81
2943// Product page:
2944// - https://www.good-display.com/product/440.html
2945// - https://www.seeedstudio.com/5-83-Monochrome-ePaper-Display-with-648x480-Pixels-p-5785.html
2946// Datasheet:
2947// -
2948// https://www.good-display.com/public/html/pdfjs/viewer/viewernew.html?file=https://v4.cecdn.yun300.cn/100001_1909185148/GDEY0583T81-new.pdf
2949// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEY0583T81-new.pdf
2950// Reference code from GoodDisplay:
2951// - https://www.good-display.com/companyfile/903.html
2952// ========================================================
2953
2955 // Allocate buffer for old data for partial updates
2956 RAMAllocator<uint8_t> allocator{};
2957 this->old_buffer_ = allocator.allocate(this->get_buffer_length_());
2958 if (this->old_buffer_ == nullptr) {
2959 ESP_LOGE(TAG, "Could not allocate old buffer for display!");
2960 return;
2961 }
2962 memset(this->old_buffer_, 0xFF, this->get_buffer_length_());
2963
2964 this->init_full_();
2965
2966 this->wait_until_idle_();
2967
2968 this->deep_sleep();
2969}
2970
2971void GDEY0583T81::power_on_() {
2972 if (!this->power_is_on_) {
2973 this->command(0x04);
2974 this->wait_until_idle_();
2975 }
2976 this->power_is_on_ = true;
2977 this->is_deep_sleep_ = false;
2978}
2979
2980void GDEY0583T81::power_off_() {
2981 this->command(0x02);
2982 this->wait_until_idle_();
2983 this->power_is_on_ = false;
2984}
2985
2987 if (this->is_deep_sleep_) {
2988 return;
2989 }
2990
2991 // VCOM and data interval setting (CDI)
2992 this->command(0x50);
2993 this->data(0xf7);
2994
2995 this->power_off_();
2996 delay(10);
2997
2998 // Deep sleep (DSLP)
2999 this->command(0x07);
3000 this->data(0xA5);
3001 this->is_deep_sleep_ = true;
3002}
3003
3004void GDEY0583T81::reset_() {
3005 if (this->reset_pin_ != nullptr) {
3006 this->reset_pin_->digital_write(false);
3007 delay(10);
3008 this->reset_pin_->digital_write(true);
3009 delay(10);
3010 }
3011}
3012
3013// Initialize for full screen update in fast mode
3014void GDEY0583T81::init_full_() {
3015 this->init_display_();
3016
3017 // Based on the GD sample code
3018 // VCOM and data interval setting (CDI)
3019 this->command(0x50);
3020 this->data(0x29);
3021 this->data(0x07);
3022
3023 // Cascade Setting (CCSET)
3024 this->command(0xE0);
3025 this->data(0x02);
3026
3027 // Force Temperature (TSSET)
3028 this->command(0xE5);
3029 this->data(0x5A);
3030}
3031
3032// Initialize for a partial update of the full screen
3033void GDEY0583T81::init_partial_() {
3034 this->init_display_();
3035
3036 // Cascade Setting (CCSET)
3037 this->command(0xE0);
3038 this->data(0x02);
3039
3040 // Force Temperature (TSSET)
3041 this->command(0xE5);
3042 this->data(0x6E);
3043}
3044
3045void GDEY0583T81::init_display_() {
3046 this->reset_();
3047
3048 // Panel Setting (PSR)
3049 this->command(0x00);
3050 // Sets: REG=0, LUT from OTP (set by CDI)
3051 // KW/R=1, Sets KW mode (Black/White)
3052 // as opposed to the default KWR mode (Black/White/Red)
3053 // UD=1, Gate Scan Direction, 1 = up (default)
3054 // SHL=1, Source Shift Direction, 1 = right (default)
3055 // SHD_N=1, Booster Switch, 1 = ON (default)
3056 // RST_N=1, Soft reset, 1 = No effect (default)
3057 this->data(0x1F);
3058
3059 // Resolution setting (TRES)
3060 this->command(0x61);
3061
3062 // Horizontal display resolution (HRES)
3063 this->data(get_width_internal() / 256);
3064 this->data(get_width_internal() % 256);
3065
3066 // Vertical display resolution (VRES)
3067 this->data(get_height_internal() / 256);
3068 this->data(get_height_internal() % 256);
3069
3070 this->power_on_();
3071}
3072
3074 bool full_update = this->at_update_ == 0;
3075 if (full_update) {
3076 this->init_full_();
3077 } else {
3078 this->init_partial_();
3079
3080 // VCOM and data interval setting (CDI)
3081 this->command(0x50);
3082 this->data(0xA9);
3083 this->data(0x07);
3084
3085 // Partial In (PTIN), makes the display enter partial mode
3086 this->command(0x91);
3087
3088 // Partial Window (PTL)
3089 // We use the full screen as the window
3090 this->command(0x90);
3091
3092 // Horizontal start/end channel bank (HRST/HRED)
3093 this->data(0);
3094 this->data(0);
3095 this->data((get_width_internal() - 1) / 256);
3096 this->data((get_width_internal() - 1) % 256);
3097
3098 // Vertical start/end line (VRST/VRED)
3099 this->data(0);
3100 this->data(0);
3101 this->data((get_height_internal() - 1) / 256);
3102 this->data((get_height_internal() - 1) % 256);
3103
3104 this->data(0x01);
3105
3106 // Display Start Transmission 1 (DTM1)
3107 // in KW mode this writes "OLD" data to SRAM
3108 this->command(0x10);
3109 this->start_data_();
3110 this->write_array(this->old_buffer_, this->get_buffer_length_());
3111 this->end_data_();
3112 }
3113
3114 // Display Start Transmission 2 (DTM2)
3115 // in KW mode this writes "NEW" data to SRAM
3116 this->command(0x13);
3117 this->start_data_();
3118 this->write_array(this->buffer_, this->get_buffer_length_());
3119 this->end_data_();
3120
3121 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
3122 this->old_buffer_[i] = this->buffer_[i];
3123 }
3124
3125 // Display Refresh (DRF)
3126 this->command(0x12);
3127 delay(10);
3128 this->wait_until_idle_();
3129
3130 if (full_update) {
3131 ESP_LOGD(TAG, "Full update done");
3132 } else {
3133 // Partial out (PTOUT), makes the display exit partial mode
3134 this->command(0x92);
3135 ESP_LOGD(TAG, "Partial update done, next full update after %d cycles",
3136 this->full_update_every_ - this->at_update_ - 1);
3137 }
3138
3139 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
3140
3141 this->deep_sleep();
3142}
3143
3144void GDEY0583T81::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
3147uint32_t GDEY0583T81::idle_timeout_() { return 5000; }
3149 LOG_DISPLAY("", "GoodDisplay E-Paper", this);
3150 ESP_LOGCONFIG(TAG, " Model: 5.83in B/W GDEY0583T81");
3151 ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
3152 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3153 LOG_PIN(" DC Pin: ", this->dc_pin_);
3154 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3155 LOG_UPDATE_INTERVAL(this);
3156}
3157
3159 // COMMAND POWER SETTING
3160 this->command(0x01);
3161 this->data(0x07);
3162 this->data(0x07); // VGH=20V,VGL=-20V
3163 this->data(0x3f); // VDH=15V
3164 this->data(0x3f); // VDL=-15V
3165 // COMMAND POWER ON
3166 this->command(0x04);
3167 delay(100); // NOLINT
3168 this->wait_until_idle_();
3169 // COMMAND PANEL SETTING
3170 this->command(0x00);
3171 this->data(0x0F); // KW3f, KWR-2F, BWROTP 0f, BWOTP 1f
3172 this->command(0x61); // tres
3173 this->data(0x03); // 800px
3174 this->data(0x20);
3175 this->data(0x01); // 400px
3176 this->data(0xE0);
3177 this->command(0x15);
3178 this->data(0x00);
3179 // COMMAND VCOM AND DATA INTERVAL SETTING
3180 this->command(0x50);
3181 this->data(0x11);
3182 this->data(0x07);
3183 // COMMAND TCON SETTING
3184 this->command(0x60);
3185 this->data(0x22);
3186
3187 this->command(0x82);
3188 this->data(0x08);
3189 this->command(0x30);
3190 this->data(0x06);
3191
3192 // COMMAND RESOLUTION SETTING
3193 this->command(0x65);
3194 this->data(0x00);
3195 this->data(0x00); // 800*480
3196 this->data(0x00);
3197 this->data(0x00);
3198}
3200 // COMMAND DATA START TRANSMISSION 1 (B/W data)
3201 this->command(0x10);
3202 delay(2);
3203 this->start_data_();
3204 this->write_array(this->buffer_, this->get_buffer_length_());
3205 this->end_data_();
3206 delay(2);
3207
3208 // COMMAND DATA START TRANSMISSION 2 (RED data)
3209 this->command(0x13);
3210 delay(2);
3211 this->start_data_();
3212 for (size_t i = 0; i < this->get_buffer_length_(); i++)
3213 this->write_byte(0x00);
3214 this->end_data_();
3215 delay(2);
3216
3217 // COMMAND DISPLAY REFRESH
3218 this->command(0x12);
3219 delay(100); // NOLINT
3220 this->wait_until_idle_();
3221 this->deep_sleep();
3222}
3226 LOG_DISPLAY("", "Waveshare E-Paper", this);
3227 ESP_LOGCONFIG(TAG, " Model: 7.5in-bv2");
3228 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3229 LOG_PIN(" DC Pin: ", this->dc_pin_);
3230 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3231 LOG_UPDATE_INTERVAL(this);
3232}
3233
3236 if (this->busy_pin_ == nullptr) {
3237 return true;
3238 }
3239
3240 const uint32_t start = millis();
3241 while (this->busy_pin_->digital_read()) {
3242 this->command(0x71);
3243 if (millis() - start > this->idle_timeout_()) {
3244 ESP_LOGI(TAG, "Timeout while displaying image!");
3245 return false;
3246 }
3247 App.feed_wdt();
3248 delay(10);
3249 }
3250 delay(200); // NOLINT
3251 return true;
3252};
3254 this->reset_();
3255
3256 // COMMAND POWER SETTING
3257 this->command(0x01);
3258
3259 // 1-0=11: internal power
3260 this->data(0x07);
3261 this->data(0x17); // VGH&VGL
3262 this->data(0x3F); // VSH
3263 this->data(0x26); // VSL
3264 this->data(0x11); // VSHR
3265
3266 // VCOM DC Setting
3267 this->command(0x82);
3268 this->data(0x24); // VCOM
3269
3270 // Booster Setting
3271 this->command(0x06);
3272 this->data(0x27);
3273 this->data(0x27);
3274 this->data(0x2F);
3275 this->data(0x17);
3276
3277 // POWER ON
3278 this->command(0x04);
3279
3280 delay(100); // NOLINT
3281 this->wait_until_idle_();
3282 // COMMAND PANEL SETTING
3283 this->command(0x00);
3284 this->data(0x3F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
3285
3286 // COMMAND RESOLUTION SETTING
3287 this->command(0x61);
3288 this->data(0x03); // source 800
3289 this->data(0x20);
3290 this->data(0x01); // gate 480
3291 this->data(0xE0);
3292 // COMMAND ...?
3293 this->command(0x15);
3294 this->data(0x00);
3295 // COMMAND VCOM AND DATA INTERVAL SETTING
3296 this->command(0x50);
3297 this->data(0x10);
3298 this->data(0x00);
3299 // COMMAND TCON SETTING
3300 this->command(0x60);
3301 this->data(0x22);
3302 // Resolution setting
3303 this->command(0x65);
3304 this->data(0x00);
3305 this->data(0x00); // 800*480
3306 this->data(0x00);
3307 this->data(0x00);
3308
3309 uint8_t lut_vcom_7_i_n5_v2[] = {
3310 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3311 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3312 };
3313
3314 uint8_t lut_ww_7_i_n5_v2[] = {
3315 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3316 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3317 };
3318
3319 uint8_t lut_bw_7_i_n5_v2[] = {
3320 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3321 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3322 };
3323
3324 uint8_t lut_wb_7_i_n5_v2[] = {
3325 0x80, 0xF, 0xF, 0x0, 0x0, 0x3, 0x84, 0xF, 0x1, 0xF, 0x1, 0x4, 0x40, 0xF, 0xF, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0,
3326 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3327 };
3328
3329 uint8_t lut_bb_7_i_n5_v2[] = {
3330 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3331 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3332 };
3333
3334 uint8_t count;
3335 this->command(0x20); // VCOM
3336 for (count = 0; count < 42; count++)
3337 this->data(lut_vcom_7_i_n5_v2[count]);
3338
3339 this->command(0x21); // LUTBW
3340 for (count = 0; count < 42; count++)
3341 this->data(lut_ww_7_i_n5_v2[count]);
3342
3343 this->command(0x22); // LUTBW
3344 for (count = 0; count < 42; count++)
3345 this->data(lut_bw_7_i_n5_v2[count]);
3346
3347 this->command(0x23); // LUTWB
3348 for (count = 0; count < 42; count++)
3349 this->data(lut_wb_7_i_n5_v2[count]);
3350
3351 this->command(0x24); // LUTBB
3352 for (count = 0; count < 42; count++)
3353 this->data(lut_bb_7_i_n5_v2[count]);
3354};
3356 this->init_display_();
3357 uint32_t buf_len = this->get_buffer_length_();
3358
3359 this->command(0x10);
3360 for (uint32_t i = 0; i < buf_len; i++) {
3361 this->data(0xFF);
3362 }
3363
3364 this->command(0x13); // Start Transmission
3365 delay(2);
3366 for (uint32_t i = 0; i < buf_len; i++) {
3367 this->data(~this->buffer_[i]);
3368 }
3369
3370 this->command(0x12); // Display Refresh
3371 delay(100); // NOLINT
3372 this->wait_until_idle_();
3373 this->deep_sleep();
3374}
3378 LOG_DISPLAY("", "Waveshare E-Paper", this);
3379 ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3");
3380 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3381 LOG_PIN(" DC Pin: ", this->dc_pin_);
3382 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3383 LOG_UPDATE_INTERVAL(this);
3384}
3385
3388 if (this->busy_pin_ == nullptr) {
3389 return true;
3390 }
3391
3392 const uint32_t start = millis();
3393 while (this->busy_pin_->digital_read()) {
3394 this->command(0x71);
3395 if (millis() - start > this->idle_timeout_()) {
3396 ESP_LOGI(TAG, "Timeout while displaying image!");
3397 return false;
3398 }
3399 App.feed_wdt();
3400 delay(10);
3401 }
3402 delay(200); // NOLINT
3403 return true;
3404};
3406 this->reset_();
3407
3408 // COMMAND POWER SETTING
3409 this->command(0x01);
3410
3411 // 1-0=11: internal power
3412 this->data(0x07); // VRS_EN=1, VS_EN=1, VG_EN=1
3413 this->data(0x17); // VGH&VGL ??? VCOM_SLEW=1 but this is fixed, VG_LVL[2:0]=111 => VGH=20V VGL=-20V, it could be 0x07
3414 this->data(0x3F); // VSH=15V?
3415 this->data(0x26); // VSL=-9.4V?
3416 this->data(0x11); // VSHR=5.8V?
3417
3418 // VCOM DC Setting
3419 this->command(0x82);
3420 this->data(0x24); // VCOM=-1.9V
3421
3422 // POWER ON
3423 this->command(0x04);
3424 delay(100); // NOLINT
3425 this->wait_until_idle_();
3426
3427 // COMMAND PANEL SETTING
3428 this->command(0x00);
3429 this->data(0x0F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
3430
3431 // COMMAND RESOLUTION SETTING
3432 this->command(0x61);
3433 this->data(0x03); // source 800
3434 this->data(0x20);
3435 this->data(0x01); // gate 480
3436 this->data(0xE0);
3437
3438 // COMMAND VCOM AND DATA INTERVAL SETTING
3439 this->command(0x50);
3440 this->data(0x20);
3441 this->data(0x00);
3442
3443 // COMMAND TCON SETTING
3444 this->command(0x60);
3445 this->data(0x22);
3446
3447 // Resolution setting
3448 this->command(0x65);
3449 this->data(0x00);
3450 this->data(0x00); // 800*480
3451 this->data(0x00);
3452 this->data(0x00);
3453};
3455 this->init_display_();
3456 const uint32_t buf_len = this->get_buffer_length_() / 2u;
3457
3458 this->command(0x10); // Send BW data Transmission
3459 delay(2);
3460 for (uint32_t i = 0; i < buf_len; i++) {
3461 this->data(this->buffer_[i]);
3462 }
3463
3464 this->command(0x13); // Send red data Transmission
3465 delay(2);
3466 for (uint32_t i = 0; i < buf_len; i++) {
3467 this->data(this->buffer_[i + buf_len]);
3468 }
3469
3470 this->command(0x12); // Display Refresh
3471 delay(100); // NOLINT
3472 this->wait_until_idle_();
3473 this->deep_sleep();
3474}
3478 LOG_DISPLAY("", "Waveshare E-Paper", this);
3479 ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3 BWR-Mode");
3480 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3481 LOG_PIN(" DC Pin: ", this->dc_pin_);
3482 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3483 LOG_UPDATE_INTERVAL(this);
3484}
3485
3487 // COMMAND POWER SETTING
3488 this->command(0x01);
3489 this->data(0x37);
3490 this->data(0x00);
3491 // COMMAND PANEL SETTING
3492 this->command(0x00);
3493 this->data(0xCF);
3494 this->data(0x0B);
3495 // COMMAND BOOSTER SOFT START
3496 this->command(0x06);
3497 this->data(0xC7);
3498 this->data(0xCC);
3499 this->data(0x28);
3500 // COMMAND POWER ON
3501 this->command(0x04);
3502 this->wait_until_idle_();
3503 delay(10);
3504 // COMMAND PLL CONTROL
3505 this->command(0x30);
3506 this->data(0x3C);
3507 // COMMAND TEMPERATURE SENSOR CALIBRATION
3508 this->command(0x41);
3509 this->data(0x00);
3510 // COMMAND VCOM AND DATA INTERVAL SETTING
3511 this->command(0x50);
3512 this->data(0x77);
3513 // COMMAND TCON SETTING
3514 this->command(0x60);
3515 this->data(0x22);
3516 // COMMAND RESOLUTION SETTING
3517 this->command(0x61);
3518 this->data(0x02);
3519 this->data(0x80);
3520 this->data(0x01);
3521 this->data(0x80);
3522 // COMMAND VCM DC SETTING REGISTER
3523 this->command(0x82);
3524 this->data(0x1E);
3525 this->command(0xE5);
3526 this->data(0x03);
3527}
3529 // COMMAND DATA START TRANSMISSION 1
3530 this->command(0x10);
3531 this->start_data_();
3532 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
3533 uint8_t temp1 = this->buffer_[i];
3534 for (uint8_t j = 0; j < 8; j++) {
3535 uint8_t temp2;
3536 if (temp1 & 0x80) {
3537 temp2 = 0x03;
3538 } else {
3539 temp2 = 0x00;
3540 }
3541 temp2 <<= 4;
3542 temp1 <<= 1;
3543 j++;
3544 if (temp1 & 0x80) {
3545 temp2 |= 0x03;
3546 } else {
3547 temp2 |= 0x00;
3548 }
3549 temp1 <<= 1;
3550 this->write_byte(temp2);
3551 }
3552 App.feed_wdt();
3553 }
3554 this->end_data_();
3555 // COMMAND DISPLAY REFRESH
3556 this->command(0x12);
3557}
3561 LOG_DISPLAY("", "Waveshare E-Paper", this);
3562 ESP_LOGCONFIG(TAG, " Model: 7.5in");
3563 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3564 LOG_PIN(" DC Pin: ", this->dc_pin_);
3565 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3566 LOG_UPDATE_INTERVAL(this);
3567}
3568
3569// Waveshare 5.65F ========================================================
3570
3571namespace cmddata_5P65InF {
3572// WaveshareEPaper5P65InF commands
3573// https://www.waveshare.com/wiki/5.65inch_e-Paper_Module_(F)
3574
3575// R00H (PSR): Panel setting Register
3576// UD(1): scan up
3577// SHL(1) shift right
3578// SHD_N(1) DC-DC on
3579// RST_N(1) no reset
3580static const uint8_t R00_CMD_PSR[] = {0x00, 0xEF, 0x08};
3581
3582// R01H (PWR): Power setting Register
3583// internal DC-DC power generation
3584static const uint8_t R01_CMD_PWR[] = {0x01, 0x07, 0x00, 0x00, 0x00};
3585
3586// R02H (POF): Power OFF Command
3587static const uint8_t R02_CMD_POF[] = {0x02};
3588
3589// R03H (PFS): Power off sequence setting Register
3590// T_VDS_OFF (00) = 1 frame
3591static const uint8_t R03_CMD_PFS[] = {0x03, 0x00};
3592
3593// R04H (PON): Power ON Command
3594static const uint8_t R04_CMD_PON[] = {0x04};
3595
3596// R06h (BTST): Booster Soft Start
3597static const uint8_t R06_CMD_BTST[] = {0x06, 0xC7, 0xC7, 0x1D};
3598
3599// R07H (DSLP): Deep sleep#
3600// Note Documentation @ Waveshare shows cmd code as 0x10 in table, but
3601// 0x10 is DTM1.
3602static const uint8_t R07_CMD_DSLP[] = {0x07, 0xA5};
3603
3604// R10H (DTM1): Data Start Transmission 1
3605
3606static const uint8_t R10_CMD_DTM1[] = {0x10};
3607
3608// R11H (DSP): Data Stop
3609static const uint8_t R11_CMD_DSP[] = {0x11};
3610
3611// R12H (DRF): Display Refresh
3612static const uint8_t R12_CMD_DRF[] = {0x12};
3613
3614// R13H (IPC): Image Process Command
3615static const uint8_t R13_CMD_IPC[] = {0x13, 0x00};
3616
3617// R30H (PLL): PLL Control
3618// 0x3C = 50Hz
3619static const uint8_t R30_CMD_PLL[] = {0x30, 0x3C};
3620
3621// R41H (TSE): Temperature Sensor Enable
3622// TSE(0) enable, TO(0000) +0 degree offset
3623static const uint8_t R41_CMD_TSE[] = {0x41, 0x00};
3624
3625// R50H (CDI) VCOM and Data interval setting
3626// CDI(0111) 10
3627// DDX(1), VBD(001) Border output "White"
3628static const uint8_t R50_CMD_CDI[] = {0x50, 0x37};
3629
3630// R60H (TCON) Gate and Source non overlap period command
3631// S2G(10) 12 units
3632// G2S(10) 12 units
3633static const uint8_t R60_CMD_TCON[] = {0x60, 0x22};
3634
3635// R61H (TRES) Resolution Setting
3636// 0x258 = 600
3637// 0x1C0 = 448
3638static const uint8_t R61_CMD_TRES[] = {0x61, 0x02, 0x58, 0x01, 0xC0};
3639
3640// RE3H (PWS) Power Savings
3641static const uint8_t RE3_CMD_PWS[] = {0xE3, 0xAA};
3642} // namespace cmddata_5P65InF
3643
3645 if (this->buffers_[0] == nullptr) {
3646 ESP_LOGE(TAG, "Buffer unavailable!");
3647 return;
3648 }
3649
3650 this->reset_();
3651 delay(20);
3652 this->wait_until_(IDLE);
3653
3654 using namespace cmddata_5P65InF;
3655
3656 this->cmd_data(R00_CMD_PSR, sizeof(R00_CMD_PSR));
3657 this->cmd_data(R01_CMD_PWR, sizeof(R01_CMD_PWR));
3658 this->cmd_data(R03_CMD_PFS, sizeof(R03_CMD_PFS));
3659 this->cmd_data(R06_CMD_BTST, sizeof(R06_CMD_BTST));
3660 this->cmd_data(R30_CMD_PLL, sizeof(R30_CMD_PLL));
3661 this->cmd_data(R41_CMD_TSE, sizeof(R41_CMD_TSE));
3662 this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
3663 this->cmd_data(R60_CMD_TCON, sizeof(R60_CMD_TCON));
3664 this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
3665 this->cmd_data(RE3_CMD_PWS, sizeof(RE3_CMD_PWS));
3666
3667 delay(100); // NOLINT
3668 this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
3669
3670 ESP_LOGI(TAG, "Display initialized successfully");
3671}
3672
3674 // INITIALIZATION
3675 ESP_LOGI(TAG, "Initialise the display");
3676 this->initialize();
3677
3678 using namespace cmddata_5P65InF;
3679
3680 // COMMAND DATA START TRANSMISSION
3681 ESP_LOGI(TAG, "Sending data to the display");
3682 this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
3683 this->cmd_data(R10_CMD_DTM1, sizeof(R10_CMD_DTM1));
3684 this->send_buffers_();
3685
3686 // COMMAND POWER ON
3687 ESP_LOGI(TAG, "Power on the display");
3688 this->cmd_data(R04_CMD_PON, sizeof(R04_CMD_PON));
3689 this->wait_until_(IDLE);
3690
3691 // COMMAND REFRESH SCREEN
3692 ESP_LOGI(TAG, "Refresh the display");
3693 this->cmd_data(R12_CMD_DRF, sizeof(R12_CMD_DRF));
3694 this->wait_until_(IDLE);
3695
3696 // COMMAND POWER OFF
3697 ESP_LOGI(TAG, "Power off the display");
3698 this->cmd_data(R02_CMD_POF, sizeof(R02_CMD_POF));
3699 this->wait_until_(BUSY);
3700
3701 if (this->deep_sleep_between_updates_) {
3702 ESP_LOGI(TAG, "Set the display to deep sleep");
3703 this->cmd_data(R07_CMD_DSLP, sizeof(R07_CMD_DSLP));
3704 }
3705}
3706
3709uint32_t WaveshareEPaper5P65InF::idle_timeout_() { return 35000; }
3710
3712 LOG_DISPLAY("", "Waveshare E-Paper", this);
3713 ESP_LOGCONFIG(TAG, " Model: 5.65in-F");
3714 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3715 LOG_PIN(" DC Pin: ", this->dc_pin_);
3716 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3717 LOG_UPDATE_INTERVAL(this);
3718}
3719
3721 if (this->busy_pin_ == nullptr) {
3722 return true;
3723 }
3724
3725 const uint32_t start = millis();
3726 while (busy_state != this->busy_pin_->digital_read()) {
3727 if (millis() - start > this->idle_timeout_()) {
3728 ESP_LOGE(TAG, "Timeout while displaying image!");
3729 return false;
3730 }
3731 App.feed_wdt();
3732 delay(10);
3733 }
3734 return true;
3735}
3736
3738 if (this->buffers_[0] == nullptr) {
3739 ESP_LOGE(TAG, "Buffer unavailable!");
3740 return;
3741 }
3742
3743 this->reset_();
3744 delay(20);
3745 this->wait_until_idle_();
3746
3747 // COMMAND CMDH
3748 this->command(0xAA);
3749 this->data(0x49);
3750 this->data(0x55);
3751 this->data(0x20);
3752 this->data(0x08);
3753 this->data(0x09);
3754 this->data(0x18);
3755
3756 this->command(0x01);
3757 this->data(0x3F);
3758 this->data(0x00);
3759 this->data(0x32);
3760 this->data(0x2A);
3761 this->data(0x0E);
3762 this->data(0x2A);
3763
3764 this->command(0x00);
3765 this->data(0x5F);
3766 this->data(0x69);
3767
3768 this->command(0x03);
3769 this->data(0x00);
3770 this->data(0x54);
3771 this->data(0x00);
3772 this->data(0x44);
3773
3774 this->command(0x05);
3775 this->data(0x40);
3776 this->data(0x1F);
3777 this->data(0x1F);
3778 this->data(0x2C);
3779
3780 this->command(0x06);
3781 this->data(0x6F);
3782 this->data(0x1F);
3783 this->data(0x1F);
3784 this->data(0x22);
3785
3786 this->command(0x08);
3787 this->data(0x6F);
3788 this->data(0x1F);
3789 this->data(0x1F);
3790 this->data(0x22);
3791
3792 // COMMAND IPC
3793 this->command(0x13);
3794 this->data(0x00);
3795 this->data(0x04);
3796
3797 this->command(0x30);
3798 this->data(0x3C);
3799
3800 // COMMAND TSE
3801 this->command(0x41);
3802 this->data(0x00);
3803
3804 this->command(0x50);
3805 this->data(0x3F);
3806
3807 this->command(0x60);
3808 this->data(0x02);
3809 this->data(0x00);
3810
3811 this->command(0x61);
3812 this->data(0x03);
3813 this->data(0x20);
3814 this->data(0x01);
3815 this->data(0xE0);
3816
3817 this->command(0x82);
3818 this->data(0x1E);
3819
3820 this->command(0x84);
3821 this->data(0x00);
3822
3823 // COMMAND AGID
3824 this->command(0x86);
3825 this->data(0x00);
3826
3827 this->command(0xE3);
3828 this->data(0x2F);
3829
3830 // COMMAND CCSET
3831 this->command(0xE0);
3832 this->data(0x00);
3833
3834 // COMMAND TSSET
3835 this->command(0xE6);
3836 this->data(0x00);
3837
3838 ESP_LOGI(TAG, "Display initialized successfully");
3839}
3841 // INITIALIZATION
3842 ESP_LOGI(TAG, "Initialise the display");
3843 this->initialize();
3844
3845 // COMMAND DATA START TRANSMISSION
3846 ESP_LOGI(TAG, "Sending data to the display");
3847 this->command(0x10);
3848 this->send_buffers_();
3849
3850 // COMMAND POWER ON
3851 ESP_LOGI(TAG, "Power on the display");
3852 this->command(0x04);
3853 this->wait_until_idle_();
3854
3855 // COMMAND REFRESH SCREEN
3856 ESP_LOGI(TAG, "Refresh the display");
3857 this->command(0x12);
3858 this->data(0x00);
3859 this->wait_until_idle_();
3860
3861 // COMMAND POWER OFF
3862 ESP_LOGI(TAG, "Power off the display");
3863 this->command(0x02);
3864 this->data(0x00);
3865 this->wait_until_idle_();
3866
3867 if (this->deep_sleep_between_updates_) {
3868 ESP_LOGI(TAG, "Set the display to deep sleep");
3869 this->command(0x07);
3870 this->data(0xA5);
3871 }
3872}
3875uint32_t WaveshareEPaper7P3InF::idle_timeout_() { return 35000; }
3877 LOG_DISPLAY("", "Waveshare E-Paper", this);
3878 ESP_LOGCONFIG(TAG, " Model: 7.3in-F");
3879 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3880 LOG_PIN(" DC Pin: ", this->dc_pin_);
3881 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3882 LOG_UPDATE_INTERVAL(this);
3883}
3884
3886 if (this->busy_pin_ == nullptr) {
3887 return true;
3888 }
3889 const uint32_t start = millis();
3890 while (this->busy_pin_->digital_read()) {
3891 if (millis() - start > this->idle_timeout_()) {
3892 ESP_LOGE(TAG, "Timeout while displaying image!");
3893 return false;
3894 }
3895 App.feed_wdt();
3896 delay(10);
3897 }
3898 delay(200); // NOLINT
3899 return true;
3900}
3902 if (this->busy_pin_ == nullptr) {
3903 return true;
3904 }
3905
3906 const uint32_t start = millis();
3907 while (this->busy_pin_->digital_read()) {
3908 this->command(0x71);
3909 if (millis() - start > this->idle_timeout_()) {
3910 ESP_LOGE(TAG, "Timeout while displaying image!");
3911 return false;
3912 }
3913 App.feed_wdt();
3914 delay(10);
3915 }
3916 return true;
3917}
3919 // COMMAND POWER SETTING
3920 this->command(0x01);
3921 this->data(0x07);
3922 this->data(0x07);
3923 this->data(0x3f);
3924 this->data(0x3f);
3925
3926 // We don't want the display to be powered at this point
3927
3928 delay(100); // NOLINT
3929 this->wait_until_idle_();
3930
3931 // COMMAND VCOM AND DATA INTERVAL SETTING
3932 this->command(0x50);
3933 this->data(0x10);
3934 this->data(0x07);
3935
3936 // COMMAND TCON SETTING
3937 this->command(0x60);
3938 this->data(0x22);
3939
3940 // COMMAND PANEL SETTING
3941 this->command(0x00);
3942 this->data(0x1F);
3943
3944 // COMMAND RESOLUTION SETTING
3945 this->command(0x61);
3946 this->data(0x03);
3947 this->data(0x20);
3948 this->data(0x01);
3949 this->data(0xE0);
3950
3951 // COMMAND DUAL SPI MM_EN, DUSPI_EN
3952 this->command(0x15);
3953 this->data(0x00);
3954
3955 // COMMAND POWER DRIVER HAT DOWN
3956 // This command will turn off booster, controller, source driver, gate driver, VCOM, and
3957 // temperature sensor, but register data will be kept until VDD turned OFF or Deep Sleep Mode.
3958 // Source/Gate/Border/VCOM will be released to floating.
3959 this->command(0x02);
3960}
3962 uint32_t buf_len = this->get_buffer_length_();
3963
3964 // COMMAND POWER ON
3965 ESP_LOGI(TAG, "Power on the display and hat");
3966
3967 // This command will turn on booster, controller, regulators, and temperature sensor will be
3968 // activated for one-time sensing before enabling booster. When all voltages are ready, the
3969 // BUSY_N signal will return to high.
3970 this->command(0x04);
3971 delay(200); // NOLINT
3972 this->wait_until_idle_();
3973
3974 // COMMAND DATA START TRANSMISSION NEW DATA
3975 this->command(0x13);
3976 delay(2);
3977 for (uint32_t i = 0; i < buf_len; i++) {
3978 this->data(~(this->buffer_[i]));
3979 }
3980
3981 delay(100); // NOLINT
3982 this->wait_until_idle_();
3983
3984 // COMMAND DISPLAY REFRESH
3985 this->command(0x12);
3986 delay(100); // NOLINT
3987 this->wait_until_idle_();
3988
3989 ESP_LOGV(TAG, "Before command(0x02) (>> power off)");
3990 this->command(0x02);
3991 this->wait_until_idle_();
3992 ESP_LOGV(TAG, "After command(0x02) (>> power off)");
3993}
3994
3997uint32_t WaveshareEPaper7P5InV2::idle_timeout_() { return 10000; }
3999 LOG_DISPLAY("", "Waveshare E-Paper", this);
4000 ESP_LOGCONFIG(TAG, " Model: 7.5inV2rev2");
4001 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4002 LOG_PIN(" DC Pin: ", this->dc_pin_);
4003 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4004 LOG_UPDATE_INTERVAL(this);
4005}
4006
4007/* 7.50inV2alt */
4009 if (this->busy_pin_ == nullptr) {
4010 return true;
4011 }
4012
4013 const uint32_t start = millis();
4014 while (this->busy_pin_->digital_read()) {
4015 this->command(0x71);
4016 if (millis() - start > this->idle_timeout_()) {
4017 ESP_LOGI(TAG, "Timeout while displaying image!");
4018 return false;
4019 }
4020 delay(10);
4021 }
4022 return true;
4023}
4024
4026 this->reset_();
4027
4028 // COMMAND POWER SETTING
4029 this->command(0x01);
4030
4031 // 1-0=11: internal power
4032 this->data(0x07);
4033 this->data(0x17); // VGH&VGL
4034 this->data(0x3F); // VSH
4035 this->data(0x26); // VSL
4036 this->data(0x11); // VSHR
4037
4038 // VCOM DC Setting
4039 this->command(0x82);
4040 this->data(0x24); // VCOM
4041
4042 // Booster Setting
4043 this->command(0x06);
4044 this->data(0x27);
4045 this->data(0x27);
4046 this->data(0x2F);
4047 this->data(0x17);
4048
4049 // POWER ON
4050 this->command(0x04);
4051
4052 delay(100); // NOLINT
4053 this->wait_until_idle_();
4054 // COMMAND PANEL SETTING
4055 this->command(0x00);
4056 this->data(0x3F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
4057
4058 // COMMAND RESOLUTION SETTING
4059 this->command(0x61);
4060 this->data(0x03); // source 800
4061 this->data(0x20);
4062 this->data(0x01); // gate 480
4063 this->data(0xE0);
4064 // COMMAND ...?
4065 this->command(0x15);
4066 this->data(0x00);
4067 // COMMAND VCOM AND DATA INTERVAL SETTING
4068 this->command(0x50);
4069 this->data(0x10);
4070 this->data(0x00);
4071 // COMMAND TCON SETTING
4072 this->command(0x60);
4073 this->data(0x22);
4074 // Resolution setting
4075 this->command(0x65);
4076 this->data(0x00);
4077 this->data(0x00); // 800*480
4078 this->data(0x00);
4079 this->data(0x00);
4080
4081 this->wait_until_idle_();
4082
4083 uint8_t lut_vcom_7_i_n5_v2[] = {
4084 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4085 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4086 };
4087
4088 uint8_t lut_ww_7_i_n5_v2[] = {
4089 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4090 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4091 };
4092
4093 uint8_t lut_bw_7_i_n5_v2[] = {
4094 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4095 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4096 };
4097
4098 uint8_t lut_wb_7_i_n5_v2[] = {
4099 0x80, 0xF, 0xF, 0x0, 0x0, 0x3, 0x84, 0xF, 0x1, 0xF, 0x1, 0x4, 0x40, 0xF, 0xF, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0,
4100 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4101 };
4102
4103 uint8_t lut_bb_7_i_n5_v2[] = {
4104 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4105 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4106 };
4107
4108 uint8_t count;
4109 this->command(0x20); // VCOM
4110 for (count = 0; count < 42; count++)
4111 this->data(lut_vcom_7_i_n5_v2[count]);
4112
4113 this->command(0x21); // LUTBW
4114 for (count = 0; count < 42; count++)
4115 this->data(lut_ww_7_i_n5_v2[count]);
4116
4117 this->command(0x22); // LUTBW
4118 for (count = 0; count < 42; count++)
4119 this->data(lut_bw_7_i_n5_v2[count]);
4120
4121 this->command(0x23); // LUTWB
4122 for (count = 0; count < 42; count++)
4123 this->data(lut_wb_7_i_n5_v2[count]);
4124
4125 this->command(0x24); // LUTBB
4126 for (count = 0; count < 42; count++)
4127 this->data(lut_bb_7_i_n5_v2[count]);
4128}
4129
4131 LOG_DISPLAY("", "Waveshare E-Paper", this);
4132 ESP_LOGCONFIG(TAG, " Model: 7.5inV2");
4133 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4134 LOG_PIN(" DC Pin: ", this->dc_pin_);
4135 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4136 LOG_UPDATE_INTERVAL(this);
4137}
4138
4139/* 7.50inV2 with partial and fast refresh */
4141 if (this->busy_pin_ == nullptr) {
4142 return true;
4143 }
4144
4145 const uint32_t start = millis();
4146 while (this->busy_pin_->digital_read()) {
4147 this->command(0x71);
4148 if (millis() - start > this->idle_timeout_()) {
4149 ESP_LOGE(TAG, "Timeout while displaying image!");
4150 return false;
4151 }
4152 App.feed_wdt();
4153 delay(10);
4154 }
4155 return true;
4156}
4157
4158void WaveshareEPaper7P5InV2P::reset_() {
4159 if (this->reset_pin_ != nullptr) {
4160 this->reset_pin_->digital_write(true);
4161 delay(20);
4162 this->reset_pin_->digital_write(false);
4163 delay(2);
4164 this->reset_pin_->digital_write(true);
4165 delay(20);
4166 }
4167}
4168
4169void WaveshareEPaper7P5InV2P::turn_on_display_() {
4170 this->command(0x12);
4171 delay(100); // NOLINT
4172 this->wait_until_idle_();
4173}
4174
4176 this->reset_();
4177
4178 // COMMAND POWER SETTING
4179 this->command(0x01);
4180 this->data(0x07);
4181 this->data(0x07);
4182 this->data(0x3f);
4183 this->data(0x3f);
4184
4185 // COMMAND BOOSTER SOFT START
4186 this->command(0x06);
4187 this->data(0x17);
4188 this->data(0x17);
4189 this->data(0x28);
4190 this->data(0x17);
4191
4192 // COMMAND POWER DRIVER HAT UP
4193 this->command(0x04);
4194 delay(100); // NOLINT
4195 this->wait_until_idle_();
4196
4197 // COMMAND PANEL SETTING
4198 this->command(0x00);
4199 this->data(0x1F);
4200
4201 // COMMAND RESOLUTION SETTING
4202 this->command(0x61);
4203 this->data(0x03);
4204 this->data(0x20);
4205 this->data(0x01);
4206 this->data(0xE0);
4207
4208 // COMMAND DUAL SPI MM_EN, DUSPI_EN
4209 this->command(0x15);
4210 this->data(0x00);
4211
4212 // COMMAND VCOM AND DATA INTERVAL SETTING
4213 this->command(0x50);
4214 this->data(0x10);
4215 this->data(0x07);
4216
4217 // COMMAND TCON SETTING
4218 this->command(0x60);
4219 this->data(0x22);
4220
4221 // COMMAND ENABLE FAST UPDATE
4222 this->command(0xE0);
4223 this->data(0x02);
4224 this->command(0xE5);
4225 this->data(0x5A);
4226
4227 // COMMAND POWER DRIVER HAT DOWN
4228 this->command(0x02);
4229}
4230
4232 uint32_t buf_len = this->get_buffer_length_();
4233
4234 // COMMAND POWER ON
4235 ESP_LOGI(TAG, "Power on the display and hat");
4236
4237 this->command(0x04);
4238 delay(200); // NOLINT
4239 this->wait_until_idle_();
4240
4241 if (this->full_update_every_ == 1) {
4242 this->command(0x13);
4243 for (uint32_t i = 0; i < buf_len; i++) {
4244 this->data(~(this->buffer_[i]));
4245 }
4246
4247 this->turn_on_display_();
4248
4249 this->command(0x02);
4250 this->wait_until_idle_();
4251 return;
4252 }
4253
4254 this->command(0x50);
4255 this->data(0xA9);
4256 this->data(0x07);
4257
4258 if (this->at_update_ == 0) {
4259 // Enable fast refresh
4260 this->command(0xE5);
4261 this->data(0x5A);
4262
4263 this->command(0x92);
4264
4265 this->command(0x10);
4266 delay(2);
4267 for (uint32_t i = 0; i < buf_len; i++) {
4268 this->data(~(this->buffer_[i]));
4269 }
4270
4271 delay(100); // NOLINT
4272 this->wait_until_idle_();
4273
4274 this->command(0x13);
4275 delay(2);
4276 for (uint32_t i = 0; i < buf_len; i++) {
4277 this->data(this->buffer_[i]);
4278 }
4279
4280 delay(100); // NOLINT
4281 this->wait_until_idle_();
4282
4283 this->turn_on_display_();
4284
4285 } else {
4286 // Enable partial refresh
4287 this->command(0xE5);
4288 this->data(0x6E);
4289
4290 // Activate partial refresh and set window bounds
4291 this->command(0x91);
4292 this->command(0x90);
4293
4294 this->data(0x00);
4295 this->data(0x00);
4296 this->data((get_width_internal() - 1) >> 8 & 0xFF);
4297 this->data((get_width_internal() - 1) & 0xFF);
4298
4299 this->data(0x00);
4300 this->data(0x00);
4301 this->data((get_height_internal() - 1) >> 8 & 0xFF);
4302 this->data((get_height_internal() - 1) & 0xFF);
4303
4304 this->data(0x01);
4305
4306 this->command(0x13);
4307 delay(2);
4308 for (uint32_t i = 0; i < buf_len; i++) {
4309 this->data(this->buffer_[i]);
4310 }
4311
4312 delay(100); // NOLINT
4313 this->wait_until_idle_();
4314
4315 this->turn_on_display_();
4316 }
4317
4318 ESP_LOGV(TAG, "Before command(0x02) (>> power off)");
4319 this->command(0x02);
4320 this->wait_until_idle_();
4321 ESP_LOGV(TAG, "After command(0x02) (>> power off)");
4322
4323 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
4324}
4325
4328uint32_t WaveshareEPaper7P5InV2P::idle_timeout_() { return 10000; }
4330 LOG_DISPLAY("", "Waveshare E-Paper", this);
4331 ESP_LOGCONFIG(TAG, " Model: 7.50inv2p");
4332 ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
4333 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4334 LOG_PIN(" DC Pin: ", this->dc_pin_);
4335 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4336 LOG_UPDATE_INTERVAL(this);
4337}
4338void WaveshareEPaper7P5InV2P::set_full_update_every(uint32_t full_update_every) {
4339 this->full_update_every_ = full_update_every;
4340}
4341
4342/* 7.50in-bc */
4344 /* The command sequence is similar to the 7P5In display but differs in subtle ways
4345 to allow for faster updates. */
4346 // COMMAND POWER SETTING
4347 this->command(0x01);
4348 this->data(0x37);
4349 this->data(0x00);
4350
4351 // COMMAND PANEL SETTING
4352 this->command(0x00);
4353 this->data(0xCF);
4354 this->data(0x08);
4355
4356 // COMMAND PLL CONTROL
4357 this->command(0x30);
4358 this->data(0x3A);
4359
4360 // COMMAND VCM_DC_SETTING: all temperature range
4361 this->command(0x82);
4362 this->data(0x28);
4363
4364 // COMMAND BOOSTER SOFT START
4365 this->command(0x06);
4366 this->data(0xC7);
4367 this->data(0xCC);
4368 this->data(0x15);
4369
4370 // COMMAND VCOM AND DATA INTERVAL SETTING
4371 this->command(0x50);
4372 this->data(0x77);
4373
4374 // COMMAND TCON SETTING
4375 this->command(0x60);
4376 this->data(0x22);
4377
4378 // COMMAND FLASH CONTROL
4379 this->command(0x65);
4380 this->data(0x00);
4381
4382 // COMMAND RESOLUTION SETTING
4383 this->command(0x61);
4384 this->data(0x02); // 640 >> 8
4385 this->data(0x80);
4386 this->data(0x01); // 384 >> 8
4387 this->data(0x80);
4388
4389 // COMMAND FLASH MODE
4390 this->command(0xE5);
4391 this->data(0x03);
4392}
4393
4395 // COMMAND DATA START TRANSMISSION 1
4396 this->command(0x10);
4397 this->start_data_();
4398
4399 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
4400 // A line of eight source pixels (each a bit in this byte)
4401 uint8_t eight_pixels = this->buffer_[i];
4402
4403 for (uint8_t j = 0; j < 8; j += 2) {
4404 /* For bichromatic displays, each byte represents two pixels. Each nibble encodes a pixel: 0=white, 3=black,
4405 4=color. Therefore, e.g. 0x44 = two adjacent color pixels, 0x33 is two adjacent black pixels, etc. If you want
4406 to draw using the color pixels, change '0x30' with '0x40' and '0x03' with '0x04' below. */
4407 uint8_t left_nibble = (eight_pixels & 0x80) ? 0x30 : 0x00;
4408 eight_pixels <<= 1;
4409 uint8_t right_nibble = (eight_pixels & 0x80) ? 0x03 : 0x00;
4410 eight_pixels <<= 1;
4411 this->write_byte(left_nibble | right_nibble);
4412 }
4413 App.feed_wdt();
4414 }
4415 this->end_data_();
4416
4417 // Unlike the 7P5In display, we send the "power on" command here rather than during initialization
4418 // COMMAND POWER ON
4419 this->command(0x04);
4420
4421 // COMMAND DISPLAY REFRESH
4422 this->command(0x12);
4423}
4424
4426
4428
4430 LOG_DISPLAY("", "Waveshare E-Paper", this);
4431 ESP_LOGCONFIG(TAG, " Model: 7.5in-bc");
4432 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4433 LOG_PIN(" DC Pin: ", this->dc_pin_);
4434 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4435 LOG_UPDATE_INTERVAL(this);
4436}
4437
4439 this->command(0x12); // SWRESET
4440
4441 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4442
4443 this->command(0x46); // Auto Write RAM
4444 this->data(0xF7);
4445
4446 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4447
4448 this->command(0x47); // Auto Write RAM
4449 this->data(0xF7);
4450
4451 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4452
4453 this->command(0x0C); // Soft start setting
4454 this->data(0xAE);
4455 this->data(0xC7);
4456 this->data(0xC3);
4457 this->data(0xC0);
4458 this->data(0x40);
4459
4460 this->command(0x01); // Set MUX as 527
4461 this->data(0xAF);
4462 this->data(0x02);
4463 this->data(0x01);
4464
4465 this->command(0x11); // Data entry mode
4466 this->data(0x01);
4467
4468 this->command(0x44);
4469 this->data(0x00); // RAM x address start at 0
4470 this->data(0x00);
4471 this->data(0x6F); // RAM x address end at 36Fh -> 879
4472 this->data(0x03);
4473
4474 this->command(0x45);
4475 this->data(0xAF); // RAM y address start at 20Fh;
4476 this->data(0x02);
4477 this->data(0x00); // RAM y address end at 00h;
4478 this->data(0x00);
4479
4480 this->command(0x3C); // VBD
4481 this->data(0x01); // LUT1, for white
4482
4483 this->command(0x18);
4484 this->data(0x80);
4485
4486 this->command(0x22);
4487 this->data(0xB1); // Load Temperature and waveform setting.
4488
4489 this->command(0x20);
4490
4491 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4492
4493 this->command(0x4E);
4494 this->data(0x00);
4495 this->data(0x00);
4496
4497 this->command(0x4F);
4498 this->data(0xAF);
4499 this->data(0x02);
4500}
4501
4503 this->command(0x4F);
4504 this->data(0xAf);
4505 this->data(0x02);
4506
4507 // BLACK
4508 this->command(0x24);
4509 this->start_data_();
4510 this->write_array(this->buffer_, this->get_buffer_length_());
4511 this->end_data_();
4512
4513 // RED
4514 this->command(0x26);
4515 this->start_data_();
4516 for (size_t i = 0; i < this->get_buffer_length_(); i++)
4517 this->write_byte(0x00);
4518 this->end_data_();
4519
4520 this->command(0x22);
4521 this->data(0xC7);
4522 this->command(0x20);
4523 delay(100); // NOLINT
4524}
4525
4527
4529
4531 LOG_DISPLAY("", "Waveshare E-Paper", this);
4532 ESP_LOGCONFIG(TAG, " Model: 7.5in-HD-b");
4533 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4534 LOG_PIN(" DC Pin: ", this->dc_pin_);
4535 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4536 LOG_UPDATE_INTERVAL(this);
4537}
4538
4539static const uint8_t LUT_SIZE_TTGO_DKE_PART = 153;
4540
4541static const uint8_t PART_UPDATE_LUT_TTGO_DKE[LUT_SIZE_TTGO_DKE_PART] = {
4542 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4543 0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0,
4544 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4545 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4546 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4547 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4548 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4549 0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
4550 // 0x22, 0x17, 0x41, 0x0, 0x32, 0x32
4551};
4552
4555 bool partial = this->at_update_ != 0;
4556 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
4557
4558 if (partial) {
4559 ESP_LOGI(TAG, "Performing partial e-paper update.");
4560 } else {
4561 ESP_LOGI(TAG, "Performing full e-paper update.");
4562 }
4563
4564 // start and set up data format
4565 this->command(0x12);
4566 this->wait_until_idle_();
4567
4568 this->command(0x11);
4569 this->data(0x03);
4570 this->command(0x44);
4571 this->data(1);
4572 this->data(this->get_width_internal() / 8);
4573 this->command(0x45);
4574 this->data(0);
4575 this->data(0);
4576 this->data(this->get_height_internal());
4577 this->data(0);
4578 this->command(0x4e);
4579 this->data(1);
4580 this->command(0x4f);
4581 this->data(0);
4582 this->data(0);
4583
4584 if (!partial) {
4585 // send data
4586 this->command(0x24);
4587 this->start_data_();
4588 this->write_array(this->buffer_, this->get_buffer_length_());
4589 this->end_data_();
4590
4591 // commit
4592 this->command(0x20);
4593 this->wait_until_idle_();
4594 } else {
4595 // set up partial update
4596 this->command(0x32);
4597 this->start_data_();
4598 this->write_array(PART_UPDATE_LUT_TTGO_DKE, sizeof(PART_UPDATE_LUT_TTGO_DKE));
4599 this->end_data_();
4600 this->command(0x3F);
4601 this->data(0x22);
4602
4603 this->command(0x03);
4604 this->data(0x17);
4605 this->command(0x04);
4606 this->data(0x41);
4607 this->data(0x00);
4608 this->data(0x32);
4609 this->command(0x2C);
4610 this->data(0x32);
4611
4612 this->command(0x37);
4613 this->data(0x00);
4614 this->data(0x00);
4615 this->data(0x00);
4616 this->data(0x00);
4617 this->data(0x00);
4618 this->data(0x40);
4619 this->data(0x00);
4620 this->data(0x00);
4621 this->data(0x00);
4622 this->data(0x00);
4623
4624 this->command(0x3C);
4625 this->data(0x80);
4626 this->command(0x22);
4627 this->data(0xC0);
4628 this->command(0x20);
4629 this->wait_until_idle_();
4630
4631 // send data
4632 this->command(0x24);
4633 this->start_data_();
4634 this->write_array(this->buffer_, this->get_buffer_length_());
4635 this->end_data_();
4636
4637 // commit as partial
4638 this->command(0x22);
4639 this->data(0xCF);
4640 this->command(0x20);
4641 this->wait_until_idle_();
4642
4643 // data must be sent again on partial update
4644 this->command(0x24);
4645 this->start_data_();
4646 this->write_array(this->buffer_, this->get_buffer_length_());
4647 this->end_data_();
4648 }
4649
4650 ESP_LOGI(TAG, "Completed e-paper update.");
4651}
4652
4657 LOG_DISPLAY("", "Waveshare E-Paper", this);
4658 ESP_LOGCONFIG(TAG, " Model: 2.13inDKE");
4659 LOG_PIN(" CS Pin: ", this->cs_);
4660 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4661 LOG_PIN(" DC Pin: ", this->dc_pin_);
4662 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4663 LOG_UPDATE_INTERVAL(this);
4664}
4665
4666void WaveshareEPaper2P13InDKE::set_full_update_every(uint32_t full_update_every) {
4667 this->full_update_every_ = full_update_every;
4668}
4669
4670// ========================================================
4671// 13.3in (K version)
4672// Datasheet/Specification/Reference:
4673// - https://files.waveshare.com/wiki/13.3inch-e-Paper-HAT-(K)/13.3-inch-e-Paper-(K)-user-manual.pdf
4674// - https://github.com/waveshareteam/e-Paper/tree/master/Arduino/epd13in3k
4675// ========================================================
4676
4677// using default wait_until_idle_() function
4679 this->wait_until_idle_();
4680 this->command(0x12); // SWRESET
4681 this->wait_until_idle_();
4682
4683 this->command(0x0c); // set soft start
4684 this->data(0xae);
4685 this->data(0xc7);
4686 this->data(0xc3);
4687 this->data(0xc0);
4688 this->data(0x80);
4689
4690 this->command(0x01); // driver output control
4691 this->data((get_height_internal() - 1) % 256); // Y
4692 this->data((get_height_internal() - 1) / 256); // Y
4693 this->data(0x00);
4694
4695 this->command(0x11); // data entry mode
4696 this->data(0x03);
4697
4698 // SET WINDOWS
4699 // XRAM_START_AND_END_POSITION
4700 this->command(0x44);
4701 this->data(0 & 0xFF);
4702 this->data((0 >> 8) & 0x03);
4703 this->data((get_width_internal() - 1) & 0xFF);
4704 this->data(((get_width_internal() - 1) >> 8) & 0x03);
4705 // YRAM_START_AND_END_POSITION
4706 this->command(0x45);
4707 this->data(0 & 0xFF);
4708 this->data((0 >> 8) & 0x03);
4709 this->data((get_height_internal() - 1) & 0xFF);
4710 this->data(((get_height_internal() - 1) >> 8) & 0x03);
4711
4712 this->command(0x3C); // Border setting
4713 this->data(0x01);
4714
4715 this->command(0x18); // use the internal temperature sensor
4716 this->data(0x80);
4717
4718 // SET CURSOR
4719 // XRAM_ADDRESS
4720 this->command(0x4E);
4721 this->data(0 & 0xFF);
4722 this->data((0 >> 8) & 0x03);
4723 // YRAM_ADDRESS
4724 this->command(0x4F);
4725 this->data(0 & 0xFF);
4726 this->data((0 >> 8) & 0x03);
4727}
4729 // do single full update
4730 this->command(0x24);
4731 this->start_data_();
4732 this->write_array(this->buffer_, this->get_buffer_length_());
4733 this->end_data_();
4734
4735 // COMMAND DISPLAY REFRESH
4736 this->command(0x22);
4737 this->data(0xF7);
4738 this->command(0x20);
4739}
4740
4743uint32_t WaveshareEPaper13P3InK::idle_timeout_() { return 10000; }
4745 LOG_DISPLAY("", "Waveshare E-Paper", this);
4746 ESP_LOGCONFIG(TAG, " Model: 13.3inK");
4747 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4748 LOG_PIN(" DC Pin: ", this->dc_pin_);
4749 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4750 LOG_UPDATE_INTERVAL(this);
4751}
4752
4753} // namespace waveshare_epaper
4754} // namespace esphome
void feed_wdt(uint32_t time=0)
void status_set_warning(const char *message="unspecified")
void status_clear_warning()
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual bool digital_read()=0
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:683
void deallocate(T *p, size_t n)
Definition helpers.h:741
T * allocate(size_t n)
Definition helpers.h:703
int get_width() override
Get the width of the image in pixels with rotation applied.
void init_internal_(uint32_t buffer_length)
int get_height() override
Get the height of the image in pixels with rotation applied.
void clear()
Clear the entire screen by filling it with OFF pixels.
Definition display.cpp:16
virtual int get_width_internal()=0
virtual int get_height_internal()=0
void filled_rectangle(int x1, int y1, int width, int height, Color color=COLOR_ON)
Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width,...
Definition display.cpp:104
void set_full_update_every(uint32_t full_update_every)
void write_lut_(const uint8_t *lut, uint8_t size)
void set_full_update_every(uint32_t full_update_every)
void set_full_update_every(uint32_t full_update_every)
void write_lut_(const uint8_t *lut, uint8_t size)
void draw_absolute_pixel_internal(int x, int y, Color color) override
void draw_absolute_pixel_internal(int x, int y, Color color) override
void cmd_data(const uint8_t *data, size_t length)
void draw_absolute_pixel_internal(int x, int y, Color color) override
void set_full_update_every(uint32_t full_update_every)
WaveshareEPaperTypeA(WaveshareEPaperTypeAModel model)
void write_lut_(const uint8_t *lut, uint8_t size)
const float PROCESSOR
For components that use data from sensors like displays.
Definition component.cpp:20
const char *const TAG
Definition spi.cpp:8
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:30
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:27
Application App
Global storage of Application pointer - only one Application can exist.
uint8_t red
Definition color.h:15
uint8_t green
Definition color.h:19
bool is_on() ESPHOME_ALWAYS_INLINE
Definition color.h:46
uint8_t blue
Definition color.h:23
uint16_t length
Definition tt21100.cpp:0
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6