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