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