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