ESPHome 2026.3.0
Loading...
Searching...
No Matches
inkplate.cpp
Go to the documentation of this file.
1#include "inkplate.h"
4#include "esphome/core/log.h"
5
6#include <hal/gpio_hal.h>
7
8namespace esphome {
9namespace inkplate {
10
11static const char *const TAG = "inkplate";
12
14 for (uint32_t i = 0; i < 256; i++) {
15 this->pin_lut_[i] = ((i & 0b00000011) << 4) | (((i & 0b00001100) >> 2) << 18) | (((i & 0b00010000) >> 4) << 23) |
16 (((i & 0b11100000) >> 5) << 25);
17 }
18
19 this->initialize_();
20
21 this->vcom_pin_->setup();
22 this->powerup_pin_->setup();
23 this->wakeup_pin_->setup();
24 this->gpio0_enable_pin_->setup();
26
27 this->cl_pin_->setup();
28 this->le_pin_->setup();
29 this->ckv_pin_->setup();
30 this->gmod_pin_->setup();
31 this->oe_pin_->setup();
32 this->sph_pin_->setup();
33 this->spv_pin_->setup();
34
43
44 this->wakeup_pin_->digital_write(true);
45 delay(1);
46 this->write_bytes(0x09, {
47 0b00011011, // Power up seq.
48 0b00000000, // Power up delay (3mS per rail)
49 0b00011011, // Power down seq.
50 0b00000000, // Power down delay (6mS per rail)
51 });
52 delay(1);
53 this->wakeup_pin_->digital_write(false);
54}
55
60 RAMAllocator<uint8_t> allocator;
61 RAMAllocator<uint32_t> allocator32;
62 uint32_t buffer_size = this->get_buffer_length_();
63 if (buffer_size == 0)
64 return;
65
66 if (this->partial_buffer_ != nullptr) {
67 allocator.deallocate(this->partial_buffer_, buffer_size);
68 this->partial_buffer_ = nullptr;
69 }
70 if (this->partial_buffer_2_ != nullptr) {
71 allocator.deallocate(this->partial_buffer_2_, buffer_size * 2);
72 this->partial_buffer_2_ = nullptr;
73 }
74 if (this->buffer_ != nullptr) {
75 allocator.deallocate(this->buffer_, buffer_size);
76 this->buffer_ = nullptr;
77 }
78 if (this->glut_ != nullptr) {
79 allocator32.deallocate(this->glut_, 256 * 9);
80 this->glut_ = nullptr;
81 }
82 if (this->glut2_ != nullptr) {
83 allocator32.deallocate(this->glut2_, 256 * 9);
84 this->glut2_ = nullptr;
85 }
86
87 this->buffer_ = allocator.allocate(buffer_size);
88 if (this->buffer_ == nullptr) {
89 ESP_LOGE(TAG, "Could not allocate buffer for display!");
90 this->mark_failed();
91 return;
92 }
93 if (this->greyscale_) {
94 this->glut_ = allocator32.allocate(256 * GLUT_SIZE);
95 if (this->glut_ == nullptr) {
96 ESP_LOGE(TAG, "Could not allocate glut!");
97 this->mark_failed();
98 return;
99 }
100 this->glut2_ = allocator32.allocate(256 * GLUT_SIZE);
101 if (this->glut2_ == nullptr) {
102 ESP_LOGE(TAG, "Could not allocate glut2!");
103 this->mark_failed();
104 return;
105 }
106
107 for (uint8_t i = 0; i < GLUT_SIZE; i++) {
108 for (uint32_t j = 0; j < 256; j++) {
109 uint8_t z = (this->waveform_[j & 0x07][i] << 2) | (this->waveform_[(j >> 4) & 0x07][i]);
110 this->glut_[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) |
111 (((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25);
112 z = ((this->waveform_[j & 0x07][i] << 2) | (this->waveform_[(j >> 4) & 0x07][i])) << 4;
113 this->glut2_[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) |
114 (((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25);
115 }
116 }
117
118 } else {
119 this->partial_buffer_ = allocator.allocate(buffer_size);
120 if (this->partial_buffer_ == nullptr) {
121 ESP_LOGE(TAG, "Could not allocate partial buffer for display!");
122 this->mark_failed();
123 return;
124 }
125 this->partial_buffer_2_ = allocator.allocate(buffer_size * 2);
126 if (this->partial_buffer_2_ == nullptr) {
127 ESP_LOGE(TAG, "Could not allocate partial buffer 2 for display!");
128 this->mark_failed();
129 return;
130 }
131
132 memset(this->partial_buffer_, 0, buffer_size);
133 memset(this->partial_buffer_2_, 0, buffer_size * 2);
134 }
135
136 memset(this->buffer_, 0, buffer_size);
137}
138
140
142 if (this->greyscale_) {
143 return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 2u;
144 } else {
145 return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u;
146 }
147}
148
150 this->do_update_();
151
152 if (this->full_update_every_ > 0 && this->partial_updates_ >= this->full_update_every_) {
153 this->block_partial_ = true;
154 }
155
156 this->display();
157}
158
160 if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
161 return;
162
163 if (this->mirror_y_)
164 y = this->get_height_internal() - y - 1;
165
166 if (this->mirror_x_)
167 x = this->get_width_internal() - x - 1;
168
169 if (this->greyscale_) {
170 int x1 = x / 2;
171 int x_sub = x % 2;
172 uint32_t pos = (x1 + y * (this->get_width_internal() / 2));
173 uint8_t current = this->buffer_[pos];
174
175 // float px = (0.2126 * (color.red / 255.0)) + (0.7152 * (color.green / 255.0)) + (0.0722 * (color.blue / 255.0));
176 // px = pow(px, 1.5);
177 // uint8_t gs = (uint8_t)(px*7);
178
179 uint8_t gs = ((color.red * 2126 / 10000) + (color.green * 7152 / 10000) + (color.blue * 722 / 10000)) >> 5;
180 this->buffer_[pos] = (PIXEL_MASK_GLUT[x_sub] & current) | (x_sub ? gs : gs << 4);
181
182 } else {
183 int x1 = x / 8;
184 int x_sub = x % 8;
185 uint32_t pos = (x1 + y * (this->get_width_internal() / 8));
186 uint8_t current = this->partial_buffer_[pos];
187 this->partial_buffer_[pos] = (~PIXEL_MASK_LUT[x_sub] & current) | (color.is_on() ? 0 : PIXEL_MASK_LUT[x_sub]);
188 }
189}
190
192 LOG_DISPLAY("", "Inkplate", this);
193 ESP_LOGCONFIG(TAG,
194 " Greyscale: %s\n"
195 " Partial Updating: %s\n"
196 " Full Update Every: %d",
197 YESNO(this->greyscale_), YESNO(this->partial_updating_), this->full_update_every_);
198 // Log pins
199 LOG_PIN(" CKV Pin: ", this->ckv_pin_);
200 LOG_PIN(" CL Pin: ", this->cl_pin_);
201 LOG_PIN(" GPIO0 Enable Pin: ", this->gpio0_enable_pin_);
202 LOG_PIN(" GMOD Pin: ", this->gmod_pin_);
203 LOG_PIN(" LE Pin: ", this->le_pin_);
204 LOG_PIN(" OE Pin: ", this->oe_pin_);
205 LOG_PIN(" POWERUP Pin: ", this->powerup_pin_);
206 LOG_PIN(" SPH Pin: ", this->sph_pin_);
207 LOG_PIN(" SPV Pin: ", this->spv_pin_);
208 LOG_PIN(" VCOM Pin: ", this->vcom_pin_);
209 LOG_PIN(" WAKEUP Pin: ", this->wakeup_pin_);
210
211 LOG_PIN(" Data 0 Pin: ", this->display_data_0_pin_);
212 LOG_PIN(" Data 1 Pin: ", this->display_data_1_pin_);
213 LOG_PIN(" Data 2 Pin: ", this->display_data_2_pin_);
214 LOG_PIN(" Data 3 Pin: ", this->display_data_3_pin_);
215 LOG_PIN(" Data 4 Pin: ", this->display_data_4_pin_);
216 LOG_PIN(" Data 5 Pin: ", this->display_data_5_pin_);
217 LOG_PIN(" Data 6 Pin: ", this->display_data_6_pin_);
218 LOG_PIN(" Data 7 Pin: ", this->display_data_7_pin_);
219
220 LOG_UPDATE_INTERVAL(this);
221}
222
224 ESP_LOGV(TAG, "Eink off called");
225 if (!panel_on_)
226 return;
227 panel_on_ = false;
228
229 this->oe_pin_->digital_write(false);
230 this->gmod_pin_->digital_write(false);
231
232 GPIO.out &= ~(this->get_data_pin_mask_() | (1 << this->cl_pin_->get_pin()) | (1 << this->le_pin_->get_pin()));
233 this->ckv_pin_->digital_write(false);
234 this->sph_pin_->digital_write(false);
235 this->spv_pin_->digital_write(false);
236
237 this->vcom_pin_->digital_write(false);
238
239 this->write_byte(0x01, 0x6F); // Put TPS65186 into standby mode
240
241 delay(100); // NOLINT
242
243 this->write_byte(0x01, 0x4f); // Disable 3V3 to the panel
244
245 if (this->model_ != INKPLATE_6_PLUS)
246 this->wakeup_pin_->digital_write(false);
247
249}
250
252 ESP_LOGV(TAG, "Eink on called");
253 if (panel_on_)
254 return;
255 this->panel_on_ = true;
256
257 this->pins_as_outputs_();
258 this->wakeup_pin_->digital_write(true);
259 this->vcom_pin_->digital_write(true);
260 delay(2);
261
262 this->write_byte(0x01, 0b00101111); // Enable all rails
263
264 delay(1);
265
266 this->write_byte(0x01, 0b10101111); // Switch TPS65186 into active mode
267
268 this->le_pin_->digital_write(false);
269 this->oe_pin_->digital_write(false);
270 this->cl_pin_->digital_write(false);
271 this->sph_pin_->digital_write(true);
272 this->gmod_pin_->digital_write(true);
273 this->spv_pin_->digital_write(true);
274 this->ckv_pin_->digital_write(false);
275 this->oe_pin_->digital_write(false);
276
277 uint32_t timer = millis();
278 do {
279 delay(1);
280 } while (!this->read_power_status_() && ((millis() - timer) < 250));
281 if ((millis() - timer) >= 250) {
282 ESP_LOGW(TAG, "Power supply not detected");
283 this->wakeup_pin_->digital_write(false);
284 this->vcom_pin_->digital_write(false);
285 this->powerup_pin_->digital_write(false);
286 this->panel_on_ = false;
287 return;
288 }
289
290 this->oe_pin_->digital_write(true);
291}
292
294 uint8_t data;
295 auto err = this->read_register(0x0F, &data, 1);
296 if (err == i2c::ERROR_OK) {
297 return data == 0b11111010;
298 }
299 return false;
300}
301
303 ESP_LOGV(TAG, "Fill called");
304 uint32_t start_time = millis();
305
306 // If clipping is active, fall back to base implementation
307 if (this->get_clipping().is_set()) {
308 Display::fill(color);
309 ESP_LOGV(TAG, "Fill finished (%ums)", millis() - start_time);
310 return;
311 }
312
313 if (this->greyscale_) {
314 uint8_t fill = ((color.red * 2126 / 10000) + (color.green * 7152 / 10000) + (color.blue * 722 / 10000)) >> 5;
315 memset(this->buffer_, (fill << 4) | fill, this->get_buffer_length_());
316 } else {
317 uint8_t fill = color.is_on() ? 0x00 : 0xFF;
318 memset(this->partial_buffer_, fill, this->get_buffer_length_());
319 }
320
321 ESP_LOGV(TAG, "Fill finished (%ums)", millis() - start_time);
322}
323
325 ESP_LOGV(TAG, "Display called");
326 uint32_t start_time = millis();
327
328 if (this->greyscale_) {
329 this->display3b_();
330 } else {
331 if (this->partial_updating_ && this->partial_update_()) {
332 ESP_LOGV(TAG, "Display finished (partial) (%ums)", millis() - start_time);
333 return;
334 }
335 this->display1b_();
336 }
337 ESP_LOGV(TAG, "Display finished (full) (%ums)", millis() - start_time);
338}
339
341 ESP_LOGV(TAG, "Display1b called");
342 uint32_t start_time = millis();
343
344 memcpy(this->buffer_, this->partial_buffer_, this->get_buffer_length_());
345
346 uint8_t data;
347 uint8_t buffer_value;
348 const uint8_t *buffer_ptr;
349 eink_on_();
350 uint8_t rep = 4;
351 switch (this->model_) {
352 case INKPLATE_10:
353 clean_fast_(0, 1);
354 clean_fast_(1, 10);
355 clean_fast_(2, 1);
356 clean_fast_(0, 10);
357 clean_fast_(2, 1);
358 clean_fast_(1, 10);
359 clean_fast_(2, 1);
360 clean_fast_(0, 10);
361 rep = 5;
362 break;
363 case INKPLATE_6_PLUS:
364 clean_fast_(0, 1);
365 clean_fast_(1, 15);
366 clean_fast_(2, 1);
367 clean_fast_(0, 5);
368 clean_fast_(2, 1);
369 clean_fast_(1, 15);
370 break;
371 case INKPLATE_6:
372 case INKPLATE_6_V2:
373 clean_fast_(0, 1);
374 clean_fast_(1, 18);
375 clean_fast_(2, 1);
376 clean_fast_(0, 18);
377 clean_fast_(2, 1);
378 clean_fast_(1, 18);
379 clean_fast_(2, 1);
380 clean_fast_(0, 18);
381 clean_fast_(2, 1);
382 if (this->model_ == INKPLATE_6_V2)
383 rep = 5;
384 break;
385 case INKPLATE_5:
386 clean_fast_(0, 1);
387 clean_fast_(1, 14);
388 clean_fast_(2, 1);
389 clean_fast_(0, 14);
390 clean_fast_(2, 1);
391 clean_fast_(1, 14);
392 clean_fast_(2, 1);
393 clean_fast_(0, 14);
394 clean_fast_(2, 1);
395 rep = 5;
396 break;
397 case INKPLATE_5_V2:
398 clean_fast_(0, 1);
399 clean_fast_(1, 11);
400 clean_fast_(2, 1);
401 clean_fast_(0, 11);
402 clean_fast_(2, 1);
403 clean_fast_(1, 11);
404 clean_fast_(2, 1);
405 clean_fast_(0, 11);
406 rep = 3;
407 break;
408 }
409
410 uint32_t clock = (1UL << this->cl_pin_->get_pin());
411 uint32_t data_mask = this->get_data_pin_mask_();
412 ESP_LOGV(TAG, "Display1b start loops (%ums)", millis() - start_time);
413
414 for (uint8_t k = 0; k < rep; k++) {
415 buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1];
416 vscan_start_();
417 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
418 buffer_value = *(buffer_ptr--);
419 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F];
420 hscan_start_(this->pin_lut_[data]);
421 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F];
422 GPIO.out_w1ts = this->pin_lut_[data] | clock;
423 GPIO.out_w1tc = data_mask | clock;
424
425 for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
426 buffer_value = *(buffer_ptr--);
427 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F];
428 GPIO.out_w1ts = this->pin_lut_[data] | clock;
429 GPIO.out_w1tc = data_mask | clock;
430 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F];
431 GPIO.out_w1ts = this->pin_lut_[data] | clock;
432 GPIO.out_w1tc = data_mask | clock;
433 }
434 // New Inkplate6 panel doesn't need last clock
435 if (this->model_ != INKPLATE_6_V2) {
436 GPIO.out_w1ts = clock;
437 GPIO.out_w1tc = data_mask | clock;
438 }
439 vscan_end_();
440 }
442 }
443 ESP_LOGV(TAG, "Display1b first loop x %d (%ums)", 4, millis() - start_time);
444
445 buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1];
446 vscan_start_();
447 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
448 buffer_value = *(buffer_ptr--);
449 data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F];
450 hscan_start_(this->pin_lut_[data] | clock);
451 data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F];
452 GPIO.out_w1ts = this->pin_lut_[data] | clock;
453 GPIO.out_w1tc = data_mask | clock;
454
455 for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
456 buffer_value = *(buffer_ptr--);
457 data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F];
458 GPIO.out_w1ts = this->pin_lut_[data] | clock;
459 GPIO.out_w1tc = data_mask | clock;
460 data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F];
461 GPIO.out_w1ts = this->pin_lut_[data] | clock;
462 GPIO.out_w1tc = data_mask | clock;
463 }
464 // New Inkplate6 panel doesn't need last clock
465 if (this->model_ != INKPLATE_6_V2) {
466 GPIO.out_w1ts = clock;
467 GPIO.out_w1tc = data_mask | clock;
468 }
469 vscan_end_();
470 }
472 ESP_LOGV(TAG, "Display1b second loop (%ums)", millis() - start_time);
473
474 if (this->model_ == INKPLATE_6_PLUS) {
475 clean_fast_(2, 2);
476 clean_fast_(3, 1);
477 } else {
478 uint32_t send = this->pin_lut_[0];
479 vscan_start_();
480 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
481 hscan_start_(send);
482 GPIO.out_w1ts = send | clock;
483 GPIO.out_w1tc = data_mask | clock;
484 for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
485 GPIO.out_w1ts = send | clock;
486 GPIO.out_w1tc = data_mask | clock;
487 GPIO.out_w1ts = send | clock;
488 GPIO.out_w1tc = data_mask | clock;
489 }
490 // New Inkplate6 panel doesn't need last clock
491 if (this->model_ != INKPLATE_6_V2) {
492 GPIO.out_w1ts = clock;
493 GPIO.out_w1tc = data_mask | clock;
494 }
495 vscan_end_();
496 }
498 ESP_LOGV(TAG, "Display1b third loop (%ums)", millis() - start_time);
499 }
500 vscan_start_();
501 eink_off_();
502 this->block_partial_ = false;
503 this->partial_updates_ = 0;
504 ESP_LOGV(TAG, "Display1b finished (%ums)", millis() - start_time);
505}
506
508 ESP_LOGV(TAG, "Display3b called");
509 uint32_t start_time = millis();
510
511 eink_on_();
512
513 switch (this->model_) {
514 case INKPLATE_10:
515 if (this->custom_waveform_) {
516 clean_fast_(1, 1);
517 clean_fast_(0, 7);
518 clean_fast_(2, 1);
519 clean_fast_(1, 12);
520 clean_fast_(2, 1);
521 clean_fast_(0, 7);
522 clean_fast_(2, 1);
523 clean_fast_(1, 12);
524 } else {
525 clean_fast_(1, 1);
526 clean_fast_(0, 10);
527 clean_fast_(2, 1);
528 clean_fast_(1, 10);
529 clean_fast_(2, 1);
530 clean_fast_(0, 10);
531 clean_fast_(2, 1);
532 clean_fast_(1, 10);
533 }
534 break;
535 case INKPLATE_6_PLUS:
536 clean_fast_(0, 1);
537 clean_fast_(1, 15);
538 clean_fast_(2, 1);
539 clean_fast_(0, 5);
540 clean_fast_(2, 1);
541 clean_fast_(1, 15);
542 break;
543 case INKPLATE_6:
544 case INKPLATE_6_V2:
545 clean_fast_(0, 1);
546 clean_fast_(1, 18);
547 clean_fast_(2, 1);
548 clean_fast_(0, 18);
549 clean_fast_(2, 1);
550 clean_fast_(1, 18);
551 clean_fast_(2, 1);
552 clean_fast_(0, 18);
553 clean_fast_(2, 1);
554 break;
555 case INKPLATE_5:
556 clean_fast_(0, 1);
557 clean_fast_(1, 14);
558 clean_fast_(2, 1);
559 clean_fast_(0, 14);
560 clean_fast_(2, 1);
561 clean_fast_(1, 14);
562 clean_fast_(2, 1);
563 clean_fast_(0, 14);
564 clean_fast_(2, 1);
565 break;
566 case INKPLATE_5_V2:
567 clean_fast_(0, 1);
568 clean_fast_(1, 11);
569 clean_fast_(2, 1);
570 clean_fast_(0, 11);
571 clean_fast_(2, 1);
572 clean_fast_(1, 11);
573 clean_fast_(2, 1);
574 clean_fast_(0, 11);
575 break;
576 }
577
578 uint32_t clock = (1UL << this->cl_pin_->get_pin());
579 uint32_t data_mask = this->get_data_pin_mask_();
581 uint32_t data;
582 uint8_t glut_size = 9;
583 for (int k = 0; k < glut_size; k++) {
584 pos = this->get_buffer_length_();
585 vscan_start_();
586 for (int i = 0; i < this->get_height_internal(); i++) {
587 data = this->glut2_[k * 256 + this->buffer_[--pos]];
588 data |= this->glut_[k * 256 + this->buffer_[--pos]];
589 hscan_start_(data);
590 data = this->glut2_[k * 256 + this->buffer_[--pos]];
591 data |= this->glut_[k * 256 + this->buffer_[--pos]];
592 GPIO.out_w1ts = data | clock;
593 GPIO.out_w1tc = data_mask | clock;
594
595 for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
596 data = this->glut2_[k * 256 + this->buffer_[--pos]];
597 data |= this->glut_[k * 256 + this->buffer_[--pos]];
598 GPIO.out_w1ts = data | clock;
599 GPIO.out_w1tc = data_mask | clock;
600 data = this->glut2_[k * 256 + this->buffer_[--pos]];
601 data |= this->glut_[k * 256 + this->buffer_[--pos]];
602 GPIO.out_w1ts = data | clock;
603 GPIO.out_w1tc = data_mask | clock;
604 }
605 // New Inkplate6 panel doesn't need last clock
606 if (this->model_ != INKPLATE_6_V2) {
607 GPIO.out_w1ts = clock;
608 GPIO.out_w1tc = data_mask | clock;
609 }
610 vscan_end_();
611 }
613 }
614 clean_fast_(3, 1);
615 vscan_start_();
616 eink_off_();
617 ESP_LOGV(TAG, "Display3b finished (%ums)", millis() - start_time);
618}
619
621 ESP_LOGV(TAG, "Partial update called");
622 uint32_t start_time = millis();
623 if (this->greyscale_)
624 return false;
625 if (this->block_partial_)
626 return false;
627
628 this->partial_updates_++;
629
630 uint32_t pos = this->get_buffer_length_() - 1;
631 uint8_t data;
632 uint8_t diffw, diffb;
633 uint32_t n = (this->get_buffer_length_() * 2) - 1;
634
635 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
636 for (int j = 0, jm = (this->get_width_internal() / 8); j < jm; j++) {
637 diffw = this->buffer_[pos] & ~(this->partial_buffer_[pos]);
638 diffb = ~(this->buffer_[pos]) & this->partial_buffer_[pos];
639 pos--;
640 this->partial_buffer_2_[n--] = LUTW[diffw >> 4] & LUTB[diffb >> 4];
641 this->partial_buffer_2_[n--] = LUTW[diffw & 0x0F] & LUTB[diffb & 0x0F];
642 }
643 }
644 ESP_LOGV(TAG, "Partial update buffer built after (%ums)", millis() - start_time);
645
646 int rep = (this->model_ == INKPLATE_6_V2) ? 6 : 5;
647
648 eink_on_();
649 uint32_t clock = (1UL << this->cl_pin_->get_pin());
650 uint32_t data_mask = this->get_data_pin_mask_();
651 for (int k = 0; k < rep; k++) {
652 vscan_start_();
653 const uint8_t *data_ptr = &this->partial_buffer_2_[(this->get_buffer_length_() * 2) - 1];
654 for (int i = 0; i < this->get_height_internal(); i++) {
655 data = *(data_ptr--);
656 hscan_start_(this->pin_lut_[data]);
657 for (int j = 0, jm = (this->get_width_internal() / 4) - 1; j < jm; j++) {
658 data = *(data_ptr--);
659 GPIO.out_w1ts = this->pin_lut_[data] | clock;
660 GPIO.out_w1tc = data_mask | clock;
661 }
662 // New Inkplate panel doesn't need last clock
663 if (this->model_ != INKPLATE_6_V2) {
664 GPIO.out_w1ts = clock;
665 GPIO.out_w1tc = data_mask | clock;
666 }
667 vscan_end_();
668 }
670 ESP_LOGV(TAG, "Partial update loop k=%d (%ums)", k, millis() - start_time);
671 }
672 clean_fast_(2, 2);
673 clean_fast_(3, 1);
674 vscan_start_();
675 eink_off_();
676
677 memcpy(this->buffer_, this->partial_buffer_, this->get_buffer_length_());
678 ESP_LOGV(TAG, "Partial update finished (%ums)", millis() - start_time);
679 return true;
680}
681
683 this->ckv_pin_->digital_write(true);
685 this->spv_pin_->digital_write(false);
687 this->ckv_pin_->digital_write(false);
689 this->ckv_pin_->digital_write(true);
691 this->spv_pin_->digital_write(true);
693 this->ckv_pin_->digital_write(false);
695 this->ckv_pin_->digital_write(true);
697 this->ckv_pin_->digital_write(false);
699 this->ckv_pin_->digital_write(true);
701 this->ckv_pin_->digital_write(false);
703 this->ckv_pin_->digital_write(true);
704}
705
707 uint32_t clock = (1UL << this->cl_pin_->get_pin());
708 this->sph_pin_->digital_write(false);
709 GPIO.out_w1ts = d | clock;
710 GPIO.out_w1tc = this->get_data_pin_mask_() | clock;
711 this->sph_pin_->digital_write(true);
712 this->ckv_pin_->digital_write(true);
713}
714
716 this->ckv_pin_->digital_write(false);
717 this->le_pin_->digital_write(true);
718 this->le_pin_->digital_write(false);
720}
721
723 ESP_LOGV(TAG, "Clean called");
724 uint32_t start_time = millis();
725
726 eink_on_();
727 clean_fast_(0, 1); // White
728 clean_fast_(0, 8); // White to White
729 clean_fast_(0, 1); // White to Black
730 clean_fast_(0, 8); // Black to Black
731 clean_fast_(2, 1); // Black to White
732 clean_fast_(1, 10); // White to White
733 ESP_LOGV(TAG, "Clean finished (%ums)", millis() - start_time);
734}
735
736void Inkplate::clean_fast_(uint8_t c, uint8_t rep) {
737 ESP_LOGV(TAG, "Clean fast called with: (%d, %d)", c, rep);
738 uint32_t start_time = millis();
739
740 eink_on_();
741 uint8_t data = 0;
742 if (c == 0) { // White
743 data = 0b10101010;
744 } else if (c == 1) { // Black
745 data = 0b01010101;
746 } else if (c == 2) { // Discharge
747 data = 0b00000000;
748 } else if (c == 3) { // Skip
749 data = 0b11111111;
750 }
751
752 uint32_t send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) |
753 (((data & 0b11100000) >> 5) << 25);
754 uint32_t clock = (1UL << this->cl_pin_->get_pin());
755
756 for (int k = 0; k < rep; k++) {
757 vscan_start_();
758 for (int i = 0; i < this->get_height_internal(); i++) {
759 hscan_start_(send);
760 GPIO.out_w1ts = send | clock;
761 GPIO.out_w1tc = clock;
762 for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
763 GPIO.out_w1ts = clock;
764 GPIO.out_w1tc = clock;
765 GPIO.out_w1ts = clock;
766 GPIO.out_w1tc = clock;
767 }
768 // New Inkplate panel doesn't need last clock
769 if (this->model_ != INKPLATE_6_V2) {
770 GPIO.out_w1ts = send | clock;
771 GPIO.out_w1tc = clock;
772 }
773 vscan_end_();
774 }
776 ESP_LOGV(TAG, "Clean fast rep loop %d finished (%ums)", k, millis() - start_time);
777 }
778 ESP_LOGV(TAG, "Clean fast finished (%ums)", millis() - start_time);
779}
780
800
820
821} // namespace inkplate
822} // namespace esphome
void mark_failed()
Mark this component as failed.
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual uint8_t get_pin() const =0
An STL allocator that uses SPI or internal RAM.
Definition helpers.h:1899
void deallocate(T *p, size_t n)
Definition helpers.h:1954
T * allocate(size_t n)
Definition helpers.h:1916
Rect get_clipping() const
Get the current the clipping rectangle.
Definition display.cpp:766
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:265
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:25
bool write_bytes(uint8_t a_register, const uint8_t *data, uint8_t len) const
Definition i2c.h:251
InternalGPIOPin * cl_pin_
Definition inkplate.h:201
void fill(Color color) override
Definition inkplate.cpp:302
InternalGPIOPin * display_data_0_pin_
Definition inkplate.h:191
void clean_fast_(uint8_t c, uint8_t rep)
Definition inkplate.cpp:736
void hscan_start_(uint32_t d)
Definition inkplate.cpp:706
InternalGPIOPin * display_data_7_pin_
Definition inkplate.h:198
InternalGPIOPin * le_pin_
Definition inkplate.h:204
InternalGPIOPin * display_data_4_pin_
Definition inkplate.h:195
InternalGPIOPin * display_data_1_pin_
Definition inkplate.h:192
void draw_absolute_pixel_internal(int x, int y, Color color) override
Definition inkplate.cpp:159
uint8_t waveform_[GLUT_COUNT][GLUT_SIZE]
Definition inkplate.h:187
void dump_config() override
Definition inkplate.cpp:191
int get_width_internal() override
Definition inkplate.h:123
InternalGPIOPin * display_data_6_pin_
Definition inkplate.h:197
InternalGPIOPin * display_data_3_pin_
Definition inkplate.h:194
InternalGPIOPin * display_data_5_pin_
Definition inkplate.h:196
InternalGPIOPin * display_data_2_pin_
Definition inkplate.h:193
int get_height_internal() override
Definition inkplate.h:138
float get_setup_priority() const override
Definition inkplate.cpp:139
void initialize_()
Allocate buffers.
Definition inkplate.cpp:59
bool z
Definition msa3xx.h:1
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_INPUT
Definition gpio.h:27
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
constexpr float PROCESSOR
For components that use data from sensors like displays.
Definition component.h:33
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delayMicroseconds(uint32_t us)
Definition core.cpp:30
size_t size_t pos
Definition helpers.h:929
void HOT delay(uint32_t ms)
Definition core.cpp:28
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:26
static void uint32_t
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 x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6