ESPHome 2025.10.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 (this->greyscale_) {
297 uint8_t fill = ((color.red * 2126 / 10000) + (color.green * 7152 / 10000) + (color.blue * 722 / 10000)) >> 5;
298 memset(this->buffer_, (fill << 4) | fill, this->get_buffer_length_());
299 } else {
300 uint8_t fill = color.is_on() ? 0x00 : 0xFF;
301 memset(this->partial_buffer_, fill, this->get_buffer_length_());
302 }
303
304 ESP_LOGV(TAG, "Fill finished (%ums)", millis() - start_time);
305}
306
308 ESP_LOGV(TAG, "Display called");
309 uint32_t start_time = millis();
310
311 if (this->greyscale_) {
312 this->display3b_();
313 } else {
314 if (this->partial_updating_ && this->partial_update_()) {
315 ESP_LOGV(TAG, "Display finished (partial) (%ums)", millis() - start_time);
316 return;
317 }
318 this->display1b_();
319 }
320 ESP_LOGV(TAG, "Display finished (full) (%ums)", millis() - start_time);
321}
322
324 ESP_LOGV(TAG, "Display1b called");
325 uint32_t start_time = millis();
326
327 memcpy(this->buffer_, this->partial_buffer_, this->get_buffer_length_());
328
329 uint8_t data;
330 uint8_t buffer_value;
331 const uint8_t *buffer_ptr;
332 eink_on_();
333 uint8_t rep = 4;
334 switch (this->model_) {
335 case INKPLATE_10:
336 clean_fast_(0, 1);
337 clean_fast_(1, 10);
338 clean_fast_(2, 1);
339 clean_fast_(0, 10);
340 clean_fast_(2, 1);
341 clean_fast_(1, 10);
342 clean_fast_(2, 1);
343 clean_fast_(0, 10);
344 rep = 5;
345 break;
346 case INKPLATE_6_PLUS:
347 clean_fast_(0, 1);
348 clean_fast_(1, 15);
349 clean_fast_(2, 1);
350 clean_fast_(0, 5);
351 clean_fast_(2, 1);
352 clean_fast_(1, 15);
353 break;
354 case INKPLATE_6:
355 case INKPLATE_6_V2:
356 clean_fast_(0, 1);
357 clean_fast_(1, 18);
358 clean_fast_(2, 1);
359 clean_fast_(0, 18);
360 clean_fast_(2, 1);
361 clean_fast_(1, 18);
362 clean_fast_(2, 1);
363 clean_fast_(0, 18);
364 clean_fast_(2, 1);
365 if (this->model_ == INKPLATE_6_V2)
366 rep = 5;
367 break;
368 case INKPLATE_5:
369 clean_fast_(0, 1);
370 clean_fast_(1, 14);
371 clean_fast_(2, 1);
372 clean_fast_(0, 14);
373 clean_fast_(2, 1);
374 clean_fast_(1, 14);
375 clean_fast_(2, 1);
376 clean_fast_(0, 14);
377 clean_fast_(2, 1);
378 rep = 5;
379 break;
380 case INKPLATE_5_V2:
381 clean_fast_(0, 1);
382 clean_fast_(1, 11);
383 clean_fast_(2, 1);
384 clean_fast_(0, 11);
385 clean_fast_(2, 1);
386 clean_fast_(1, 11);
387 clean_fast_(2, 1);
388 clean_fast_(0, 11);
389 rep = 3;
390 break;
391 }
392
393 uint32_t clock = (1 << this->cl_pin_->get_pin());
394 uint32_t data_mask = this->get_data_pin_mask_();
395 ESP_LOGV(TAG, "Display1b start loops (%ums)", millis() - start_time);
396
397 for (uint8_t k = 0; k < rep; k++) {
398 buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1];
399 vscan_start_();
400 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
401 buffer_value = *(buffer_ptr--);
402 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F];
403 hscan_start_(this->pin_lut_[data]);
404 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F];
405 GPIO.out_w1ts = this->pin_lut_[data] | clock;
406 GPIO.out_w1tc = data_mask | clock;
407
408 for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
409 buffer_value = *(buffer_ptr--);
410 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F];
411 GPIO.out_w1ts = this->pin_lut_[data] | clock;
412 GPIO.out_w1tc = data_mask | clock;
413 data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F];
414 GPIO.out_w1ts = this->pin_lut_[data] | clock;
415 GPIO.out_w1tc = data_mask | clock;
416 }
417 // New Inkplate6 panel doesn't need last clock
418 if (this->model_ != INKPLATE_6_V2) {
419 GPIO.out_w1ts = clock;
420 GPIO.out_w1tc = data_mask | clock;
421 }
422 vscan_end_();
423 }
425 }
426 ESP_LOGV(TAG, "Display1b first loop x %d (%ums)", 4, millis() - start_time);
427
428 buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1];
429 vscan_start_();
430 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
431 buffer_value = *(buffer_ptr--);
432 data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F];
433 hscan_start_(this->pin_lut_[data] | clock);
434 data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F];
435 GPIO.out_w1ts = this->pin_lut_[data] | clock;
436 GPIO.out_w1tc = data_mask | clock;
437
438 for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
439 buffer_value = *(buffer_ptr--);
440 data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F];
441 GPIO.out_w1ts = this->pin_lut_[data] | clock;
442 GPIO.out_w1tc = data_mask | clock;
443 data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F];
444 GPIO.out_w1ts = this->pin_lut_[data] | clock;
445 GPIO.out_w1tc = data_mask | clock;
446 }
447 // New Inkplate6 panel doesn't need last clock
448 if (this->model_ != INKPLATE_6_V2) {
449 GPIO.out_w1ts = clock;
450 GPIO.out_w1tc = data_mask | clock;
451 }
452 vscan_end_();
453 }
455 ESP_LOGV(TAG, "Display1b second loop (%ums)", millis() - start_time);
456
457 if (this->model_ == INKPLATE_6_PLUS) {
458 clean_fast_(2, 2);
459 clean_fast_(3, 1);
460 } else {
461 uint32_t send = this->pin_lut_[0];
462 vscan_start_();
463 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
464 hscan_start_(send);
465 GPIO.out_w1ts = send | clock;
466 GPIO.out_w1tc = data_mask | clock;
467 for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
468 GPIO.out_w1ts = send | clock;
469 GPIO.out_w1tc = data_mask | clock;
470 GPIO.out_w1ts = send | clock;
471 GPIO.out_w1tc = data_mask | clock;
472 }
473 // New Inkplate6 panel doesn't need last clock
474 if (this->model_ != INKPLATE_6_V2) {
475 GPIO.out_w1ts = clock;
476 GPIO.out_w1tc = data_mask | clock;
477 }
478 vscan_end_();
479 }
481 ESP_LOGV(TAG, "Display1b third loop (%ums)", millis() - start_time);
482 }
483 vscan_start_();
484 eink_off_();
485 this->block_partial_ = false;
486 this->partial_updates_ = 0;
487 ESP_LOGV(TAG, "Display1b finished (%ums)", millis() - start_time);
488}
489
491 ESP_LOGV(TAG, "Display3b called");
492 uint32_t start_time = millis();
493
494 eink_on_();
495
496 switch (this->model_) {
497 case INKPLATE_10:
498 if (this->custom_waveform_) {
499 clean_fast_(1, 1);
500 clean_fast_(0, 7);
501 clean_fast_(2, 1);
502 clean_fast_(1, 12);
503 clean_fast_(2, 1);
504 clean_fast_(0, 7);
505 clean_fast_(2, 1);
506 clean_fast_(1, 12);
507 } else {
508 clean_fast_(1, 1);
509 clean_fast_(0, 10);
510 clean_fast_(2, 1);
511 clean_fast_(1, 10);
512 clean_fast_(2, 1);
513 clean_fast_(0, 10);
514 clean_fast_(2, 1);
515 clean_fast_(1, 10);
516 }
517 break;
518 case INKPLATE_6_PLUS:
519 clean_fast_(0, 1);
520 clean_fast_(1, 15);
521 clean_fast_(2, 1);
522 clean_fast_(0, 5);
523 clean_fast_(2, 1);
524 clean_fast_(1, 15);
525 break;
526 case INKPLATE_6:
527 case INKPLATE_6_V2:
528 clean_fast_(0, 1);
529 clean_fast_(1, 18);
530 clean_fast_(2, 1);
531 clean_fast_(0, 18);
532 clean_fast_(2, 1);
533 clean_fast_(1, 18);
534 clean_fast_(2, 1);
535 clean_fast_(0, 18);
536 clean_fast_(2, 1);
537 break;
538 case INKPLATE_5:
539 clean_fast_(0, 1);
540 clean_fast_(1, 14);
541 clean_fast_(2, 1);
542 clean_fast_(0, 14);
543 clean_fast_(2, 1);
544 clean_fast_(1, 14);
545 clean_fast_(2, 1);
546 clean_fast_(0, 14);
547 clean_fast_(2, 1);
548 break;
549 case INKPLATE_5_V2:
550 clean_fast_(0, 1);
551 clean_fast_(1, 11);
552 clean_fast_(2, 1);
553 clean_fast_(0, 11);
554 clean_fast_(2, 1);
555 clean_fast_(1, 11);
556 clean_fast_(2, 1);
557 clean_fast_(0, 11);
558 break;
559 }
560
561 uint32_t clock = (1 << this->cl_pin_->get_pin());
562 uint32_t data_mask = this->get_data_pin_mask_();
563 uint32_t pos;
564 uint32_t data;
565 uint8_t glut_size = 9;
566 for (int k = 0; k < glut_size; k++) {
567 pos = this->get_buffer_length_();
568 vscan_start_();
569 for (int i = 0; i < this->get_height_internal(); i++) {
570 data = this->glut2_[k * 256 + this->buffer_[--pos]];
571 data |= this->glut_[k * 256 + this->buffer_[--pos]];
573 data = this->glut2_[k * 256 + this->buffer_[--pos]];
574 data |= this->glut_[k * 256 + this->buffer_[--pos]];
575 GPIO.out_w1ts = data | clock;
576 GPIO.out_w1tc = data_mask | clock;
577
578 for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
579 data = this->glut2_[k * 256 + this->buffer_[--pos]];
580 data |= this->glut_[k * 256 + this->buffer_[--pos]];
581 GPIO.out_w1ts = data | clock;
582 GPIO.out_w1tc = data_mask | clock;
583 data = this->glut2_[k * 256 + this->buffer_[--pos]];
584 data |= this->glut_[k * 256 + this->buffer_[--pos]];
585 GPIO.out_w1ts = data | clock;
586 GPIO.out_w1tc = data_mask | clock;
587 }
588 // New Inkplate6 panel doesn't need last clock
589 if (this->model_ != INKPLATE_6_V2) {
590 GPIO.out_w1ts = clock;
591 GPIO.out_w1tc = data_mask | clock;
592 }
593 vscan_end_();
594 }
596 }
597 clean_fast_(3, 1);
598 vscan_start_();
599 eink_off_();
600 ESP_LOGV(TAG, "Display3b finished (%ums)", millis() - start_time);
601}
602
604 ESP_LOGV(TAG, "Partial update called");
605 uint32_t start_time = millis();
606 if (this->greyscale_)
607 return false;
608 if (this->block_partial_)
609 return false;
610
611 this->partial_updates_++;
612
613 uint32_t pos = this->get_buffer_length_() - 1;
614 uint8_t data;
615 uint8_t diffw, diffb;
616 uint32_t n = (this->get_buffer_length_() * 2) - 1;
617
618 for (int i = 0, im = this->get_height_internal(); i < im; i++) {
619 for (int j = 0, jm = (this->get_width_internal() / 8); j < jm; j++) {
620 diffw = this->buffer_[pos] & ~(this->partial_buffer_[pos]);
621 diffb = ~(this->buffer_[pos]) & this->partial_buffer_[pos];
622 pos--;
623 this->partial_buffer_2_[n--] = LUTW[diffw >> 4] & LUTB[diffb >> 4];
624 this->partial_buffer_2_[n--] = LUTW[diffw & 0x0F] & LUTB[diffb & 0x0F];
625 }
626 }
627 ESP_LOGV(TAG, "Partial update buffer built after (%ums)", millis() - start_time);
628
629 int rep = (this->model_ == INKPLATE_6_V2) ? 6 : 5;
630
631 eink_on_();
632 uint32_t clock = (1 << this->cl_pin_->get_pin());
633 uint32_t data_mask = this->get_data_pin_mask_();
634 for (int k = 0; k < rep; k++) {
635 vscan_start_();
636 const uint8_t *data_ptr = &this->partial_buffer_2_[(this->get_buffer_length_() * 2) - 1];
637 for (int i = 0; i < this->get_height_internal(); i++) {
638 data = *(data_ptr--);
639 hscan_start_(this->pin_lut_[data]);
640 for (int j = 0, jm = (this->get_width_internal() / 4) - 1; j < jm; j++) {
641 data = *(data_ptr--);
642 GPIO.out_w1ts = this->pin_lut_[data] | clock;
643 GPIO.out_w1tc = data_mask | clock;
644 }
645 // New Inkplate panel doesn't need last clock
646 if (this->model_ != INKPLATE_6_V2) {
647 GPIO.out_w1ts = clock;
648 GPIO.out_w1tc = data_mask | clock;
649 }
650 vscan_end_();
651 }
653 ESP_LOGV(TAG, "Partial update loop k=%d (%ums)", k, millis() - start_time);
654 }
655 clean_fast_(2, 2);
656 clean_fast_(3, 1);
657 vscan_start_();
658 eink_off_();
659
660 memcpy(this->buffer_, this->partial_buffer_, this->get_buffer_length_());
661 ESP_LOGV(TAG, "Partial update finished (%ums)", millis() - start_time);
662 return true;
663}
664
666 this->ckv_pin_->digital_write(true);
668 this->spv_pin_->digital_write(false);
670 this->ckv_pin_->digital_write(false);
672 this->ckv_pin_->digital_write(true);
674 this->spv_pin_->digital_write(true);
676 this->ckv_pin_->digital_write(false);
678 this->ckv_pin_->digital_write(true);
680 this->ckv_pin_->digital_write(false);
682 this->ckv_pin_->digital_write(true);
684 this->ckv_pin_->digital_write(false);
686 this->ckv_pin_->digital_write(true);
687}
688
689void Inkplate::hscan_start_(uint32_t d) {
690 uint8_t clock = (1 << this->cl_pin_->get_pin());
691 this->sph_pin_->digital_write(false);
692 GPIO.out_w1ts = d | clock;
693 GPIO.out_w1tc = this->get_data_pin_mask_() | clock;
694 this->sph_pin_->digital_write(true);
695 this->ckv_pin_->digital_write(true);
696}
697
699 this->ckv_pin_->digital_write(false);
700 this->le_pin_->digital_write(true);
701 this->le_pin_->digital_write(false);
703}
704
706 ESP_LOGV(TAG, "Clean called");
707 uint32_t start_time = millis();
708
709 eink_on_();
710 clean_fast_(0, 1); // White
711 clean_fast_(0, 8); // White to White
712 clean_fast_(0, 1); // White to Black
713 clean_fast_(0, 8); // Black to Black
714 clean_fast_(2, 1); // Black to White
715 clean_fast_(1, 10); // White to White
716 ESP_LOGV(TAG, "Clean finished (%ums)", millis() - start_time);
717}
718
719void Inkplate::clean_fast_(uint8_t c, uint8_t rep) {
720 ESP_LOGV(TAG, "Clean fast called with: (%d, %d)", c, rep);
721 uint32_t start_time = millis();
722
723 eink_on_();
724 uint8_t data = 0;
725 if (c == 0) { // White
726 data = 0b10101010;
727 } else if (c == 1) { // Black
728 data = 0b01010101;
729 } else if (c == 2) { // Discharge
730 data = 0b00000000;
731 } else if (c == 3) { // Skip
732 data = 0b11111111;
733 }
734
735 uint32_t send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) |
736 (((data & 0b11100000) >> 5) << 25);
737 uint32_t clock = (1 << this->cl_pin_->get_pin());
738
739 for (int k = 0; k < rep; k++) {
740 vscan_start_();
741 for (int i = 0; i < this->get_height_internal(); i++) {
742 hscan_start_(send);
743 GPIO.out_w1ts = send | clock;
744 GPIO.out_w1tc = clock;
745 for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
746 GPIO.out_w1ts = clock;
747 GPIO.out_w1tc = clock;
748 GPIO.out_w1ts = clock;
749 GPIO.out_w1tc = clock;
750 }
751 // New Inkplate panel doesn't need last clock
752 if (this->model_ != INKPLATE_6_V2) {
753 GPIO.out_w1ts = send | clock;
754 GPIO.out_w1tc = clock;
755 }
756 vscan_end_();
757 }
759 ESP_LOGV(TAG, "Clean fast rep loop %d finished (%ums)", k, millis() - start_time);
760 }
761 ESP_LOGV(TAG, "Clean fast finished (%ums)", millis() - start_time);
762}
763
783
803
804} // namespace inkplate
805} // 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:859
void deallocate(T *p, size_t n)
Definition helpers.h:917
T * allocate(size_t n)
Definition helpers.h:879
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:32
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:719
void hscan_start_(uint32_t d)
Definition inkplate.cpp:689
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:50
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:31
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:29
uint32_t IRAM_ATTR HOT millis()
Definition core.cpp:28
uint8_t red
Definition color.h:22
uint8_t green
Definition color.h:26
bool is_on() ESPHOME_ALWAYS_INLINE
Definition color.h:61
uint8_t blue
Definition color.h:30
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6