ESPHome 2026.1.4
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,
1829 " Model: 2.9inV2R2\n"
1830 " Full Update Every: %" PRIu32,
1831 this->full_update_every_);
1832 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1833 LOG_PIN(" DC Pin: ", this->dc_pin_);
1834 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1835 LOG_UPDATE_INTERVAL(this);
1836}
1837
1839 this->command(0x10);
1840 this->data(0x01);
1841}
1842
1846void WaveshareEPaper2P9InV2R2::set_full_update_every(uint32_t full_update_every) {
1847 this->full_update_every_ = full_update_every;
1848}
1849// ========================================================
1850// Good Display 2.9in black/white
1851// Datasheet:
1852// - https://files.seeedstudio.com/wiki/Other_Display/29-epaper/GDEY029T94.pdf
1853// -
1854// https://github.com/Allen-Kuang/e-ink_Demo/blob/main/2.9%20inch%20E-paper%20-%20monocolor%20128x296/example/Display_EPD_W21.cpp
1855// ========================================================
1856
1858 // EPD hardware init start
1859 this->reset_();
1860
1861 this->wait_until_idle_();
1862 this->command(0x12); // SWRESET
1863 this->wait_until_idle_();
1864
1865 this->command(0x01); // Driver output control
1866 this->data((this->get_height_internal() - 1) % 256);
1867 this->data((this->get_height_internal() - 1) / 256);
1868 this->data(0x00);
1869
1870 this->command(0x11); // data entry mode
1871 this->data(0x03);
1872
1873 this->command(0x44); // set Ram-X address start/end position
1874 this->data(0x00);
1875 this->data(this->get_width_internal() / 8 - 1);
1876
1877 this->command(0x45); // set Ram-Y address start/end position
1878 this->data(0x00);
1879 this->data(0x00);
1880 this->data((this->get_height_internal() - 1) % 256);
1881 this->data((this->get_height_internal() - 1) / 256);
1882
1883 this->command(0x3C); // BorderWavefrom
1884 this->data(0x05);
1885
1886 this->command(0x21); // Display update control
1887 this->data(0x00);
1888 this->data(0x80);
1889
1890 this->command(0x18); // Read built-in temperature sensor
1891 this->data(0x80);
1892
1893 this->command(0x4E); // set RAM x address count to 0;
1894 this->data(0x00);
1895 this->command(0x4F); // set RAM y address count to 0x199;
1896 this->command(0x00);
1897 this->command(0x00);
1898 this->wait_until_idle_();
1899}
1901 this->command(0x24); // write RAM for black(0)/white (1)
1902 this->start_data_();
1903 for (uint32_t i = 0; i < this->get_buffer_length_(); i++) {
1904 this->write_byte(this->buffer_[i]);
1905 }
1906 this->end_data_();
1907 this->command(0x22); // Display Update Control
1908 this->data(0xF7);
1909 this->command(0x20); // Activate Display Update Sequence
1910 this->wait_until_idle_();
1911}
1915 LOG_DISPLAY("", "E-Paper (Good Display)", this);
1916 ESP_LOGCONFIG(TAG, " Model: 2.9in GDEY029T94");
1917 LOG_PIN(" Reset Pin: ", this->reset_pin_);
1918 LOG_PIN(" DC Pin: ", this->dc_pin_);
1919 LOG_PIN(" Busy Pin: ", this->busy_pin_);
1920 LOG_UPDATE_INTERVAL(this);
1921}
1922
1923// ========================================================
1924// Good Display 2.9in black/white
1925// Datasheet:
1926// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1680.pdf
1927// - https://github.com/adafruit/Adafruit_EPD/blob/master/src/panels/ThinkInk_290_Grayscale4_T5.h
1928// - https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
1929// - http://www.e-paper-display.com/GDEW029T5%20V3.1%20Specification5c22.pdf?
1930// ========================================================
1931
1932// full screen update LUT
1933static const uint8_t LUT_20_VCOMDC_29_5[] = {
1934 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x60, 0x28, 0x28, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00,
1935 0x00, 0x00, 0x01, 0x00, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1936 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1937};
1938
1939static const uint8_t LUT_21_WW_29_5[] = {
1940 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
1941 0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1942 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1943};
1944
1945static const uint8_t LUT_22_BW_29_5[] = {
1946 0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
1947 0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1948 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1949};
1950
1951static const uint8_t LUT_23_WB_29_5[] = {
1952 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
1953 0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1954 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1955};
1956
1957static const uint8_t LUT_24_BB_29_5[] = {
1958 0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
1959 0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
1960 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1961};
1962
1963// partial screen update LUT
1964static const uint8_t LUT_20_VCOMDC_PARTIAL_29_5[] = {
1965 0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1966 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1967 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1968};
1969
1970static const uint8_t LUT_21_WW_PARTIAL_29_5[] = {
1971 0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1972 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1973 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1974};
1975
1976static const uint8_t LUT_22_BW_PARTIAL_29_5[] = {
1977 0x80, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1978 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1979 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1980};
1981
1982static const uint8_t LUT_23_WB_PARTIAL_29_5[] = {
1983 0x40, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1984 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1985 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1986};
1987
1988static const uint8_t LUT_24_BB_PARTIAL_29_5[] = {
1989 0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1990 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1991 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1992};
1993
1995 if (!this->power_is_on_) {
1996 this->command(0x04);
1997 this->wait_until_idle_();
1998 }
1999 this->power_is_on_ = true;
2000}
2001
2003 this->command(0x02);
2004 this->wait_until_idle_();
2005 this->power_is_on_ = false;
2006}
2007
2009 this->power_off_();
2010 if (this->deep_sleep_between_updates_) {
2011 this->command(0x07); // deep sleep
2012 this->data(0xA5); // check code
2013 ESP_LOGD(TAG, "go to deep sleep");
2014 this->is_deep_sleep_ = true;
2015 }
2016}
2017
2019 // from https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
2020
2021 // Hardware Initialization
2022 if (this->deep_sleep_between_updates_ && this->is_deep_sleep_) {
2023 ESP_LOGI(TAG, "wake up from deep sleep");
2024 this->reset_();
2025 this->is_deep_sleep_ = false;
2026 }
2027
2028 // COMMAND POWER SETTINGS
2029 this->command(0x01);
2030 this->data(0x03);
2031 this->data(0x00);
2032 this->data(0x2b);
2033 this->data(0x2b);
2034 this->data(0x03); /* for b/w */
2035
2036 // COMMAND BOOSTER SOFT START
2037 this->command(0x06);
2038 this->data(0x17);
2039 this->data(0x17);
2040 this->data(0x17);
2041
2042 this->power_on_();
2043
2044 // COMMAND PANEL SETTING
2045 this->command(0x00);
2046 // 128x296 resolution: 10
2047 // LUT from register: 1
2048 // B/W mode (doesn't work): 1
2049 // scan-up: 1
2050 // shift-right: 1
2051 // booster ON: 1
2052 // no soft reset: 1
2053 this->data(0b10111111);
2054 this->data(0x0d); // VCOM to 0V fast
2055 this->command(0x30); // PLL setting
2056 this->data(0x3a); // 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
2057 this->command(0x61); // resolution setting
2058 this->data(this->get_width_internal());
2059 this->data(this->get_height_internal() >> 8);
2060 this->data(this->get_height_internal() & 0xFF);
2061
2062 ESP_LOGD(TAG, "panel setting done");
2063}
2064
2066 // from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37
2067 if (this->reset_pin_ != nullptr)
2068 this->deep_sleep_between_updates_ = true;
2069
2070 // old buffer for partial update
2071 RAMAllocator<uint8_t> allocator;
2072 this->old_buffer_ = allocator.allocate(this->get_buffer_length_());
2073 if (this->old_buffer_ == nullptr) {
2074 ESP_LOGE(TAG, "Could not allocate old buffer for display!");
2075 return;
2076 }
2077 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2078 this->old_buffer_[i] = 0xFF;
2079 }
2080}
2081
2082// initialize for full(normal) update
2084 this->init_display_();
2085 this->command(0x82); // vcom_DC setting
2086 this->data(0x08);
2087 this->command(0x50); // VCOM AND DATA INTERVAL SETTING
2088 this->data(0x97); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
2089 this->command(0x20);
2090 this->write_lut_(LUT_20_VCOMDC_29_5, sizeof(LUT_20_VCOMDC_29_5));
2091 this->command(0x21);
2092 this->write_lut_(LUT_21_WW_29_5, sizeof(LUT_21_WW_29_5));
2093 this->command(0x22);
2094 this->write_lut_(LUT_22_BW_29_5, sizeof(LUT_22_BW_29_5));
2095 this->command(0x23);
2096 this->write_lut_(LUT_23_WB_29_5, sizeof(LUT_23_WB_29_5));
2097 this->command(0x24);
2098 this->write_lut_(LUT_24_BB_29_5, sizeof(LUT_24_BB_29_5));
2099 ESP_LOGD(TAG, "initialized full update");
2100}
2101
2102// initialzie for partial update
2104 this->init_display_();
2105 this->command(0x82); // vcom_DC setting
2106 this->data(0x08);
2107 this->command(0x50); // VCOM AND DATA INTERVAL SETTING
2108 this->data(0x17); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
2109 this->command(0x20);
2110 this->write_lut_(LUT_20_VCOMDC_PARTIAL_29_5, sizeof(LUT_20_VCOMDC_PARTIAL_29_5));
2111 this->command(0x21);
2112 this->write_lut_(LUT_21_WW_PARTIAL_29_5, sizeof(LUT_21_WW_PARTIAL_29_5));
2113 this->command(0x22);
2114 this->write_lut_(LUT_22_BW_PARTIAL_29_5, sizeof(LUT_22_BW_PARTIAL_29_5));
2115 this->command(0x23);
2116 this->write_lut_(LUT_23_WB_PARTIAL_29_5, sizeof(LUT_23_WB_PARTIAL_29_5));
2117 this->command(0x24);
2118 this->write_lut_(LUT_24_BB_PARTIAL_29_5, sizeof(LUT_24_BB_PARTIAL_29_5));
2119 ESP_LOGD(TAG, "initialized partial update");
2120}
2121
2123 bool full_update = this->at_update_ == 0;
2124 if (full_update) {
2125 this->init_full_();
2126 } else {
2127 this->init_partial_();
2128 this->command(0x91); // partial in
2129 // set partial window
2130 this->command(0x90);
2131 // this->data(0);
2132 this->data(0);
2133 // this->data(0);
2134 this->data((this->get_width_internal() - 1) % 256);
2135 this->data(0);
2136 this->data(0);
2137 this->data(((this->get_height_internal() - 1)) / 256);
2138 this->data(((this->get_height_internal() - 1)) % 256);
2139 this->data(0x01);
2140 }
2141 // input old buffer data
2142 this->command(0x10);
2143 delay(2);
2144 this->start_data_();
2145 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2146 this->write_byte(this->old_buffer_[i]);
2147 }
2148 this->end_data_();
2149 delay(2);
2150
2151 // COMMAND DATA START TRANSMISSION 2 (B/W only)
2152 this->command(0x13);
2153 delay(2);
2154 this->start_data_();
2155 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2156 this->write_byte(this->buffer_[i]);
2157 this->old_buffer_[i] = this->buffer_[i];
2158 }
2159 this->end_data_();
2160 delay(2);
2161
2162 // COMMAND DISPLAY REFRESH
2163 this->command(0x12);
2164 delay(2);
2165 this->wait_until_idle_();
2166
2167 if (full_update) {
2168 ESP_LOGD(TAG, "full update done");
2169 } else {
2170 this->command(0x92); // partial out
2171 ESP_LOGD(TAG, "partial update done");
2172 }
2173
2174 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
2175 // COMMAND deep sleep
2176 this->deep_sleep();
2177}
2178
2179void GDEW029T5::write_lut_(const uint8_t *lut, const uint8_t size) {
2180 // COMMAND WRITE LUT REGISTER
2181 this->start_data_();
2182 for (uint8_t i = 0; i < size; i++)
2183 this->write_byte(lut[i]);
2184 this->end_data_();
2185}
2186
2187void GDEW029T5::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
2188
2192 LOG_DISPLAY("", "Waveshare E-Paper (Good Display)", this);
2193 ESP_LOGCONFIG(TAG, " Model: 2.9in Greyscale GDEW029T5");
2194 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2195 LOG_PIN(" DC Pin: ", this->dc_pin_);
2196 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2197 ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
2198 LOG_UPDATE_INTERVAL(this);
2199}
2200
2201// ========================================================
2202// Good Display 1.54in black/white/grey GDEW0154M09
2203// As used in M5Stack Core Ink
2204// Datasheet:
2205// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEW0154M09-200709.pdf
2206// - https://github.com/m5stack/M5Core-Ink
2207// Reference code from GoodDisplay:
2208// - https://github.com/GoodDisplay/E-paper-Display-Library-of-GoodDisplay/
2209// -> /Monochrome_E-paper-Display/1.54inch_JD79653_GDEW0154M09_200x200/ESP32-Arduino%20IDE/GDEW0154M09_Arduino.ino
2210// M5Stack Core Ink spec:
2211// - https://docs.m5stack.com/en/core/coreink
2212// ========================================================
2213
2215 this->init_internal_();
2216 RAMAllocator<uint8_t> allocator;
2217 this->lastbuff_ = allocator.allocate(this->get_buffer_length_());
2218 if (this->lastbuff_ != nullptr) {
2219 memset(this->lastbuff_, 0xff, sizeof(uint8_t) * this->get_buffer_length_());
2220 }
2221 this->clear_();
2222}
2223
2224void GDEW0154M09::reset_() {
2225 // RST is inverse from other einks in this project
2226 if (this->reset_pin_ != nullptr) {
2227 this->reset_pin_->digital_write(false);
2228 delay(10);
2229 this->reset_pin_->digital_write(true);
2230 delay(10);
2231 }
2232}
2233
2234void GDEW0154M09::init_internal_() {
2235 this->reset_();
2236
2237 // clang-format off
2238 // 200x200 resolution: 11
2239 // LUT from OTP: 0
2240 // B/W mode (doesn't work): 1
2241 // scan-up: 1
2242 // shift-right: 1
2243 // booster ON: 1
2244 // no soft reset: 1
2245 const uint8_t panel_setting_1 = 0b11011111;
2246
2247 // VCOM status off 0
2248 // Temp sensing default 1
2249 // VGL Power Off Floating 1
2250 // NORG expect refresh 1
2251 // VCOM Off on displ off 0
2252 const uint8_t panel_setting_2 = 0b01110;
2253
2254 const uint8_t wf_t0154_cz_b3_list[] = {
2255 11, // 11 commands in list
2256 CMD_PSR_PANEL_SETTING, 2, panel_setting_1, panel_setting_2,
2257 CMD_UNDOCUMENTED_0x4D, 1, 0x55,
2258 CMD_UNDOCUMENTED_0xAA, 1, 0x0f,
2259 CMD_UNDOCUMENTED_0xE9, 1, 0x02,
2260 CMD_UNDOCUMENTED_0xB6, 1, 0x11,
2261 CMD_UNDOCUMENTED_0xF3, 1, 0x0a,
2262 CMD_TRES_RESOLUTION_SETTING, 3, 0xc8, 0x00, 0xc8,
2263 CMD_TCON_TCONSETTING, 1, 0x00,
2264 CMD_CDI_VCOM_DATA_INTERVAL, 1, 0xd7,
2265 CMD_PWS_POWER_SAVING, 1, 0x00,
2266 CMD_PON_POWER_ON, 0
2267 };
2268 // clang-format on
2269
2270 this->write_init_list_(wf_t0154_cz_b3_list);
2271 delay(100); // NOLINT
2272 this->wait_until_idle_();
2273}
2274
2275void GDEW0154M09::write_init_list_(const uint8_t *list) {
2276 uint8_t list_limit = list[0];
2277 uint8_t *start_ptr = ((uint8_t *) list + 1);
2278 for (uint8_t i = 0; i < list_limit; i++) {
2279 this->command(*(start_ptr + 0));
2280 for (uint8_t dnum = 0; dnum < *(start_ptr + 1); dnum++) {
2281 this->data(*(start_ptr + 2 + dnum));
2282 }
2283 start_ptr += (*(start_ptr + 1) + 2);
2284 }
2285}
2286
2287void GDEW0154M09::clear_() {
2288 uint32_t pixsize = this->get_buffer_length_();
2289 for (uint8_t j = 0; j < 2; j++) {
2290 this->command(CMD_DTM1_DATA_START_TRANS);
2291 for (uint32_t count = 0; count < pixsize; count++) {
2292 this->data(0x00);
2293 }
2294 this->command(CMD_DTM2_DATA_START_TRANS2);
2295 for (uint32_t count = 0; count < pixsize; count++) {
2296 this->data(0xff);
2297 }
2298 this->command(CMD_DISPLAY_REFRESH);
2299 delay(10);
2300 this->wait_until_idle_();
2301 }
2302}
2303
2305 this->init_internal_();
2306 // "Mode 0 display" for now
2307 this->command(CMD_DTM1_DATA_START_TRANS);
2308 for (uint32_t i = 0; i < this->get_buffer_length_(); i++) {
2309 this->data(0xff);
2310 }
2311 this->command(CMD_DTM2_DATA_START_TRANS2); // write 'new' data to SRAM
2312 for (uint32_t i = 0; i < this->get_buffer_length_(); i++) {
2313 this->data(this->buffer_[i]);
2314 }
2315 this->command(CMD_DISPLAY_REFRESH);
2316 delay(10);
2317 this->wait_until_idle_();
2318 this->deep_sleep();
2319}
2320
2322 // COMMAND DEEP SLEEP
2323 this->command(CMD_POF_POWER_OFF);
2324 this->wait_until_idle_();
2325 delay(1000); // NOLINT
2326 this->command(CMD_DSLP_DEEP_SLEEP);
2327 this->data(DATA_DSLP_DEEP_SLEEP);
2328}
2329
2333 LOG_DISPLAY("", "M5Stack CoreInk E-Paper (Good Display)", this);
2334 ESP_LOGCONFIG(TAG, " Model: 1.54in Greyscale GDEW0154M09");
2335 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2336 LOG_PIN(" DC Pin: ", this->dc_pin_);
2337 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2338 LOG_UPDATE_INTERVAL(this);
2339}
2340
2341// ========================================================
2342// Good Display 4.2in black/white GDEY042T81 (SSD1683)
2343// Product page:
2344// - https://www.good-display.com/product/386.html
2345// Datasheet:
2346// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf
2347// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF
2348// Reference code from GoodDisplay:
2349// - https://www.good-display.com/companyfile/1572.html (2024-08-01 15:40:41)
2350// Other reference code:
2351// - https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp
2352// ========================================================
2353
2355 this->init_display_();
2356 ESP_LOGD(TAG, "Initialization complete, set the display to deep sleep");
2357 this->deep_sleep();
2358}
2359
2360// conflicting documentation / examples regarding reset timings
2361// https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF -> 10ms
2362// GD sample code (Display_EPD_W21.cpp, see above) -> 10 ms
2363// https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf (section 14.2) -> 0.2ms (200us)
2364// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L351
2365// -> 10ms
2366// 10 ms seems to work, so we use this
2368
2369void GDEY042T81::reset_() {
2370 if (this->reset_pin_ != nullptr) {
2371 this->reset_pin_->digital_write(false);
2372 delay(reset_duration_); // NOLINT
2373 this->reset_pin_->digital_write(true);
2374 delay(reset_duration_); // NOLINT
2375 }
2376}
2377
2378void GDEY042T81::init_display_() {
2379 this->reset_();
2380
2381 this->wait_until_idle_();
2382 this->command(0x12); // SWRESET
2383 this->wait_until_idle_();
2384
2385 // Specify number of lines for the driver: 300 (MUX 300)
2386 // https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF (section 8.1)
2387 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L354
2388 this->command(0x01); // driver output control
2389 this->data(0x2B); // (height - 1) % 256
2390 this->data(0x01); // (height - 1) / 256
2391 this->data(0x00);
2392
2393 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L360
2394 this->command(0x3C); // BorderWaveform
2395 this->data(0x01);
2396 this->command(0x18); // Read built-in temperature sensor
2397 this->data(0x80);
2398
2399 // GD sample code (Display_EPD_W21.cpp@90ff)
2400 this->command(0x11); // data entry mode
2401 this->data(0x03);
2402 // set windows (0,0,400,300)
2403 this->command(0x44); // set Ram-X address start/end position
2404 this->data(0);
2405 this->data(0x31); // (width / 8 -1)
2406
2407 this->command(0x45); // set Ram-y address start/end position
2408 this->data(0);
2409 this->data(0);
2410 this->data(0x2B); // (height - 1) % 256
2411 this->data(0x01); // (height - 1) / 256
2412
2413 // set cursor (0,0)
2414 this->command(0x4E); // set RAM x address count to 0;
2415 this->data(0);
2416 this->command(0x4F); // set RAM y address count to 0;
2417 this->data(0);
2418 this->data(0);
2419
2420 this->wait_until_idle_();
2421}
2422
2423// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L366
2424void GDEY042T81::update_full_() {
2425 this->command(0x21); // display update control
2426 this->data(0x40); // bypass RED as 0
2427 this->data(0x00); // single chip application
2428
2429 // only ever do a fast update because slow updates are only relevant
2430 // for lower operating temperatures
2431 // see
2432 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_290_GDEY029T94.h#L30
2433 //
2434 // Should slow/fast updates be made configurable similar to how GxEPD2 does it? No idea if anyone would need it...
2435 this->command(0x1A); // Write to temperature register
2436 this->data(0x6E);
2437 this->command(0x22);
2438 this->data(0xd7);
2439
2440 this->command(0x20);
2441 this->wait_until_idle_();
2442}
2443
2444// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L389
2445void GDEY042T81::update_part_() {
2446 this->command(0x21); // display update control
2447 this->data(0x00); // RED normal
2448 this->data(0x00); // single chip application
2449
2450 this->command(0x22);
2451 this->data(0xfc);
2452
2453 this->command(0x20);
2454 this->wait_until_idle_();
2455}
2456
2458 ESP_LOGD(TAG, "Wake up the display");
2459 this->init_display_();
2460
2461 if (!this->wait_until_idle_()) {
2462 this->status_set_warning();
2463 ESP_LOGE(TAG, "Failed to perform update, display is busy");
2464 return;
2465 }
2466
2467 // basic code structure copied from WaveshareEPaper2P9InV2R2
2468 if (this->full_update_every_ == 1) {
2469 ESP_LOGD(TAG, "Full update");
2470 // do single full update
2471 this->command(0x24);
2472 this->start_data_();
2473 this->write_array(this->buffer_, this->get_buffer_length_());
2474 this->end_data_();
2475
2476 // TurnOnDisplay
2477 this->update_full_();
2478 return;
2479 }
2480
2481 // if (this->full_update_every_ == 1 ||
2482 if (this->at_update_ == 0) {
2483 ESP_LOGD(TAG, "Update");
2484 // do base update
2485 this->command(0x24);
2486 this->start_data_();
2487 this->write_array(this->buffer_, this->get_buffer_length_());
2488 this->end_data_();
2489
2490 this->command(0x26);
2491 this->start_data_();
2492 this->write_array(this->buffer_, this->get_buffer_length_());
2493 this->end_data_();
2494
2495 // TurnOnDisplay;
2496 this->update_full_();
2497 } else {
2498 // do partial update (full screen)
2499 // no need to load a LUT for GoodDisplays as they seem to have the LUT onboard
2500 // GD example code (Display_EPD_W21.cpp@283ff)
2501 //
2502 // not setting the BorderWaveform here again (contrary to the GD example) because according to
2503 // https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L358
2504 // it seems to be enough to set it during display initialization
2505 ESP_LOGD(TAG, "Partial update");
2506 this->reset_();
2507 if (!this->wait_until_idle_()) {
2508 this->status_set_warning();
2509 ESP_LOGE(TAG, "Failed to perform partial update, display is busy");
2510 return;
2511 }
2512
2513 this->command(0x24);
2514 this->start_data_();
2515 this->write_array(this->buffer_, this->get_buffer_length_());
2516 this->end_data_();
2517
2518 // TurnOnDisplay
2519 this->update_part_();
2520 }
2521
2522 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
2523 this->wait_until_idle_();
2524 ESP_LOGD(TAG, "Set the display back to deep sleep");
2525 this->deep_sleep();
2526}
2527void GDEY042T81::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
2530uint32_t GDEY042T81::idle_timeout_() { return 5000; }
2532 LOG_DISPLAY("", "GoodDisplay E-Paper", this);
2533 ESP_LOGCONFIG(TAG,
2534 " Model: 4.2in B/W GDEY042T81\n"
2535 " Full Update Every: %" PRIu32,
2536 this->full_update_every_);
2537 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2538 LOG_PIN(" DC Pin: ", this->dc_pin_);
2539 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2540 LOG_UPDATE_INTERVAL(this);
2541}
2542
2543static const uint8_t LUT_VCOM_DC_4_2[] = {
2544 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x01,
2545 0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2546 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2547};
2548static const uint8_t LUT_WHITE_TO_WHITE_4_2[] = {
2549 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
2550 0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2551 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2552};
2553static const uint8_t LUT_BLACK_TO_WHITE_4_2[] = {
2554 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
2555 0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2556 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2557};
2558
2559static const uint8_t LUT_BLACK_TO_BLACK_4_2[] = {
2560 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
2561 0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2563};
2564
2565static const uint8_t LUT_WHITE_TO_BLACK_4_2[] = {
2566 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
2567 0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
2568 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2569};
2570
2572 // https://www.waveshare.com/w/upload/7/7f/4.2inch-e-paper-b-specification.pdf - page 8
2573
2574 // COMMAND POWER SETTING
2575 this->command(0x01);
2576 this->data(0x03); // VDS_EN, VDG_EN
2577 this->data(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
2578 this->data(0x2B); // VDH
2579 this->data(0x2B); // VDL
2580 this->data(0xFF); // VDHR
2581
2582 // COMMAND BOOSTER SOFT START
2583 this->command(0x06);
2584 this->data(0x17); // PHA
2585 this->data(0x17); // PHB
2586 this->data(0x17); // PHC
2587
2588 // COMMAND POWER ON
2589 this->command(0x04);
2590 this->wait_until_idle_();
2591 delay(10);
2592 // COMMAND PANEL SETTING
2593 this->command(0x00);
2594 this->data(0xBF); // KW-BF KWR-AF BWROTP 0f
2595 this->data(0x0B);
2596 // COMMAND PLL CONTROL
2597 this->command(0x30);
2598 this->data(0x3C); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
2599
2600 delay(2);
2601 // COMMAND LUT FOR VCOM
2602 this->command(0x20);
2603 for (uint8_t i : LUT_VCOM_DC_4_2)
2604 this->data(i);
2605 // COMMAND LUT WHITE TO WHITE
2606 this->command(0x21);
2607 for (uint8_t i : LUT_WHITE_TO_WHITE_4_2)
2608 this->data(i);
2609 // COMMAND LUT BLACK TO WHITE
2610 this->command(0x22);
2611 for (uint8_t i : LUT_BLACK_TO_WHITE_4_2)
2612 this->data(i);
2613 // COMMAND LUT WHITE TO BLACK
2614 this->command(0x23);
2615 for (uint8_t i : LUT_WHITE_TO_BLACK_4_2)
2616 this->data(i);
2617 // COMMAND LUT BLACK TO BLACK
2618 this->command(0x24);
2619 for (uint8_t i : LUT_BLACK_TO_BLACK_4_2)
2620 this->data(i);
2621}
2623 // COMMAND RESOLUTION SETTING
2624 this->command(0x61);
2625 this->data(0x01);
2626 this->data(0x90);
2627 this->data(0x01);
2628 this->data(0x2C);
2629
2630 // COMMAND VCM DC SETTING REGISTER
2631 this->command(0x82);
2632 this->data(0x12);
2633
2634 // COMMAND VCOM AND DATA INTERVAL SETTING
2635 this->command(0x50);
2636 this->data(0x97);
2637
2638 // COMMAND DATA START TRANSMISSION 1
2639 this->command(0x10);
2640 delay(2);
2641 this->start_data_();
2642 this->write_array(this->buffer_, this->get_buffer_length_());
2643 this->end_data_();
2644 delay(2);
2645 // COMMAND DATA START TRANSMISSION 2
2646 this->command(0x13);
2647 delay(2);
2648 this->start_data_();
2649 this->write_array(this->buffer_, this->get_buffer_length_());
2650 this->end_data_();
2651 // COMMAND DISPLAY REFRESH
2652 this->command(0x12);
2653}
2657 LOG_DISPLAY("", "Waveshare E-Paper", this);
2658 ESP_LOGCONFIG(TAG, " Model: 4.2in");
2659 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2660 LOG_PIN(" DC Pin: ", this->dc_pin_);
2661 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2662 LOG_UPDATE_INTERVAL(this);
2663}
2664
2665// ========================================================
2666// 4.20in Type B (LUT from OTP)
2667// Datasheet:
2668// - https://www.waveshare.com/w/upload/2/20/4.2inch-e-paper-module-user-manual-en.pdf
2669// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_4in2b_V2.c
2670// ========================================================
2672 // these exact timings are required for a proper reset/init
2673 this->reset_pin_->digital_write(false);
2674 delay(2);
2675 this->reset_pin_->digital_write(true);
2676 delay(200); // NOLINT
2677
2678 // COMMAND POWER ON
2679 this->command(0x04);
2680 this->wait_until_idle_();
2681
2682 // COMMAND PANEL SETTING
2683 this->command(0x00);
2684 this->data(0x0f); // LUT from OTP
2685}
2686
2688 // COMMAND DATA START TRANSMISSION 1 (B/W data)
2689 this->command(0x10);
2690 this->start_data_();
2691 this->write_array(this->buffer_, this->get_buffer_length_());
2692 this->end_data_();
2693
2694 // COMMAND DATA START TRANSMISSION 2 (RED data)
2695 this->command(0x13);
2696 this->start_data_();
2697 for (size_t i = 0; i < this->get_buffer_length_(); i++)
2698 this->write_byte(0xFF);
2699 this->end_data_();
2700 delay(2);
2701
2702 // COMMAND DISPLAY REFRESH
2703 this->command(0x12);
2704 this->wait_until_idle_();
2705
2706 // COMMAND POWER OFF
2707 // NOTE: power off < deep sleep
2708 this->command(0x02);
2709}
2713 LOG_DISPLAY("", "Waveshare E-Paper", this);
2714 ESP_LOGCONFIG(TAG, " Model: 4.2in (B V2)");
2715 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2716 LOG_PIN(" DC Pin: ", this->dc_pin_);
2717 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2718 LOG_UPDATE_INTERVAL(this);
2719}
2720
2721// ========================================================
2722// 4.20in Type B With Red colour support (LUT from OTP)
2723// Datasheet:
2724// - https://www.waveshare.com/w/upload/2/20/4.2inch-e-paper-module-user-manual-en.pdf
2725// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_4in2b_V2.c
2726// The implementation is an adaptation of WaveshareEPaper4P2InBV2 class
2727// ========================================================
2729 // these exact timings are required for a proper reset/init
2730 this->reset_pin_->digital_write(false);
2731 delay(2);
2732 this->reset_pin_->digital_write(true);
2733 delay(200); // NOLINT
2734
2735 // COMMAND POWER ON
2736 this->command(0x04);
2737 this->wait_until_idle_();
2738
2739 // COMMAND PANEL SETTING
2740 this->command(0x00);
2741 this->data(0x0f); // LUT from OTP
2742}
2743
2745 const uint32_t buf_len = this->get_buffer_length_() / 2u;
2746
2747 this->command(0x10); // Send BW data Transmission
2748 delay(2); // Delay to prevent Watchdog error
2749 for (uint32_t i = 0; i < buf_len; ++i) {
2750 this->data(this->buffer_[i]);
2751 }
2752
2753 this->command(0x13); // Send red data Transmission
2754 delay(2); // Delay to prevent Watchdog error
2755 for (uint32_t i = 0; i < buf_len; ++i) {
2756 // Red color need to flip bit from the buffer. Otherwise, red will conqure the screen!
2757 this->data(~this->buffer_[buf_len + i]);
2758 }
2759
2760 // COMMAND DISPLAY REFRESH
2761 this->command(0x12);
2762 this->wait_until_idle_();
2763
2764 // COMMAND POWER OFF
2765 // NOTE: power off < deep sleep
2766 this->command(0x02);
2767}
2771 LOG_DISPLAY("", "Waveshare E-Paper", this);
2772 ESP_LOGCONFIG(TAG, " Model: 4.2in (B V2) BWR-Mode");
2773 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2774 LOG_PIN(" DC Pin: ", this->dc_pin_);
2775 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2776 LOG_UPDATE_INTERVAL(this);
2777}
2778
2780 // COMMAND POWER SETTING
2781 this->command(0x01);
2782 this->data(0x37);
2783 this->data(0x00);
2784
2785 // COMMAND PANEL SETTING
2786 this->command(0x00);
2787 this->data(0xCF);
2788 this->data(0x0B);
2789
2790 // COMMAND BOOSTER SOFT START
2791 this->command(0x06);
2792 this->data(0xC7);
2793 this->data(0xCC);
2794 this->data(0x28);
2795
2796 // COMMAND POWER ON
2797 this->command(0x04);
2798 this->wait_until_idle_();
2799 delay(10);
2800
2801 // COMMAND PLL CONTROL
2802 this->command(0x30);
2803 this->data(0x3C);
2804
2805 // COMMAND TEMPERATURE SENSOR CALIBRATION
2806 this->command(0x41);
2807 this->data(0x00);
2808
2809 // COMMAND VCOM AND DATA INTERVAL SETTING
2810 this->command(0x50);
2811 this->data(0x77);
2812
2813 // COMMAND TCON SETTING
2814 this->command(0x60);
2815 this->data(0x22);
2816
2817 // COMMAND RESOLUTION SETTING
2818 this->command(0x61);
2819 this->data(0x02);
2820 this->data(0x58);
2821 this->data(0x01);
2822 this->data(0xC0);
2823
2824 // COMMAND VCM DC SETTING REGISTER
2825 this->command(0x82);
2826 this->data(0x1E);
2827
2828 this->command(0xE5);
2829 this->data(0x03);
2830}
2832 // COMMAND DATA START TRANSMISSION 1
2833 this->command(0x10);
2834
2835 this->start_data_();
2836 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
2837 uint8_t temp1 = this->buffer_[i];
2838 for (uint8_t j = 0; j < 8; j++) {
2839 uint8_t temp2;
2840 if (temp1 & 0x80) {
2841 temp2 = 0x03;
2842 } else {
2843 temp2 = 0x00;
2844 }
2845
2846 temp2 <<= 4;
2847 temp1 <<= 1;
2848 j++;
2849 if (temp1 & 0x80) {
2850 temp2 |= 0x03;
2851 } else {
2852 temp2 |= 0x00;
2853 }
2854 temp1 <<= 1;
2855 this->write_byte(temp2);
2856 }
2857
2858 App.feed_wdt();
2859 }
2860 this->end_data_();
2861
2862 // COMMAND DISPLAY REFRESH
2863 this->command(0x12);
2864}
2868 LOG_DISPLAY("", "Waveshare E-Paper", this);
2869 ESP_LOGCONFIG(TAG, " Model: 5.83in");
2870 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2871 LOG_PIN(" DC Pin: ", this->dc_pin_);
2872 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2873 LOG_UPDATE_INTERVAL(this);
2874}
2875
2876// ========================================================
2877// 5.83in V2
2878// Datasheet/Specification/Reference:
2879// - https://www.waveshare.com/w/upload/3/37/5.83inch_e-Paper_V2_Specification.pdf
2880// - https://github.com/waveshare/e-Paper/blob/master/Arduino/epd5in83_V2/epd5in83_V2.cpp
2881// ========================================================
2883 // COMMAND POWER SETTING
2884 this->command(0x01);
2885 this->data(0x07);
2886 this->data(0x07);
2887 this->data(0x3f);
2888 this->data(0x3f);
2889
2890 // COMMAND POWER ON
2891 this->command(0x04);
2892 delay(10);
2893 this->wait_until_idle_();
2894
2895 // PANNEL SETTING
2896 this->command(0x00);
2897 this->data(0x1F);
2898
2899 // COMMAND RESOLUTION SETTING
2900 this->command(0x61);
2901 this->data(0x02);
2902 this->data(0x88);
2903 this->data(0x01);
2904 this->data(0xE0);
2905
2906 this->command(0x15);
2907 this->data(0x00);
2908
2909 // COMMAND TCON SETTING
2910 this->command(0x60);
2911 this->data(0x22);
2912
2913 // Do we need this?
2914 // COMMAND PLL CONTROL
2915 this->command(0x30);
2916 this->data(0x3C); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
2917}
2919 // Reuse the code from WaveshareEPaper4P2In::display()
2920 // COMMAND VCM DC SETTING REGISTER
2921 this->command(0x82);
2922 this->data(0x12);
2923
2924 // COMMAND VCOM AND DATA INTERVAL SETTING
2925 this->command(0x50);
2926 this->data(0x97);
2927
2928 // COMMAND DATA START TRANSMISSION 1
2929 this->command(0x10);
2930 delay(2);
2931 this->start_data_();
2932 this->write_array(this->buffer_, this->get_buffer_length_());
2933 this->end_data_();
2934 delay(2);
2935
2936 // COMMAND DATA START TRANSMISSION 2
2937 this->command(0x13);
2938 delay(2);
2939 this->start_data_();
2940 this->write_array(this->buffer_, this->get_buffer_length_());
2941 this->end_data_();
2942
2943 // COMMAND DISPLAY REFRESH
2944 this->command(0x12);
2945}
2949 LOG_DISPLAY("", "Waveshare E-Paper", this);
2950 ESP_LOGCONFIG(TAG, " Model: 5.83inv2");
2951 LOG_PIN(" Reset Pin: ", this->reset_pin_);
2952 LOG_PIN(" DC Pin: ", this->dc_pin_);
2953 LOG_PIN(" Busy Pin: ", this->busy_pin_);
2954 LOG_UPDATE_INTERVAL(this);
2955}
2956
2957// ========================================================
2958// Good Display 5.83in black/white GDEY0583T81
2959// Product page:
2960// - https://www.good-display.com/product/440.html
2961// - https://www.seeedstudio.com/5-83-Monochrome-ePaper-Display-with-648x480-Pixels-p-5785.html
2962// Datasheet:
2963// -
2964// https://www.good-display.com/public/html/pdfjs/viewer/viewernew.html?file=https://v4.cecdn.yun300.cn/100001_1909185148/GDEY0583T81-new.pdf
2965// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEY0583T81-new.pdf
2966// Reference code from GoodDisplay:
2967// - https://www.good-display.com/companyfile/903.html
2968// ========================================================
2969
2971 // Allocate buffer for old data for partial updates
2972 RAMAllocator<uint8_t> allocator{};
2973 this->old_buffer_ = allocator.allocate(this->get_buffer_length_());
2974 if (this->old_buffer_ == nullptr) {
2975 ESP_LOGE(TAG, "Could not allocate old buffer for display!");
2976 return;
2977 }
2978 memset(this->old_buffer_, 0xFF, this->get_buffer_length_());
2979
2980 this->init_full_();
2981
2982 this->wait_until_idle_();
2983
2984 this->deep_sleep();
2985}
2986
2987void GDEY0583T81::power_on_() {
2988 if (!this->power_is_on_) {
2989 this->command(0x04);
2990 this->wait_until_idle_();
2991 }
2992 this->power_is_on_ = true;
2993 this->is_deep_sleep_ = false;
2994}
2995
2996void GDEY0583T81::power_off_() {
2997 this->command(0x02);
2998 this->wait_until_idle_();
2999 this->power_is_on_ = false;
3000}
3001
3003 if (this->is_deep_sleep_) {
3004 return;
3005 }
3006
3007 // VCOM and data interval setting (CDI)
3008 this->command(0x50);
3009 this->data(0xf7);
3010
3011 this->power_off_();
3012 delay(10);
3013
3014 // Deep sleep (DSLP)
3015 this->command(0x07);
3016 this->data(0xA5);
3017 this->is_deep_sleep_ = true;
3018}
3019
3020void GDEY0583T81::reset_() {
3021 if (this->reset_pin_ != nullptr) {
3022 this->reset_pin_->digital_write(false);
3023 delay(10);
3024 this->reset_pin_->digital_write(true);
3025 delay(10);
3026 }
3027}
3028
3029// Initialize for full screen update in fast mode
3030void GDEY0583T81::init_full_() {
3031 this->init_display_();
3032
3033 // Based on the GD sample code
3034 // VCOM and data interval setting (CDI)
3035 this->command(0x50);
3036 this->data(0x29);
3037 this->data(0x07);
3038
3039 // Cascade Setting (CCSET)
3040 this->command(0xE0);
3041 this->data(0x02);
3042
3043 // Force Temperature (TSSET)
3044 this->command(0xE5);
3045 this->data(0x5A);
3046}
3047
3048// Initialize for a partial update of the full screen
3049void GDEY0583T81::init_partial_() {
3050 this->init_display_();
3051
3052 // Cascade Setting (CCSET)
3053 this->command(0xE0);
3054 this->data(0x02);
3055
3056 // Force Temperature (TSSET)
3057 this->command(0xE5);
3058 this->data(0x6E);
3059}
3060
3061void GDEY0583T81::init_display_() {
3062 this->reset_();
3063
3064 // Panel Setting (PSR)
3065 this->command(0x00);
3066 // Sets: REG=0, LUT from OTP (set by CDI)
3067 // KW/R=1, Sets KW mode (Black/White)
3068 // as opposed to the default KWR mode (Black/White/Red)
3069 // UD=1, Gate Scan Direction, 1 = up (default)
3070 // SHL=1, Source Shift Direction, 1 = right (default)
3071 // SHD_N=1, Booster Switch, 1 = ON (default)
3072 // RST_N=1, Soft reset, 1 = No effect (default)
3073 this->data(0x1F);
3074
3075 // Resolution setting (TRES)
3076 this->command(0x61);
3077
3078 // Horizontal display resolution (HRES)
3079 this->data(get_width_internal() / 256);
3080 this->data(get_width_internal() % 256);
3081
3082 // Vertical display resolution (VRES)
3083 this->data(get_height_internal() / 256);
3084 this->data(get_height_internal() % 256);
3085
3086 this->power_on_();
3087}
3088
3090 bool full_update = this->at_update_ == 0;
3091 if (full_update) {
3092 this->init_full_();
3093 } else {
3094 this->init_partial_();
3095
3096 // VCOM and data interval setting (CDI)
3097 this->command(0x50);
3098 this->data(0xA9);
3099 this->data(0x07);
3100
3101 // Partial In (PTIN), makes the display enter partial mode
3102 this->command(0x91);
3103
3104 // Partial Window (PTL)
3105 // We use the full screen as the window
3106 this->command(0x90);
3107
3108 // Horizontal start/end channel bank (HRST/HRED)
3109 this->data(0);
3110 this->data(0);
3111 this->data((get_width_internal() - 1) / 256);
3112 this->data((get_width_internal() - 1) % 256);
3113
3114 // Vertical start/end line (VRST/VRED)
3115 this->data(0);
3116 this->data(0);
3117 this->data((get_height_internal() - 1) / 256);
3118 this->data((get_height_internal() - 1) % 256);
3119
3120 this->data(0x01);
3121
3122 // Display Start Transmission 1 (DTM1)
3123 // in KW mode this writes "OLD" data to SRAM
3124 this->command(0x10);
3125 this->start_data_();
3126 this->write_array(this->old_buffer_, this->get_buffer_length_());
3127 this->end_data_();
3128 }
3129
3130 // Display Start Transmission 2 (DTM2)
3131 // in KW mode this writes "NEW" data to SRAM
3132 this->command(0x13);
3133 this->start_data_();
3134 this->write_array(this->buffer_, this->get_buffer_length_());
3135 this->end_data_();
3136
3137 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
3138 this->old_buffer_[i] = this->buffer_[i];
3139 }
3140
3141 // Display Refresh (DRF)
3142 this->command(0x12);
3143 delay(10);
3144 this->wait_until_idle_();
3145
3146 if (full_update) {
3147 ESP_LOGD(TAG, "Full update done");
3148 } else {
3149 // Partial out (PTOUT), makes the display exit partial mode
3150 this->command(0x92);
3151 ESP_LOGD(TAG, "Partial update done, next full update after %" PRIu32 " cycles",
3152 this->full_update_every_ - this->at_update_ - 1);
3153 }
3154
3155 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
3156
3157 this->deep_sleep();
3158}
3159
3160void GDEY0583T81::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
3163uint32_t GDEY0583T81::idle_timeout_() { return 5000; }
3165 LOG_DISPLAY("", "GoodDisplay E-Paper", this);
3166 ESP_LOGCONFIG(TAG,
3167 " Model: 5.83in B/W GDEY0583T81\n"
3168 " Full Update Every: %" PRIu32,
3169 this->full_update_every_);
3170 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3171 LOG_PIN(" DC Pin: ", this->dc_pin_);
3172 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3173 LOG_UPDATE_INTERVAL(this);
3174}
3175
3177 // COMMAND POWER SETTING
3178 this->command(0x01);
3179 this->data(0x07);
3180 this->data(0x07); // VGH=20V,VGL=-20V
3181 this->data(0x3f); // VDH=15V
3182 this->data(0x3f); // VDL=-15V
3183 // COMMAND POWER ON
3184 this->command(0x04);
3185 delay(100); // NOLINT
3186 this->wait_until_idle_();
3187 // COMMAND PANEL SETTING
3188 this->command(0x00);
3189 this->data(0x0F); // KW3f, KWR-2F, BWROTP 0f, BWOTP 1f
3190 this->command(0x61); // tres
3191 this->data(0x03); // 800px
3192 this->data(0x20);
3193 this->data(0x01); // 400px
3194 this->data(0xE0);
3195 this->command(0x15);
3196 this->data(0x00);
3197 // COMMAND VCOM AND DATA INTERVAL SETTING
3198 this->command(0x50);
3199 this->data(0x11);
3200 this->data(0x07);
3201 // COMMAND TCON SETTING
3202 this->command(0x60);
3203 this->data(0x22);
3204
3205 this->command(0x82);
3206 this->data(0x08);
3207 this->command(0x30);
3208 this->data(0x06);
3209
3210 // COMMAND RESOLUTION SETTING
3211 this->command(0x65);
3212 this->data(0x00);
3213 this->data(0x00); // 800*480
3214 this->data(0x00);
3215 this->data(0x00);
3216}
3218 // COMMAND DATA START TRANSMISSION 1 (B/W data)
3219 this->command(0x10);
3220 delay(2);
3221 this->start_data_();
3222 this->write_array(this->buffer_, this->get_buffer_length_());
3223 this->end_data_();
3224 delay(2);
3225
3226 // COMMAND DATA START TRANSMISSION 2 (RED data)
3227 this->command(0x13);
3228 delay(2);
3229 this->start_data_();
3230 for (size_t i = 0; i < this->get_buffer_length_(); i++)
3231 this->write_byte(0x00);
3232 this->end_data_();
3233 delay(2);
3234
3235 // COMMAND DISPLAY REFRESH
3236 this->command(0x12);
3237 delay(100); // NOLINT
3238 this->wait_until_idle_();
3239 this->deep_sleep();
3240}
3244 LOG_DISPLAY("", "Waveshare E-Paper", this);
3245 ESP_LOGCONFIG(TAG, " Model: 7.5in-bv2");
3246 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3247 LOG_PIN(" DC Pin: ", this->dc_pin_);
3248 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3249 LOG_UPDATE_INTERVAL(this);
3250}
3251
3254 if (this->busy_pin_ == nullptr) {
3255 return true;
3256 }
3257
3258 const uint32_t start = millis();
3259 while (this->busy_pin_->digital_read()) {
3260 this->command(0x71);
3261 if (millis() - start > this->idle_timeout_()) {
3262 ESP_LOGI(TAG, "Timeout while displaying image!");
3263 return false;
3264 }
3265 App.feed_wdt();
3266 delay(10);
3267 }
3268 delay(200); // NOLINT
3269 return true;
3270};
3272 this->reset_();
3273
3274 // COMMAND POWER SETTING
3275 this->command(0x01);
3276
3277 // 1-0=11: internal power
3278 this->data(0x07);
3279 this->data(0x17); // VGH&VGL
3280 this->data(0x3F); // VSH
3281 this->data(0x26); // VSL
3282 this->data(0x11); // VSHR
3283
3284 // VCOM DC Setting
3285 this->command(0x82);
3286 this->data(0x24); // VCOM
3287
3288 // Booster Setting
3289 this->command(0x06);
3290 this->data(0x27);
3291 this->data(0x27);
3292 this->data(0x2F);
3293 this->data(0x17);
3294
3295 // POWER ON
3296 this->command(0x04);
3297
3298 delay(100); // NOLINT
3299 this->wait_until_idle_();
3300 // COMMAND PANEL SETTING
3301 this->command(0x00);
3302 this->data(0x3F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
3303
3304 // COMMAND RESOLUTION SETTING
3305 this->command(0x61);
3306 this->data(0x03); // source 800
3307 this->data(0x20);
3308 this->data(0x01); // gate 480
3309 this->data(0xE0);
3310 // COMMAND ...?
3311 this->command(0x15);
3312 this->data(0x00);
3313 // COMMAND VCOM AND DATA INTERVAL SETTING
3314 this->command(0x50);
3315 this->data(0x10);
3316 this->data(0x00);
3317 // COMMAND TCON SETTING
3318 this->command(0x60);
3319 this->data(0x22);
3320 // Resolution setting
3321 this->command(0x65);
3322 this->data(0x00);
3323 this->data(0x00); // 800*480
3324 this->data(0x00);
3325 this->data(0x00);
3326
3327 uint8_t lut_vcom_7_i_n5_v2[] = {
3328 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3329 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3330 };
3331
3332 uint8_t lut_ww_7_i_n5_v2[] = {
3333 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3334 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3335 };
3336
3337 uint8_t lut_bw_7_i_n5_v2[] = {
3338 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3339 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3340 };
3341
3342 uint8_t lut_wb_7_i_n5_v2[] = {
3343 0x80, 0xF, 0xF, 0x0, 0x0, 0x3, 0x84, 0xF, 0x1, 0xF, 0x1, 0x4, 0x40, 0xF, 0xF, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0,
3344 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3345 };
3346
3347 uint8_t lut_bb_7_i_n5_v2[] = {
3348 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
3349 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
3350 };
3351
3352 uint8_t count;
3353 this->command(0x20); // VCOM
3354 for (count = 0; count < 42; count++)
3355 this->data(lut_vcom_7_i_n5_v2[count]);
3356
3357 this->command(0x21); // LUTBW
3358 for (count = 0; count < 42; count++)
3359 this->data(lut_ww_7_i_n5_v2[count]);
3360
3361 this->command(0x22); // LUTBW
3362 for (count = 0; count < 42; count++)
3363 this->data(lut_bw_7_i_n5_v2[count]);
3364
3365 this->command(0x23); // LUTWB
3366 for (count = 0; count < 42; count++)
3367 this->data(lut_wb_7_i_n5_v2[count]);
3368
3369 this->command(0x24); // LUTBB
3370 for (count = 0; count < 42; count++)
3371 this->data(lut_bb_7_i_n5_v2[count]);
3372};
3374 this->init_display_();
3375 uint32_t buf_len = this->get_buffer_length_();
3376
3377 this->command(0x10);
3378 for (uint32_t i = 0; i < buf_len; i++) {
3379 this->data(0xFF);
3380 }
3381
3382 this->command(0x13); // Start Transmission
3383 delay(2);
3384 for (uint32_t i = 0; i < buf_len; i++) {
3385 this->data(~this->buffer_[i]);
3386 }
3387
3388 this->command(0x12); // Display Refresh
3389 delay(100); // NOLINT
3390 this->wait_until_idle_();
3391 this->deep_sleep();
3392}
3396 LOG_DISPLAY("", "Waveshare E-Paper", this);
3397 ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3");
3398 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3399 LOG_PIN(" DC Pin: ", this->dc_pin_);
3400 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3401 LOG_UPDATE_INTERVAL(this);
3402}
3403
3406 if (this->busy_pin_ == nullptr) {
3407 return true;
3408 }
3409
3410 const uint32_t start = millis();
3411 while (this->busy_pin_->digital_read()) {
3412 this->command(0x71);
3413 if (millis() - start > this->idle_timeout_()) {
3414 ESP_LOGI(TAG, "Timeout while displaying image!");
3415 return false;
3416 }
3417 App.feed_wdt();
3418 delay(10);
3419 }
3420 delay(200); // NOLINT
3421 return true;
3422};
3424 this->reset_();
3425
3426 // COMMAND POWER SETTING
3427 this->command(0x01);
3428
3429 // 1-0=11: internal power
3430 this->data(0x07); // VRS_EN=1, VS_EN=1, VG_EN=1
3431 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
3432 this->data(0x3F); // VSH=15V?
3433 this->data(0x26); // VSL=-9.4V?
3434 this->data(0x11); // VSHR=5.8V?
3435
3436 // VCOM DC Setting
3437 this->command(0x82);
3438 this->data(0x24); // VCOM=-1.9V
3439
3440 // POWER ON
3441 this->command(0x04);
3442 delay(100); // NOLINT
3443 this->wait_until_idle_();
3444
3445 // COMMAND PANEL SETTING
3446 this->command(0x00);
3447 this->data(0x0F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
3448
3449 // COMMAND RESOLUTION SETTING
3450 this->command(0x61);
3451 this->data(0x03); // source 800
3452 this->data(0x20);
3453 this->data(0x01); // gate 480
3454 this->data(0xE0);
3455
3456 // COMMAND VCOM AND DATA INTERVAL SETTING
3457 this->command(0x50);
3458 this->data(0x20);
3459 this->data(0x00);
3460
3461 // COMMAND TCON SETTING
3462 this->command(0x60);
3463 this->data(0x22);
3464
3465 // Resolution setting
3466 this->command(0x65);
3467 this->data(0x00);
3468 this->data(0x00); // 800*480
3469 this->data(0x00);
3470 this->data(0x00);
3471};
3473 this->init_display_();
3474 const uint32_t buf_len = this->get_buffer_length_() / 2u;
3475
3476 this->command(0x10); // Send BW data Transmission
3477 delay(2);
3478 for (uint32_t i = 0; i < buf_len; i++) {
3479 this->data(this->buffer_[i]);
3480 }
3481
3482 this->command(0x13); // Send red data Transmission
3483 delay(2);
3484 for (uint32_t i = 0; i < buf_len; i++) {
3485 this->data(this->buffer_[i + buf_len]);
3486 }
3487
3488 this->command(0x12); // Display Refresh
3489 delay(100); // NOLINT
3490 this->wait_until_idle_();
3491 this->deep_sleep();
3492}
3496 LOG_DISPLAY("", "Waveshare E-Paper", this);
3497 ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3 BWR-Mode");
3498 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3499 LOG_PIN(" DC Pin: ", this->dc_pin_);
3500 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3501 LOG_UPDATE_INTERVAL(this);
3502}
3503
3505 // COMMAND POWER SETTING
3506 this->command(0x01);
3507 this->data(0x37);
3508 this->data(0x00);
3509 // COMMAND PANEL SETTING
3510 this->command(0x00);
3511 this->data(0xCF);
3512 this->data(0x0B);
3513 // COMMAND BOOSTER SOFT START
3514 this->command(0x06);
3515 this->data(0xC7);
3516 this->data(0xCC);
3517 this->data(0x28);
3518 // COMMAND POWER ON
3519 this->command(0x04);
3520 this->wait_until_idle_();
3521 delay(10);
3522 // COMMAND PLL CONTROL
3523 this->command(0x30);
3524 this->data(0x3C);
3525 // COMMAND TEMPERATURE SENSOR CALIBRATION
3526 this->command(0x41);
3527 this->data(0x00);
3528 // COMMAND VCOM AND DATA INTERVAL SETTING
3529 this->command(0x50);
3530 this->data(0x77);
3531 // COMMAND TCON SETTING
3532 this->command(0x60);
3533 this->data(0x22);
3534 // COMMAND RESOLUTION SETTING
3535 this->command(0x61);
3536 this->data(0x02);
3537 this->data(0x80);
3538 this->data(0x01);
3539 this->data(0x80);
3540 // COMMAND VCM DC SETTING REGISTER
3541 this->command(0x82);
3542 this->data(0x1E);
3543 this->command(0xE5);
3544 this->data(0x03);
3545}
3547 // COMMAND DATA START TRANSMISSION 1
3548 this->command(0x10);
3549 this->start_data_();
3550 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
3551 uint8_t temp1 = this->buffer_[i];
3552 for (uint8_t j = 0; j < 8; j++) {
3553 uint8_t temp2;
3554 if (temp1 & 0x80) {
3555 temp2 = 0x03;
3556 } else {
3557 temp2 = 0x00;
3558 }
3559 temp2 <<= 4;
3560 temp1 <<= 1;
3561 j++;
3562 if (temp1 & 0x80) {
3563 temp2 |= 0x03;
3564 } else {
3565 temp2 |= 0x00;
3566 }
3567 temp1 <<= 1;
3568 this->write_byte(temp2);
3569 }
3570 App.feed_wdt();
3571 }
3572 this->end_data_();
3573 // COMMAND DISPLAY REFRESH
3574 this->command(0x12);
3575}
3579 LOG_DISPLAY("", "Waveshare E-Paper", this);
3580 ESP_LOGCONFIG(TAG, " Model: 7.5in");
3581 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3582 LOG_PIN(" DC Pin: ", this->dc_pin_);
3583 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3584 LOG_UPDATE_INTERVAL(this);
3585}
3586
3587// Waveshare 5.65F ========================================================
3588
3589namespace cmddata_5P65InF {
3590// WaveshareEPaper5P65InF commands
3591// https://www.waveshare.com/wiki/5.65inch_e-Paper_Module_(F)
3592
3593// R00H (PSR): Panel setting Register
3594// UD(1): scan up
3595// SHL(1) shift right
3596// SHD_N(1) DC-DC on
3597// RST_N(1) no reset
3598static const uint8_t R00_CMD_PSR[] = {0x00, 0xEF, 0x08};
3599
3600// R01H (PWR): Power setting Register
3601// internal DC-DC power generation
3602static const uint8_t R01_CMD_PWR[] = {0x01, 0x07, 0x00, 0x00, 0x00};
3603
3604// R02H (POF): Power OFF Command
3605static const uint8_t R02_CMD_POF[] = {0x02};
3606
3607// R03H (PFS): Power off sequence setting Register
3608// T_VDS_OFF (00) = 1 frame
3609static const uint8_t R03_CMD_PFS[] = {0x03, 0x00};
3610
3611// R04H (PON): Power ON Command
3612static const uint8_t R04_CMD_PON[] = {0x04};
3613
3614// R06h (BTST): Booster Soft Start
3615static const uint8_t R06_CMD_BTST[] = {0x06, 0xC7, 0xC7, 0x1D};
3616
3617// R07H (DSLP): Deep sleep#
3618// Note Documentation @ Waveshare shows cmd code as 0x10 in table, but
3619// 0x10 is DTM1.
3620static const uint8_t R07_CMD_DSLP[] = {0x07, 0xA5};
3621
3622// R10H (DTM1): Data Start Transmission 1
3623
3624static const uint8_t R10_CMD_DTM1[] = {0x10};
3625
3626// R11H (DSP): Data Stop
3627static const uint8_t R11_CMD_DSP[] = {0x11};
3628
3629// R12H (DRF): Display Refresh
3630static const uint8_t R12_CMD_DRF[] = {0x12};
3631
3632// R13H (IPC): Image Process Command
3633static const uint8_t R13_CMD_IPC[] = {0x13, 0x00};
3634
3635// R30H (PLL): PLL Control
3636// 0x3C = 50Hz
3637static const uint8_t R30_CMD_PLL[] = {0x30, 0x3C};
3638
3639// R41H (TSE): Temperature Sensor Enable
3640// TSE(0) enable, TO(0000) +0 degree offset
3641static const uint8_t R41_CMD_TSE[] = {0x41, 0x00};
3642
3643// R50H (CDI) VCOM and Data interval setting
3644// CDI(0111) 10
3645// DDX(1), VBD(001) Border output "White"
3646static const uint8_t R50_CMD_CDI[] = {0x50, 0x37};
3647
3648// R60H (TCON) Gate and Source non overlap period command
3649// S2G(10) 12 units
3650// G2S(10) 12 units
3651static const uint8_t R60_CMD_TCON[] = {0x60, 0x22};
3652
3653// R61H (TRES) Resolution Setting
3654// 0x258 = 600
3655// 0x1C0 = 448
3656static const uint8_t R61_CMD_TRES[] = {0x61, 0x02, 0x58, 0x01, 0xC0};
3657
3658// RE3H (PWS) Power Savings
3659static const uint8_t RE3_CMD_PWS[] = {0xE3, 0xAA};
3660} // namespace cmddata_5P65InF
3661
3663 if (this->buffers_[0] == nullptr) {
3664 ESP_LOGE(TAG, "Buffer unavailable!");
3665 return;
3666 }
3667
3668 this->reset_();
3669 delay(20);
3670 this->wait_until_(IDLE);
3671
3672 using namespace cmddata_5P65InF;
3673
3674 this->cmd_data(R00_CMD_PSR, sizeof(R00_CMD_PSR));
3675 this->cmd_data(R01_CMD_PWR, sizeof(R01_CMD_PWR));
3676 this->cmd_data(R03_CMD_PFS, sizeof(R03_CMD_PFS));
3677 this->cmd_data(R06_CMD_BTST, sizeof(R06_CMD_BTST));
3678 this->cmd_data(R30_CMD_PLL, sizeof(R30_CMD_PLL));
3679 this->cmd_data(R41_CMD_TSE, sizeof(R41_CMD_TSE));
3680 this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
3681 this->cmd_data(R60_CMD_TCON, sizeof(R60_CMD_TCON));
3682 this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
3683 this->cmd_data(RE3_CMD_PWS, sizeof(RE3_CMD_PWS));
3684
3685 delay(100); // NOLINT
3686 this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
3687
3688 ESP_LOGI(TAG, "Display initialized successfully");
3689}
3690
3692 // INITIALIZATION
3693 ESP_LOGI(TAG, "Initialise the display");
3694 this->initialize();
3695
3696 using namespace cmddata_5P65InF;
3697
3698 // COMMAND DATA START TRANSMISSION
3699 ESP_LOGI(TAG, "Sending data to the display");
3700 this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
3701 this->cmd_data(R10_CMD_DTM1, sizeof(R10_CMD_DTM1));
3702 this->send_buffers_();
3703
3704 // COMMAND POWER ON
3705 ESP_LOGI(TAG, "Power on the display");
3706 this->cmd_data(R04_CMD_PON, sizeof(R04_CMD_PON));
3707 this->wait_until_(IDLE);
3708
3709 // COMMAND REFRESH SCREEN
3710 ESP_LOGI(TAG, "Refresh the display");
3711 this->cmd_data(R12_CMD_DRF, sizeof(R12_CMD_DRF));
3712 this->wait_until_(IDLE);
3713
3714 // COMMAND POWER OFF
3715 ESP_LOGI(TAG, "Power off the display");
3716 this->cmd_data(R02_CMD_POF, sizeof(R02_CMD_POF));
3717 this->wait_until_(BUSY);
3718
3719 if (this->deep_sleep_between_updates_) {
3720 ESP_LOGI(TAG, "Set the display to deep sleep");
3721 this->cmd_data(R07_CMD_DSLP, sizeof(R07_CMD_DSLP));
3722 }
3723}
3724
3727uint32_t WaveshareEPaper5P65InF::idle_timeout_() { return 35000; }
3728
3730 LOG_DISPLAY("", "Waveshare E-Paper", this);
3731 ESP_LOGCONFIG(TAG, " Model: 5.65in-F");
3732 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3733 LOG_PIN(" DC Pin: ", this->dc_pin_);
3734 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3735 LOG_UPDATE_INTERVAL(this);
3736}
3737
3739 if (this->busy_pin_ == nullptr) {
3740 return true;
3741 }
3742
3743 const uint32_t start = millis();
3744 while (busy_state != this->busy_pin_->digital_read()) {
3745 if (millis() - start > this->idle_timeout_()) {
3746 ESP_LOGE(TAG, "Timeout while displaying image!");
3747 return false;
3748 }
3749 App.feed_wdt();
3750 delay(10);
3751 }
3752 return true;
3753}
3754
3756 if (this->buffers_[0] == nullptr) {
3757 ESP_LOGE(TAG, "Buffer unavailable!");
3758 return;
3759 }
3760
3761 this->reset_();
3762 delay(20);
3763 this->wait_until_idle_();
3764
3765 // COMMAND CMDH
3766 this->command(0xAA);
3767 this->data(0x49);
3768 this->data(0x55);
3769 this->data(0x20);
3770 this->data(0x08);
3771 this->data(0x09);
3772 this->data(0x18);
3773
3774 this->command(0x01);
3775 this->data(0x3F);
3776 this->data(0x00);
3777 this->data(0x32);
3778 this->data(0x2A);
3779 this->data(0x0E);
3780 this->data(0x2A);
3781
3782 this->command(0x00);
3783 this->data(0x5F);
3784 this->data(0x69);
3785
3786 this->command(0x03);
3787 this->data(0x00);
3788 this->data(0x54);
3789 this->data(0x00);
3790 this->data(0x44);
3791
3792 this->command(0x05);
3793 this->data(0x40);
3794 this->data(0x1F);
3795 this->data(0x1F);
3796 this->data(0x2C);
3797
3798 this->command(0x06);
3799 this->data(0x6F);
3800 this->data(0x1F);
3801 this->data(0x1F);
3802 this->data(0x22);
3803
3804 this->command(0x08);
3805 this->data(0x6F);
3806 this->data(0x1F);
3807 this->data(0x1F);
3808 this->data(0x22);
3809
3810 // COMMAND IPC
3811 this->command(0x13);
3812 this->data(0x00);
3813 this->data(0x04);
3814
3815 this->command(0x30);
3816 this->data(0x3C);
3817
3818 // COMMAND TSE
3819 this->command(0x41);
3820 this->data(0x00);
3821
3822 this->command(0x50);
3823 this->data(0x3F);
3824
3825 this->command(0x60);
3826 this->data(0x02);
3827 this->data(0x00);
3828
3829 this->command(0x61);
3830 this->data(0x03);
3831 this->data(0x20);
3832 this->data(0x01);
3833 this->data(0xE0);
3834
3835 this->command(0x82);
3836 this->data(0x1E);
3837
3838 this->command(0x84);
3839 this->data(0x00);
3840
3841 // COMMAND AGID
3842 this->command(0x86);
3843 this->data(0x00);
3844
3845 this->command(0xE3);
3846 this->data(0x2F);
3847
3848 // COMMAND CCSET
3849 this->command(0xE0);
3850 this->data(0x00);
3851
3852 // COMMAND TSSET
3853 this->command(0xE6);
3854 this->data(0x00);
3855
3856 ESP_LOGI(TAG, "Display initialized successfully");
3857}
3859 // INITIALIZATION
3860 ESP_LOGI(TAG, "Initialise the display");
3861 this->initialize();
3862
3863 // COMMAND DATA START TRANSMISSION
3864 ESP_LOGI(TAG, "Sending data to the display");
3865 this->command(0x10);
3866 this->send_buffers_();
3867
3868 // COMMAND POWER ON
3869 ESP_LOGI(TAG, "Power on the display");
3870 this->command(0x04);
3871 this->wait_until_idle_();
3872
3873 // COMMAND REFRESH SCREEN
3874 ESP_LOGI(TAG, "Refresh the display");
3875 this->command(0x12);
3876 this->data(0x00);
3877 this->wait_until_idle_();
3878
3879 // COMMAND POWER OFF
3880 ESP_LOGI(TAG, "Power off the display");
3881 this->command(0x02);
3882 this->data(0x00);
3883 this->wait_until_idle_();
3884
3885 if (this->deep_sleep_between_updates_) {
3886 ESP_LOGI(TAG, "Set the display to deep sleep");
3887 this->command(0x07);
3888 this->data(0xA5);
3889 }
3890}
3893uint32_t WaveshareEPaper7P3InF::idle_timeout_() { return 35000; }
3895 LOG_DISPLAY("", "Waveshare E-Paper", this);
3896 ESP_LOGCONFIG(TAG, " Model: 7.3in-F");
3897 LOG_PIN(" Reset Pin: ", this->reset_pin_);
3898 LOG_PIN(" DC Pin: ", this->dc_pin_);
3899 LOG_PIN(" Busy Pin: ", this->busy_pin_);
3900 LOG_UPDATE_INTERVAL(this);
3901}
3902
3904 if (this->busy_pin_ == nullptr) {
3905 return true;
3906 }
3907 const uint32_t start = millis();
3908 while (this->busy_pin_->digital_read()) {
3909 if (millis() - start > this->idle_timeout_()) {
3910 ESP_LOGE(TAG, "Timeout while displaying image!");
3911 return false;
3912 }
3913 App.feed_wdt();
3914 delay(10);
3915 }
3916 delay(200); // NOLINT
3917 return true;
3918}
3920 if (this->busy_pin_ == nullptr) {
3921 return true;
3922 }
3923
3924 const uint32_t start = millis();
3925 while (this->busy_pin_->digital_read()) {
3926 this->command(0x71);
3927 if (millis() - start > this->idle_timeout_()) {
3928 ESP_LOGE(TAG, "Timeout while displaying image!");
3929 return false;
3930 }
3931 App.feed_wdt();
3932 delay(10);
3933 }
3934 return true;
3935}
3937 // COMMAND POWER SETTING
3938 this->command(0x01);
3939 this->data(0x07);
3940 this->data(0x07);
3941 this->data(0x3f);
3942 this->data(0x3f);
3943
3944 // We don't want the display to be powered at this point
3945
3946 delay(100); // NOLINT
3947 this->wait_until_idle_();
3948
3949 // COMMAND VCOM AND DATA INTERVAL SETTING
3950 this->command(0x50);
3951 this->data(0x10);
3952 this->data(0x07);
3953
3954 // COMMAND TCON SETTING
3955 this->command(0x60);
3956 this->data(0x22);
3957
3958 // COMMAND PANEL SETTING
3959 this->command(0x00);
3960 this->data(0x1F);
3961
3962 // COMMAND RESOLUTION SETTING
3963 this->command(0x61);
3964 this->data(0x03);
3965 this->data(0x20);
3966 this->data(0x01);
3967 this->data(0xE0);
3968
3969 // COMMAND DUAL SPI MM_EN, DUSPI_EN
3970 this->command(0x15);
3971 this->data(0x00);
3972
3973 // COMMAND POWER DRIVER HAT DOWN
3974 // This command will turn off booster, controller, source driver, gate driver, VCOM, and
3975 // temperature sensor, but register data will be kept until VDD turned OFF or Deep Sleep Mode.
3976 // Source/Gate/Border/VCOM will be released to floating.
3977 this->command(0x02);
3978}
3980 uint32_t buf_len = this->get_buffer_length_();
3981
3982 // COMMAND POWER ON
3983 ESP_LOGI(TAG, "Power on the display and hat");
3984
3985 // This command will turn on booster, controller, regulators, and temperature sensor will be
3986 // activated for one-time sensing before enabling booster. When all voltages are ready, the
3987 // BUSY_N signal will return to high.
3988 this->command(0x04);
3989 delay(200); // NOLINT
3990 this->wait_until_idle_();
3991
3992 // COMMAND DATA START TRANSMISSION NEW DATA
3993 this->command(0x13);
3994 delay(2);
3995 for (uint32_t i = 0; i < buf_len; i++) {
3996 this->data(~(this->buffer_[i]));
3997 }
3998
3999 delay(100); // NOLINT
4000 this->wait_until_idle_();
4001
4002 // COMMAND DISPLAY REFRESH
4003 this->command(0x12);
4004 delay(100); // NOLINT
4005 this->wait_until_idle_();
4006
4007 ESP_LOGV(TAG, "Before command(0x02) (>> power off)");
4008 this->command(0x02);
4009 this->wait_until_idle_();
4010 ESP_LOGV(TAG, "After command(0x02) (>> power off)");
4011}
4012
4015uint32_t WaveshareEPaper7P5InV2::idle_timeout_() { return 10000; }
4017 LOG_DISPLAY("", "Waveshare E-Paper", this);
4018 ESP_LOGCONFIG(TAG, " Model: 7.5inV2rev2");
4019 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4020 LOG_PIN(" DC Pin: ", this->dc_pin_);
4021 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4022 LOG_UPDATE_INTERVAL(this);
4023}
4024
4025/* 7.50inV2alt */
4027 if (this->busy_pin_ == nullptr) {
4028 return true;
4029 }
4030
4031 const uint32_t start = millis();
4032 while (this->busy_pin_->digital_read()) {
4033 this->command(0x71);
4034 if (millis() - start > this->idle_timeout_()) {
4035 ESP_LOGI(TAG, "Timeout while displaying image!");
4036 return false;
4037 }
4038 delay(10);
4039 }
4040 return true;
4041}
4042
4044 this->reset_();
4045
4046 // COMMAND POWER SETTING
4047 this->command(0x01);
4048
4049 // 1-0=11: internal power
4050 this->data(0x07);
4051 this->data(0x17); // VGH&VGL
4052 this->data(0x3F); // VSH
4053 this->data(0x26); // VSL
4054 this->data(0x11); // VSHR
4055
4056 // VCOM DC Setting
4057 this->command(0x82);
4058 this->data(0x24); // VCOM
4059
4060 // Booster Setting
4061 this->command(0x06);
4062 this->data(0x27);
4063 this->data(0x27);
4064 this->data(0x2F);
4065 this->data(0x17);
4066
4067 // POWER ON
4068 this->command(0x04);
4069
4070 delay(100); // NOLINT
4071 this->wait_until_idle_();
4072 // COMMAND PANEL SETTING
4073 this->command(0x00);
4074 this->data(0x3F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
4075
4076 // COMMAND RESOLUTION SETTING
4077 this->command(0x61);
4078 this->data(0x03); // source 800
4079 this->data(0x20);
4080 this->data(0x01); // gate 480
4081 this->data(0xE0);
4082 // COMMAND ...?
4083 this->command(0x15);
4084 this->data(0x00);
4085 // COMMAND VCOM AND DATA INTERVAL SETTING
4086 this->command(0x50);
4087 this->data(0x10);
4088 this->data(0x00);
4089 // COMMAND TCON SETTING
4090 this->command(0x60);
4091 this->data(0x22);
4092 // Resolution setting
4093 this->command(0x65);
4094 this->data(0x00);
4095 this->data(0x00); // 800*480
4096 this->data(0x00);
4097 this->data(0x00);
4098
4099 this->wait_until_idle_();
4100
4101 uint8_t lut_vcom_7_i_n5_v2[] = {
4102 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4103 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4104 };
4105
4106 uint8_t lut_ww_7_i_n5_v2[] = {
4107 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4108 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4109 };
4110
4111 uint8_t lut_bw_7_i_n5_v2[] = {
4112 0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4113 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4114 };
4115
4116 uint8_t lut_wb_7_i_n5_v2[] = {
4117 0x80, 0xF, 0xF, 0x0, 0x0, 0x3, 0x84, 0xF, 0x1, 0xF, 0x1, 0x4, 0x40, 0xF, 0xF, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0,
4118 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4119 };
4120
4121 uint8_t lut_bb_7_i_n5_v2[] = {
4122 0x80, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
4123 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4124 };
4125
4126 uint8_t count;
4127 this->command(0x20); // VCOM
4128 for (count = 0; count < 42; count++)
4129 this->data(lut_vcom_7_i_n5_v2[count]);
4130
4131 this->command(0x21); // LUTBW
4132 for (count = 0; count < 42; count++)
4133 this->data(lut_ww_7_i_n5_v2[count]);
4134
4135 this->command(0x22); // LUTBW
4136 for (count = 0; count < 42; count++)
4137 this->data(lut_bw_7_i_n5_v2[count]);
4138
4139 this->command(0x23); // LUTWB
4140 for (count = 0; count < 42; count++)
4141 this->data(lut_wb_7_i_n5_v2[count]);
4142
4143 this->command(0x24); // LUTBB
4144 for (count = 0; count < 42; count++)
4145 this->data(lut_bb_7_i_n5_v2[count]);
4146}
4147
4149 LOG_DISPLAY("", "Waveshare E-Paper", this);
4150 ESP_LOGCONFIG(TAG, " Model: 7.5inV2");
4151 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4152 LOG_PIN(" DC Pin: ", this->dc_pin_);
4153 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4154 LOG_UPDATE_INTERVAL(this);
4155}
4156
4157/* 7.50inV2 with partial and fast refresh */
4159 if (this->busy_pin_ == nullptr) {
4160 return true;
4161 }
4162
4163 const uint32_t start = millis();
4164 while (this->busy_pin_->digital_read()) {
4165 this->command(0x71);
4166 if (millis() - start > this->idle_timeout_()) {
4167 ESP_LOGE(TAG, "Timeout while displaying image!");
4168 return false;
4169 }
4170 App.feed_wdt();
4171 delay(10);
4172 }
4173 return true;
4174}
4175
4176void WaveshareEPaper7P5InV2P::reset_() {
4177 if (this->reset_pin_ != nullptr) {
4178 this->reset_pin_->digital_write(true);
4179 delay(20);
4180 this->reset_pin_->digital_write(false);
4181 delay(2);
4182 this->reset_pin_->digital_write(true);
4183 delay(20);
4184 }
4185}
4186
4187void WaveshareEPaper7P5InV2P::turn_on_display_() {
4188 this->command(0x12);
4189 delay(100); // NOLINT
4190 this->wait_until_idle_();
4191}
4192
4194 this->reset_();
4195
4196 // COMMAND POWER SETTING
4197 this->command(0x01);
4198 this->data(0x07);
4199 this->data(0x07);
4200 this->data(0x3f);
4201 this->data(0x3f);
4202
4203 // COMMAND BOOSTER SOFT START
4204 this->command(0x06);
4205 this->data(0x17);
4206 this->data(0x17);
4207 this->data(0x28);
4208 this->data(0x17);
4209
4210 // COMMAND POWER DRIVER HAT UP
4211 this->command(0x04);
4212 delay(100); // NOLINT
4213 this->wait_until_idle_();
4214
4215 // COMMAND PANEL SETTING
4216 this->command(0x00);
4217 this->data(0x1F);
4218
4219 // COMMAND RESOLUTION SETTING
4220 this->command(0x61);
4221 this->data(0x03);
4222 this->data(0x20);
4223 this->data(0x01);
4224 this->data(0xE0);
4225
4226 // COMMAND DUAL SPI MM_EN, DUSPI_EN
4227 this->command(0x15);
4228 this->data(0x00);
4229
4230 // COMMAND VCOM AND DATA INTERVAL SETTING
4231 this->command(0x50);
4232 this->data(0x10);
4233 this->data(0x07);
4234
4235 // COMMAND TCON SETTING
4236 this->command(0x60);
4237 this->data(0x22);
4238
4239 // COMMAND ENABLE FAST UPDATE
4240 this->command(0xE0);
4241 this->data(0x02);
4242 this->command(0xE5);
4243 this->data(0x5A);
4244
4245 // COMMAND POWER DRIVER HAT DOWN
4246 this->command(0x02);
4247}
4248
4250 uint32_t buf_len = this->get_buffer_length_();
4251
4252 // COMMAND POWER ON
4253 ESP_LOGI(TAG, "Power on the display and hat");
4254
4255 this->command(0x04);
4256 delay(200); // NOLINT
4257 this->wait_until_idle_();
4258
4259 if (this->full_update_every_ == 1) {
4260 this->command(0x13);
4261 for (uint32_t i = 0; i < buf_len; i++) {
4262 this->data(~(this->buffer_[i]));
4263 }
4264
4265 this->turn_on_display_();
4266
4267 this->command(0x02);
4268 this->wait_until_idle_();
4269 return;
4270 }
4271
4272 this->command(0x50);
4273 this->data(0xA9);
4274 this->data(0x07);
4275
4276 if (this->at_update_ == 0) {
4277 // Enable fast refresh
4278 this->command(0xE5);
4279 this->data(0x5A);
4280
4281 this->command(0x92);
4282
4283 this->command(0x10);
4284 delay(2);
4285 for (uint32_t i = 0; i < buf_len; i++) {
4286 this->data(~(this->buffer_[i]));
4287 }
4288
4289 delay(100); // NOLINT
4290 this->wait_until_idle_();
4291
4292 this->command(0x13);
4293 delay(2);
4294 for (uint32_t i = 0; i < buf_len; i++) {
4295 this->data(this->buffer_[i]);
4296 }
4297
4298 delay(100); // NOLINT
4299 this->wait_until_idle_();
4300
4301 this->turn_on_display_();
4302
4303 } else {
4304 // Enable partial refresh
4305 this->command(0xE5);
4306 this->data(0x6E);
4307
4308 // Activate partial refresh and set window bounds
4309 this->command(0x91);
4310 this->command(0x90);
4311
4312 this->data(0x00);
4313 this->data(0x00);
4314 this->data((get_width_internal() - 1) >> 8 & 0xFF);
4315 this->data((get_width_internal() - 1) & 0xFF);
4316
4317 this->data(0x00);
4318 this->data(0x00);
4319 this->data((get_height_internal() - 1) >> 8 & 0xFF);
4320 this->data((get_height_internal() - 1) & 0xFF);
4321
4322 this->data(0x01);
4323
4324 this->command(0x13);
4325 delay(2);
4326 for (uint32_t i = 0; i < buf_len; i++) {
4327 this->data(this->buffer_[i]);
4328 }
4329
4330 delay(100); // NOLINT
4331 this->wait_until_idle_();
4332
4333 this->turn_on_display_();
4334 }
4335
4336 ESP_LOGV(TAG, "Before command(0x02) (>> power off)");
4337 this->command(0x02);
4338 this->wait_until_idle_();
4339 ESP_LOGV(TAG, "After command(0x02) (>> power off)");
4340
4341 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
4342}
4343
4346uint32_t WaveshareEPaper7P5InV2P::idle_timeout_() { return 10000; }
4348 LOG_DISPLAY("", "Waveshare E-Paper", this);
4349 ESP_LOGCONFIG(TAG,
4350 " Model: 7.50inv2p\n"
4351 " Full Update Every: %" PRIu32,
4352 this->full_update_every_);
4353 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4354 LOG_PIN(" DC Pin: ", this->dc_pin_);
4355 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4356 LOG_UPDATE_INTERVAL(this);
4357}
4358void WaveshareEPaper7P5InV2P::set_full_update_every(uint32_t full_update_every) {
4359 this->full_update_every_ = full_update_every;
4360}
4361
4362/* 7.50in-bc */
4364 /* The command sequence is similar to the 7P5In display but differs in subtle ways
4365 to allow for faster updates. */
4366 // COMMAND POWER SETTING
4367 this->command(0x01);
4368 this->data(0x37);
4369 this->data(0x00);
4370
4371 // COMMAND PANEL SETTING
4372 this->command(0x00);
4373 this->data(0xCF);
4374 this->data(0x08);
4375
4376 // COMMAND PLL CONTROL
4377 this->command(0x30);
4378 this->data(0x3A);
4379
4380 // COMMAND VCM_DC_SETTING: all temperature range
4381 this->command(0x82);
4382 this->data(0x28);
4383
4384 // COMMAND BOOSTER SOFT START
4385 this->command(0x06);
4386 this->data(0xC7);
4387 this->data(0xCC);
4388 this->data(0x15);
4389
4390 // COMMAND VCOM AND DATA INTERVAL SETTING
4391 this->command(0x50);
4392 this->data(0x77);
4393
4394 // COMMAND TCON SETTING
4395 this->command(0x60);
4396 this->data(0x22);
4397
4398 // COMMAND FLASH CONTROL
4399 this->command(0x65);
4400 this->data(0x00);
4401
4402 // COMMAND RESOLUTION SETTING
4403 this->command(0x61);
4404 this->data(0x02); // 640 >> 8
4405 this->data(0x80);
4406 this->data(0x01); // 384 >> 8
4407 this->data(0x80);
4408
4409 // COMMAND FLASH MODE
4410 this->command(0xE5);
4411 this->data(0x03);
4412}
4413
4415 // COMMAND DATA START TRANSMISSION 1
4416 this->command(0x10);
4417 this->start_data_();
4418
4419 for (size_t i = 0; i < this->get_buffer_length_(); i++) {
4420 // A line of eight source pixels (each a bit in this byte)
4421 uint8_t eight_pixels = this->buffer_[i];
4422
4423 for (uint8_t j = 0; j < 8; j += 2) {
4424 /* For bichromatic displays, each byte represents two pixels. Each nibble encodes a pixel: 0=white, 3=black,
4425 4=color. Therefore, e.g. 0x44 = two adjacent color pixels, 0x33 is two adjacent black pixels, etc. If you want
4426 to draw using the color pixels, change '0x30' with '0x40' and '0x03' with '0x04' below. */
4427 uint8_t left_nibble = (eight_pixels & 0x80) ? 0x30 : 0x00;
4428 eight_pixels <<= 1;
4429 uint8_t right_nibble = (eight_pixels & 0x80) ? 0x03 : 0x00;
4430 eight_pixels <<= 1;
4431 this->write_byte(left_nibble | right_nibble);
4432 }
4433 App.feed_wdt();
4434 }
4435 this->end_data_();
4436
4437 // Unlike the 7P5In display, we send the "power on" command here rather than during initialization
4438 // COMMAND POWER ON
4439 this->command(0x04);
4440
4441 // COMMAND DISPLAY REFRESH
4442 this->command(0x12);
4443}
4444
4446
4448
4450 LOG_DISPLAY("", "Waveshare E-Paper", this);
4451 ESP_LOGCONFIG(TAG, " Model: 7.5in-bc");
4452 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4453 LOG_PIN(" DC Pin: ", this->dc_pin_);
4454 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4455 LOG_UPDATE_INTERVAL(this);
4456}
4457
4459 this->command(0x12); // SWRESET
4460
4461 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4462
4463 this->command(0x46); // Auto Write RAM
4464 this->data(0xF7);
4465
4466 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4467
4468 this->command(0x47); // Auto Write RAM
4469 this->data(0xF7);
4470
4471 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4472
4473 this->command(0x0C); // Soft start setting
4474 this->data(0xAE);
4475 this->data(0xC7);
4476 this->data(0xC3);
4477 this->data(0xC0);
4478 this->data(0x40);
4479
4480 this->command(0x01); // Set MUX as 527
4481 this->data(0xAF);
4482 this->data(0x02);
4483 this->data(0x01);
4484
4485 this->command(0x11); // Data entry mode
4486 this->data(0x01);
4487
4488 this->command(0x44);
4489 this->data(0x00); // RAM x address start at 0
4490 this->data(0x00);
4491 this->data(0x6F); // RAM x address end at 36Fh -> 879
4492 this->data(0x03);
4493
4494 this->command(0x45);
4495 this->data(0xAF); // RAM y address start at 20Fh;
4496 this->data(0x02);
4497 this->data(0x00); // RAM y address end at 00h;
4498 this->data(0x00);
4499
4500 this->command(0x3C); // VBD
4501 this->data(0x01); // LUT1, for white
4502
4503 this->command(0x18);
4504 this->data(0x80);
4505
4506 this->command(0x22);
4507 this->data(0xB1); // Load Temperature and waveform setting.
4508
4509 this->command(0x20);
4510
4511 this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
4512
4513 this->command(0x4E);
4514 this->data(0x00);
4515 this->data(0x00);
4516
4517 this->command(0x4F);
4518 this->data(0xAF);
4519 this->data(0x02);
4520}
4521
4523 this->command(0x4F);
4524 this->data(0xAf);
4525 this->data(0x02);
4526
4527 // BLACK
4528 this->command(0x24);
4529 this->start_data_();
4530 this->write_array(this->buffer_, this->get_buffer_length_());
4531 this->end_data_();
4532
4533 // RED
4534 this->command(0x26);
4535 this->start_data_();
4536 for (size_t i = 0; i < this->get_buffer_length_(); i++)
4537 this->write_byte(0x00);
4538 this->end_data_();
4539
4540 this->command(0x22);
4541 this->data(0xC7);
4542 this->command(0x20);
4543 delay(100); // NOLINT
4544}
4545
4547
4549
4551 LOG_DISPLAY("", "Waveshare E-Paper", this);
4552 ESP_LOGCONFIG(TAG, " Model: 7.5in-HD-b");
4553 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4554 LOG_PIN(" DC Pin: ", this->dc_pin_);
4555 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4556 LOG_UPDATE_INTERVAL(this);
4557}
4558
4559static const uint8_t LUT_SIZE_TTGO_DKE_PART = 153;
4560
4561static const uint8_t PART_UPDATE_LUT_TTGO_DKE[LUT_SIZE_TTGO_DKE_PART] = {
4562 0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4563 0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0,
4564 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4565 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4566 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4567 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4568 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
4569 0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
4570 // 0x22, 0x17, 0x41, 0x0, 0x32, 0x32
4571};
4572
4575 bool partial = this->at_update_ != 0;
4576 this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
4577
4578 if (partial) {
4579 ESP_LOGI(TAG, "Performing partial e-paper update.");
4580 } else {
4581 ESP_LOGI(TAG, "Performing full e-paper update.");
4582 }
4583
4584 // start and set up data format
4585 this->command(0x12);
4586 this->wait_until_idle_();
4587
4588 this->command(0x11);
4589 this->data(0x03);
4590 this->command(0x44);
4591 this->data(1);
4592 this->data(this->get_width_internal() / 8);
4593 this->command(0x45);
4594 this->data(0);
4595 this->data(0);
4596 this->data(this->get_height_internal());
4597 this->data(0);
4598 this->command(0x4e);
4599 this->data(1);
4600 this->command(0x4f);
4601 this->data(0);
4602 this->data(0);
4603
4604 if (!partial) {
4605 // send data
4606 this->command(0x24);
4607 this->start_data_();
4608 this->write_array(this->buffer_, this->get_buffer_length_());
4609 this->end_data_();
4610
4611 // commit
4612 this->command(0x20);
4613 this->wait_until_idle_();
4614 } else {
4615 // set up partial update
4616 this->command(0x32);
4617 this->start_data_();
4618 this->write_array(PART_UPDATE_LUT_TTGO_DKE, sizeof(PART_UPDATE_LUT_TTGO_DKE));
4619 this->end_data_();
4620 this->command(0x3F);
4621 this->data(0x22);
4622
4623 this->command(0x03);
4624 this->data(0x17);
4625 this->command(0x04);
4626 this->data(0x41);
4627 this->data(0x00);
4628 this->data(0x32);
4629 this->command(0x2C);
4630 this->data(0x32);
4631
4632 this->command(0x37);
4633 this->data(0x00);
4634 this->data(0x00);
4635 this->data(0x00);
4636 this->data(0x00);
4637 this->data(0x00);
4638 this->data(0x40);
4639 this->data(0x00);
4640 this->data(0x00);
4641 this->data(0x00);
4642 this->data(0x00);
4643
4644 this->command(0x3C);
4645 this->data(0x80);
4646 this->command(0x22);
4647 this->data(0xC0);
4648 this->command(0x20);
4649 this->wait_until_idle_();
4650
4651 // send data
4652 this->command(0x24);
4653 this->start_data_();
4654 this->write_array(this->buffer_, this->get_buffer_length_());
4655 this->end_data_();
4656
4657 // commit as partial
4658 this->command(0x22);
4659 this->data(0xCF);
4660 this->command(0x20);
4661 this->wait_until_idle_();
4662
4663 // data must be sent again on partial update
4664 this->command(0x24);
4665 this->start_data_();
4666 this->write_array(this->buffer_, this->get_buffer_length_());
4667 this->end_data_();
4668 }
4669
4670 ESP_LOGI(TAG, "Completed e-paper update.");
4671}
4672
4677 LOG_DISPLAY("", "Waveshare E-Paper", this);
4678 ESP_LOGCONFIG(TAG, " Model: 2.13inDKE");
4679 LOG_PIN(" CS Pin: ", this->cs_);
4680 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4681 LOG_PIN(" DC Pin: ", this->dc_pin_);
4682 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4683 LOG_UPDATE_INTERVAL(this);
4684}
4685
4686void WaveshareEPaper2P13InDKE::set_full_update_every(uint32_t full_update_every) {
4687 this->full_update_every_ = full_update_every;
4688}
4689
4690// ========================================================
4691// 13.3in (K version)
4692// Datasheet/Specification/Reference:
4693// - https://files.waveshare.com/wiki/13.3inch-e-Paper-HAT-(K)/13.3-inch-e-Paper-(K)-user-manual.pdf
4694// - https://github.com/waveshareteam/e-Paper/tree/master/Arduino/epd13in3k
4695// ========================================================
4696
4697// using default wait_until_idle_() function
4699 this->wait_until_idle_();
4700 this->command(0x12); // SWRESET
4701 this->wait_until_idle_();
4702
4703 this->command(0x0c); // set soft start
4704 this->data(0xae);
4705 this->data(0xc7);
4706 this->data(0xc3);
4707 this->data(0xc0);
4708 this->data(0x80);
4709
4710 this->command(0x01); // driver output control
4711 this->data((get_height_internal() - 1) % 256); // Y
4712 this->data((get_height_internal() - 1) / 256); // Y
4713 this->data(0x00);
4714
4715 this->command(0x11); // data entry mode
4716 this->data(0x03);
4717
4718 // SET WINDOWS
4719 // XRAM_START_AND_END_POSITION
4720 this->command(0x44);
4721 this->data(0 & 0xFF);
4722 this->data((0 >> 8) & 0x03);
4723 this->data((get_width_internal() - 1) & 0xFF);
4724 this->data(((get_width_internal() - 1) >> 8) & 0x03);
4725 // YRAM_START_AND_END_POSITION
4726 this->command(0x45);
4727 this->data(0 & 0xFF);
4728 this->data((0 >> 8) & 0x03);
4729 this->data((get_height_internal() - 1) & 0xFF);
4730 this->data(((get_height_internal() - 1) >> 8) & 0x03);
4731
4732 this->command(0x3C); // Border setting
4733 this->data(0x01);
4734
4735 this->command(0x18); // use the internal temperature sensor
4736 this->data(0x80);
4737
4738 // SET CURSOR
4739 // XRAM_ADDRESS
4740 this->command(0x4E);
4741 this->data(0 & 0xFF);
4742 this->data((0 >> 8) & 0x03);
4743 // YRAM_ADDRESS
4744 this->command(0x4F);
4745 this->data(0 & 0xFF);
4746 this->data((0 >> 8) & 0x03);
4747}
4749 // do single full update
4750 this->command(0x24);
4751 this->start_data_();
4752 this->write_array(this->buffer_, this->get_buffer_length_());
4753 this->end_data_();
4754
4755 // COMMAND DISPLAY REFRESH
4756 this->command(0x22);
4757 this->data(0xF7);
4758 this->command(0x20);
4759}
4760
4763uint32_t WaveshareEPaper13P3InK::idle_timeout_() { return 10000; }
4765 LOG_DISPLAY("", "Waveshare E-Paper", this);
4766 ESP_LOGCONFIG(TAG, " Model: 13.3inK");
4767 LOG_PIN(" Reset Pin: ", this->reset_pin_);
4768 LOG_PIN(" DC Pin: ", this->dc_pin_);
4769 LOG_PIN(" Busy Pin: ", this->busy_pin_);
4770 LOG_UPDATE_INTERVAL(this);
4771}
4772
4773} // namespace waveshare_epaper
4774} // 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:1422
void deallocate(T *p, size_t n)
Definition helpers.h:1480
T * allocate(size_t n)
Definition helpers.h:1442
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