From c66d0550e85518cbe87604de557bbc43129adb92 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Tue, 8 Feb 2022 22:56:56 +1300 Subject: [PATCH] Inkplate 6 PLUS (#3013) --- esphome/components/inkplate6/display.py | 1 + esphome/components/inkplate6/inkplate.cpp | 434 +++++++++++++--------- esphome/components/inkplate6/inkplate.h | 54 +-- 3 files changed, 281 insertions(+), 208 deletions(-) diff --git a/esphome/components/inkplate6/display.py b/esphome/components/inkplate6/display.py index dca764c6ed..a17f37c920 100644 --- a/esphome/components/inkplate6/display.py +++ b/esphome/components/inkplate6/display.py @@ -47,6 +47,7 @@ InkplateModel = inkplate6_ns.enum("InkplateModel") MODELS = { "inkplate_6": InkplateModel.INKPLATE_6, "inkplate_10": InkplateModel.INKPLATE_10, + "inkplate_6_plus": InkplateModel.INKPLATE_6_PLUS, } CONFIG_SCHEMA = cv.All( diff --git a/esphome/components/inkplate6/inkplate.cpp b/esphome/components/inkplate6/inkplate.cpp index 8b7890feb7..e6fb9b773c 100644 --- a/esphome/components/inkplate6/inkplate.cpp +++ b/esphome/components/inkplate6/inkplate.cpp @@ -13,6 +13,11 @@ namespace inkplate6 { static const char *const TAG = "inkplate"; void Inkplate6::setup() { + for (uint32_t i = 0; i < 256; i++) { + this->pin_lut_[i] = ((i & 0b00000011) << 4) | (((i & 0b00001100) >> 2) << 18) | (((i & 0b00010000) >> 4) << 23) | + (((i & 0b11100000) >> 5) << 25); + } + this->initialize_(); this->vcom_pin_->setup(); @@ -38,11 +43,21 @@ void Inkplate6::setup() { this->display_data_6_pin_->setup(); this->display_data_7_pin_->setup(); - this->clean(); - this->display(); + this->wakeup_pin_->digital_write(true); + delay(1); + this->write_bytes(0x09, { + 0b00011011, // Power up seq. + 0b00000000, // Power up delay (3mS per rail) + 0b00011011, // Power down seq. + 0b00000000, // Power down delay (6mS per rail) + }); + delay(1); + this->wakeup_pin_->digital_write(false); } + void Inkplate6::initialize_() { ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + ExternalRAMAllocator allocator32(ExternalRAMAllocator::ALLOW_FAILURE); uint32_t buffer_size = this->get_buffer_length_(); if (buffer_size == 0) return; @@ -53,6 +68,10 @@ void Inkplate6::initialize_() { allocator.deallocate(this->partial_buffer_2_, buffer_size * 2); if (this->buffer_ != nullptr) allocator.deallocate(this->buffer_, buffer_size); + if (this->glut_ != nullptr) + allocator32.deallocate(this->glut_, 256 * (this->model_ == INKPLATE_6_PLUS ? 9 : 8)); + if (this->glut2_ != nullptr) + allocator32.deallocate(this->glut2_, 256 * (this->model_ == INKPLATE_6_PLUS ? 9 : 8)); this->buffer_ = allocator.allocate(buffer_size); if (this->buffer_ == nullptr) { @@ -60,7 +79,34 @@ void Inkplate6::initialize_() { this->mark_failed(); return; } - if (!this->greyscale_) { + if (this->greyscale_) { + uint8_t glut_size = (this->model_ == INKPLATE_6_PLUS ? 9 : 8); + + this->glut_ = allocator32.allocate(256 * glut_size); + if (this->glut_ == nullptr) { + ESP_LOGE(TAG, "Could not allocate glut!"); + this->mark_failed(); + return; + } + this->glut2_ = allocator32.allocate(256 * glut_size); + if (this->glut2_ == nullptr) { + ESP_LOGE(TAG, "Could not allocate glut2!"); + this->mark_failed(); + return; + } + + for (int i = 0; i < glut_size; i++) { + for (uint32_t j = 0; j < 256; j++) { + uint8_t z = (waveform3Bit[j & 0x07][i] << 2) | (waveform3Bit[(j >> 4) & 0x07][i]); + this->glut_[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) | + (((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25); + z = ((waveform3Bit[j & 0x07][i] << 2) | (waveform3Bit[(j >> 4) & 0x07][i])) << 4; + this->glut2_[i * 256 + j] = ((z & 0b00000011) << 4) | (((z & 0b00001100) >> 2) << 18) | + (((z & 0b00010000) >> 4) << 23) | (((z & 0b11100000) >> 5) << 25); + } + } + + } else { this->partial_buffer_ = allocator.allocate(buffer_size); if (this->partial_buffer_ == nullptr) { ESP_LOGE(TAG, "Could not allocate partial buffer for display!"); @@ -73,13 +119,16 @@ void Inkplate6::initialize_() { this->mark_failed(); return; } + memset(this->partial_buffer_, 0, buffer_size); memset(this->partial_buffer_2_, 0, buffer_size * 2); } memset(this->buffer_, 0, buffer_size); } + float Inkplate6::get_setup_priority() const { return setup_priority::PROCESSOR; } + size_t Inkplate6::get_buffer_length_() { if (this->greyscale_) { return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 2u; @@ -87,6 +136,7 @@ size_t Inkplate6::get_buffer_length_() { return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u; } } + void Inkplate6::update() { this->do_update_(); @@ -96,6 +146,7 @@ void Inkplate6::update() { this->display(); } + void HOT Inkplate6::draw_absolute_pixel_internal(int x, int y, Color color) { if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0) return; @@ -121,6 +172,7 @@ void HOT Inkplate6::draw_absolute_pixel_internal(int x, int y, Color color) { this->partial_buffer_[pos] = (~pixelMaskLUT[x_sub] & current) | (color.is_on() ? 0 : pixelMaskLUT[x_sub]); } } + void Inkplate6::dump_config() { LOG_DISPLAY("", "Inkplate", this); ESP_LOGCONFIG(TAG, " Greyscale: %s", YESNO(this->greyscale_)); @@ -150,44 +202,51 @@ void Inkplate6::dump_config() { LOG_UPDATE_INTERVAL(this); } + void Inkplate6::eink_off_() { ESP_LOGV(TAG, "Eink off called"); - if (panel_on_ == 0) + if (!panel_on_) return; - panel_on_ = 0; - this->gmod_pin_->digital_write(false); + panel_on_ = false; + this->oe_pin_->digital_write(false); + this->gmod_pin_->digital_write(false); - GPIO.out &= ~(get_data_pin_mask_() | (1 << this->cl_pin_->get_pin()) | (1 << this->le_pin_->get_pin())); - + GPIO.out &= ~(this->get_data_pin_mask_() | (1 << this->cl_pin_->get_pin()) | (1 << this->le_pin_->get_pin())); + this->ckv_pin_->digital_write(false); this->sph_pin_->digital_write(false); this->spv_pin_->digital_write(false); - this->powerup_pin_->digital_write(false); - this->wakeup_pin_->digital_write(false); this->vcom_pin_->digital_write(false); + this->write_byte(0x01, 0x6F); // Put TPS65186 into standby mode + + delay(100); // NOLINT + + this->write_byte(0x01, 0x4f); // Disable 3V3 to the panel + + if (this->model_ != INKPLATE_6_PLUS) + this->wakeup_pin_->digital_write(false); + pins_z_state_(); } + void Inkplate6::eink_on_() { ESP_LOGV(TAG, "Eink on called"); - if (panel_on_ == 1) + if (panel_on_) return; - panel_on_ = 1; - pins_as_outputs_(); + this->panel_on_ = true; + + this->pins_as_outputs_(); this->wakeup_pin_->digital_write(true); - this->powerup_pin_->digital_write(true); this->vcom_pin_->digital_write(true); - - this->write_byte(0x01, 0x3F); - - delay(40); - - this->write_byte(0x0D, 0x80); - delay(2); - this->read_register(0x00, nullptr, 0); + this->write_byte(0x01, 0b00101111); // Enable all rails + + delay(1); + + this->write_byte(0x01, 0b10101111); // Switch TPS65186 into active mode this->le_pin_->digital_write(false); this->oe_pin_->digital_write(false); @@ -196,8 +255,33 @@ void Inkplate6::eink_on_() { this->gmod_pin_->digital_write(true); this->spv_pin_->digital_write(true); this->ckv_pin_->digital_write(false); + this->oe_pin_->digital_write(false); + + uint32_t timer = millis(); + do { + delay(1); + } while (!this->read_power_status_() && ((millis() - timer) < 250)); + if ((millis() - timer) >= 250) { + ESP_LOGW(TAG, "Power supply not detected"); + this->wakeup_pin_->digital_write(false); + this->vcom_pin_->digital_write(false); + this->powerup_pin_->digital_write(false); + this->panel_on_ = false; + return; + } + this->oe_pin_->digital_write(true); } + +bool Inkplate6::read_power_status_() { + uint8_t data; + auto err = this->read_register(0x0F, &data, 1); + if (err == i2c::ERROR_OK) { + return data == 0b11111010; + } + return false; +} + void Inkplate6::fill(Color color) { ESP_LOGV(TAG, "Fill called"); uint32_t start_time = millis(); @@ -212,6 +296,7 @@ void Inkplate6::fill(Color color) { ESP_LOGV(TAG, "Fill finished (%ums)", millis() - start_time); } + void Inkplate6::display() { ESP_LOGV(TAG, "Display called"); uint32_t start_time = millis(); @@ -227,201 +312,185 @@ void Inkplate6::display() { } ESP_LOGV(TAG, "Display finished (full) (%ums)", millis() - start_time); } + void Inkplate6::display1b_() { ESP_LOGV(TAG, "Display1b called"); uint32_t start_time = millis(); memcpy(this->buffer_, this->partial_buffer_, this->get_buffer_length_()); - uint32_t send; uint8_t data; uint8_t buffer_value; const uint8_t *buffer_ptr; eink_on_(); - clean_fast_(0, 1); - clean_fast_(1, 5); - clean_fast_(2, 1); - clean_fast_(0, 5); - clean_fast_(2, 1); - clean_fast_(1, 12); - clean_fast_(2, 1); - clean_fast_(0, 11); + if (this->model_ == INKPLATE_6_PLUS) { + clean_fast_(0, 1); + clean_fast_(1, 15); + clean_fast_(2, 1); + clean_fast_(0, 5); + clean_fast_(2, 1); + clean_fast_(1, 15); + } else { + clean_fast_(0, 1); + clean_fast_(1, 21); + clean_fast_(2, 1); + clean_fast_(0, 12); + clean_fast_(2, 1); + clean_fast_(1, 21); + clean_fast_(2, 1); + clean_fast_(0, 12); + } uint32_t clock = (1 << this->cl_pin_->get_pin()); + uint32_t data_mask = this->get_data_pin_mask_(); ESP_LOGV(TAG, "Display1b start loops (%ums)", millis() - start_time); - for (int k = 0; k < 3; k++) { + + for (int k = 0; k < 4; k++) { buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1]; vscan_start_(); - for (int i = 0; i < this->get_height_internal(); i++) { + for (int i = 0, im = this->get_height_internal(); i < im; i++) { buffer_value = *(buffer_ptr--); - data = LUTB[(buffer_value >> 4) & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25); - hscan_start_(send); - data = LUTB[buffer_value & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; + data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F]; + hscan_start_(this->pin_lut_[data]); + data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F]; + GPIO.out_w1ts = this->pin_lut_[data] | clock; + GPIO.out_w1tc = data_mask | clock; for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) { buffer_value = *(buffer_ptr--); - data = LUTB[(buffer_value >> 4) & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; - data = LUTB[buffer_value & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; + data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F]; + GPIO.out_w1ts = this->pin_lut_[data] | clock; + GPIO.out_w1tc = data_mask | clock; + data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F]; + GPIO.out_w1ts = this->pin_lut_[data] | clock; + GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = send; - GPIO.out_w1tc = get_data_pin_mask_() | clock; + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; vscan_end_(); } delayMicroseconds(230); } - ESP_LOGV(TAG, "Display1b first loop x %d (%ums)", 3, millis() - start_time); + ESP_LOGV(TAG, "Display1b first loop x %d (%ums)", 4, millis() - start_time); buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1]; vscan_start_(); - for (int i = 0; i < this->get_height_internal(); i++) { + for (int i = 0, im = this->get_height_internal(); i < im; i++) { buffer_value = *(buffer_ptr--); - data = LUT2[(buffer_value >> 4) & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25); - hscan_start_(send); - data = LUT2[buffer_value & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; + data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F]; + hscan_start_(this->pin_lut_[data] | clock); + data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F]; + GPIO.out_w1ts = this->pin_lut_[data] | clock; + GPIO.out_w1tc = data_mask | clock; + for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) { buffer_value = *(buffer_ptr--); - data = LUT2[(buffer_value >> 4) & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; - data = LUT2[buffer_value & 0x0F]; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; + data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F]; + GPIO.out_w1ts = this->pin_lut_[data] | clock; + GPIO.out_w1tc = data_mask | clock; + data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F]; + GPIO.out_w1ts = this->pin_lut_[data] | clock; + GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = send; - GPIO.out_w1tc = get_data_pin_mask_() | clock; + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; vscan_end_(); } delayMicroseconds(230); ESP_LOGV(TAG, "Display1b second loop (%ums)", millis() - start_time); - vscan_start_(); - for (int i = 0; i < this->get_height_internal(); i++) { - data = 0b00000000; - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25); - hscan_start_(send); - send |= clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; - for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) { - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; + if (this->model_ == INKPLATE_6_PLUS) { + clean_fast_(2, 2); + clean_fast_(3, 1); + } else { + uint32_t send = this->pin_lut_[0]; + vscan_start_(); + for (int i = 0, im = this->get_height_internal(); i < im; i++) { + hscan_start_(send); + GPIO.out_w1ts = send | clock; + GPIO.out_w1tc = data_mask | clock; + for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) { + GPIO.out_w1ts = send | clock; + GPIO.out_w1tc = data_mask | clock; + GPIO.out_w1ts = send | clock; + GPIO.out_w1tc = data_mask | clock; + } + GPIO.out_w1ts = send | clock; + GPIO.out_w1tc = data_mask | clock; + vscan_end_(); } - GPIO.out_w1ts = clock; - GPIO.out_w1tc = get_data_pin_mask_() | clock; - vscan_end_(); + delayMicroseconds(230); + ESP_LOGV(TAG, "Display1b third loop (%ums)", millis() - start_time); } - delayMicroseconds(230); - ESP_LOGV(TAG, "Display1b third loop (%ums)", millis() - start_time); - vscan_start_(); eink_off_(); this->block_partial_ = false; this->partial_updates_ = 0; ESP_LOGV(TAG, "Display1b finished (%ums)", millis() - start_time); } + void Inkplate6::display3b_() { ESP_LOGV(TAG, "Display3b called"); uint32_t start_time = millis(); eink_on_(); - clean_fast_(0, 1); - clean_fast_(1, 12); - clean_fast_(2, 1); - clean_fast_(0, 11); - clean_fast_(2, 1); - clean_fast_(1, 12); - clean_fast_(2, 1); - clean_fast_(0, 11); + if (this->model_ == INKPLATE_6_PLUS) { + clean_fast_(0, 1); + clean_fast_(1, 15); + clean_fast_(2, 1); + clean_fast_(0, 5); + clean_fast_(2, 1); + clean_fast_(1, 15); + } else { + clean_fast_(0, 1); + clean_fast_(1, 21); + clean_fast_(2, 1); + clean_fast_(0, 12); + clean_fast_(2, 1); + clean_fast_(1, 21); + clean_fast_(2, 1); + clean_fast_(0, 12); + } uint32_t clock = (1 << this->cl_pin_->get_pin()); - for (int k = 0; k < 8; k++) { - const uint8_t *buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1]; - uint32_t send; - uint8_t pix1; - uint8_t pix2; - uint8_t pix3; - uint8_t pix4; - uint8_t pixel; - uint8_t pixel2; - + uint32_t data_mask = this->get_data_pin_mask_(); + uint32_t pos; + uint32_t data; + uint8_t glut_size = this->model_ == INKPLATE_6_PLUS ? 9 : 8; + for (int k = 0; k < glut_size; k++) { + pos = this->get_buffer_length_(); vscan_start_(); for (int i = 0; i < this->get_height_internal(); i++) { - pix1 = (*buffer_ptr--); - pix2 = (*buffer_ptr--); - pix3 = (*buffer_ptr--); - pix4 = (*buffer_ptr--); - pixel = (waveform3Bit[pix1 & 0x07][k] << 6) | (waveform3Bit[(pix1 >> 4) & 0x07][k] << 4) | - (waveform3Bit[pix2 & 0x07][k] << 2) | (waveform3Bit[(pix2 >> 4) & 0x07][k] << 0); - pixel2 = (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | - (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); + data = this->glut2_[k * 256 + this->buffer_[--pos]]; + data |= this->glut_[k * 256 + this->buffer_[--pos]]; + hscan_start_(data); + data = this->glut2_[k * 256 + this->buffer_[--pos]]; + data |= this->glut_[k * 256 + this->buffer_[--pos]]; + GPIO.out_w1ts = data | clock; + GPIO.out_w1tc = data_mask | clock; - send = ((pixel & 0b00000011) << 4) | (((pixel & 0b00001100) >> 2) << 18) | (((pixel & 0b00010000) >> 4) << 23) | - (((pixel & 0b11100000) >> 5) << 25); - hscan_start_(send); - send = ((pixel2 & 0b00000011) << 4) | (((pixel2 & 0b00001100) >> 2) << 18) | - (((pixel2 & 0b00010000) >> 4) << 23) | (((pixel2 & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; - - for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) { - pix1 = (*buffer_ptr--); - pix2 = (*buffer_ptr--); - pix3 = (*buffer_ptr--); - pix4 = (*buffer_ptr--); - pixel = (waveform3Bit[pix1 & 0x07][k] << 6) | (waveform3Bit[(pix1 >> 4) & 0x07][k] << 4) | - (waveform3Bit[pix2 & 0x07][k] << 2) | (waveform3Bit[(pix2 >> 4) & 0x07][k] << 0); - pixel2 = (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | - (waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0); - - send = ((pixel & 0b00000011) << 4) | (((pixel & 0b00001100) >> 2) << 18) | (((pixel & 0b00010000) >> 4) << 23) | - (((pixel & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; - - send = ((pixel2 & 0b00000011) << 4) | (((pixel2 & 0b00001100) >> 2) << 18) | - (((pixel2 & 0b00010000) >> 4) << 23) | (((pixel2 & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; + for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) { + data = this->glut2_[k * 256 + this->buffer_[--pos]]; + data |= this->glut_[k * 256 + this->buffer_[--pos]]; + GPIO.out_w1ts = data | clock; + GPIO.out_w1tc = data_mask | clock; + data = this->glut2_[k * 256 + this->buffer_[--pos]]; + data |= this->glut_[k * 256 + this->buffer_[--pos]]; + GPIO.out_w1ts = data | clock; + GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = send; - GPIO.out_w1tc = get_data_pin_mask_() | clock; + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; vscan_end_(); } delayMicroseconds(230); } - clean_fast_(2, 1); clean_fast_(3, 1); vscan_start_(); eink_off_(); ESP_LOGV(TAG, "Display3b finished (%ums)", millis() - start_time); } + bool Inkplate6::partial_update_() { ESP_LOGV(TAG, "Partial update called"); uint32_t start_time = millis(); @@ -432,16 +501,15 @@ bool Inkplate6::partial_update_() { this->partial_updates_++; - uint16_t pos = this->get_buffer_length_() - 1; - uint32_t send; + uint32_t pos = this->get_buffer_length_() - 1; uint8_t data; uint8_t diffw, diffb; uint32_t n = (this->get_buffer_length_() * 2) - 1; for (int i = 0, im = this->get_height_internal(); i < im; i++) { for (int j = 0, jm = (this->get_width_internal() / 8); j < jm; j++) { - diffw = (this->buffer_[pos] ^ this->partial_buffer_[pos]) & ~(this->partial_buffer_[pos]); - diffb = (this->buffer_[pos] ^ this->partial_buffer_[pos]) & this->partial_buffer_[pos]; + diffw = this->buffer_[pos] & ~(this->partial_buffer_[pos]); + diffb = ~(this->buffer_[pos]) & this->partial_buffer_[pos]; pos--; this->partial_buffer_2_[n--] = LUTW[diffw >> 4] & LUTB[diffb >> 4]; this->partial_buffer_2_[n--] = LUTW[diffw & 0x0F] & LUTB[diffb & 0x0F]; @@ -451,23 +519,20 @@ bool Inkplate6::partial_update_() { eink_on_(); uint32_t clock = (1 << this->cl_pin_->get_pin()); + uint32_t data_mask = this->get_data_pin_mask_(); for (int k = 0; k < 5; k++) { vscan_start_(); const uint8_t *data_ptr = &this->partial_buffer_2_[(this->get_buffer_length_() * 2) - 1]; for (int i = 0; i < this->get_height_internal(); i++) { data = *(data_ptr--); - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25); - hscan_start_(send); + hscan_start_(this->pin_lut_[data]); for (int j = 0, jm = (this->get_width_internal() / 4) - 1; j < jm; j++) { data = *(data_ptr--); - send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | - (((data & 0b11100000) >> 5) << 25) | clock; - GPIO.out_w1ts = send; - GPIO.out_w1tc = send; + GPIO.out_w1ts = this->pin_lut_[data] | clock; + GPIO.out_w1tc = data_mask | clock; } - GPIO.out_w1ts = send; - GPIO.out_w1tc = get_data_pin_mask_() | clock; + GPIO.out_w1ts = clock; + GPIO.out_w1tc = data_mask | clock; vscan_end_(); } delayMicroseconds(230); @@ -482,6 +547,7 @@ bool Inkplate6::partial_update_() { ESP_LOGV(TAG, "Partial update finished (%ums)", millis() - start_time); return true; } + void Inkplate6::vscan_start_() { this->ckv_pin_->digital_write(true); delayMicroseconds(7); @@ -505,30 +571,23 @@ void Inkplate6::vscan_start_() { delayMicroseconds(0); this->ckv_pin_->digital_write(true); } -void Inkplate6::vscan_write_() { - this->ckv_pin_->digital_write(false); - this->le_pin_->digital_write(true); - this->le_pin_->digital_write(false); - delayMicroseconds(0); + +void Inkplate6::hscan_start_(uint32_t d) { + uint8_t clock = (1 << this->cl_pin_->get_pin()); this->sph_pin_->digital_write(false); - this->cl_pin_->digital_write(true); - this->cl_pin_->digital_write(false); + GPIO.out_w1ts = d | clock; + GPIO.out_w1tc = this->get_data_pin_mask_() | clock; this->sph_pin_->digital_write(true); this->ckv_pin_->digital_write(true); } -void Inkplate6::hscan_start_(uint32_t d) { - this->sph_pin_->digital_write(false); - GPIO.out_w1ts = (d) | (1 << this->cl_pin_->get_pin()); - GPIO.out_w1tc = get_data_pin_mask_() | (1 << this->cl_pin_->get_pin()); - this->sph_pin_->digital_write(true); -} + void Inkplate6::vscan_end_() { this->ckv_pin_->digital_write(false); this->le_pin_->digital_write(true); this->le_pin_->digital_write(false); - delayMicroseconds(1); - this->ckv_pin_->digital_write(true); + delayMicroseconds(0); } + void Inkplate6::clean() { ESP_LOGV(TAG, "Clean called"); uint32_t start_time = millis(); @@ -542,6 +601,7 @@ void Inkplate6::clean() { clean_fast_(1, 10); // White to White ESP_LOGV(TAG, "Clean finished (%ums)", millis() - start_time); } + void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) { ESP_LOGV(TAG, "Clean fast called with: (%d, %d)", c, rep); uint32_t start_time = millis(); @@ -568,14 +628,14 @@ void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) { hscan_start_(send); GPIO.out_w1ts = send | clock; GPIO.out_w1tc = clock; - for (int j = 0, jm = this->get_width_internal() / 8; j < jm; j++) { + for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) { GPIO.out_w1ts = clock; GPIO.out_w1tc = clock; GPIO.out_w1ts = clock; GPIO.out_w1tc = clock; } - GPIO.out_w1ts = clock; - GPIO.out_w1tc = get_data_pin_mask_() | clock; + GPIO.out_w1ts = send | clock; + GPIO.out_w1tc = clock; vscan_end_(); } delayMicroseconds(230); @@ -583,7 +643,10 @@ void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) { } ESP_LOGV(TAG, "Clean fast finished (%ums)", millis() - start_time); } + void Inkplate6::pins_z_state_() { + this->cl_pin_->pin_mode(gpio::FLAG_INPUT); + this->le_pin_->pin_mode(gpio::FLAG_INPUT); this->ckv_pin_->pin_mode(gpio::FLAG_INPUT); this->sph_pin_->pin_mode(gpio::FLAG_INPUT); @@ -600,7 +663,10 @@ void Inkplate6::pins_z_state_() { this->display_data_6_pin_->pin_mode(gpio::FLAG_INPUT); this->display_data_7_pin_->pin_mode(gpio::FLAG_INPUT); } + void Inkplate6::pins_as_outputs_() { + this->cl_pin_->pin_mode(gpio::FLAG_OUTPUT); + this->le_pin_->pin_mode(gpio::FLAG_OUTPUT); this->ckv_pin_->pin_mode(gpio::FLAG_OUTPUT); this->sph_pin_->pin_mode(gpio::FLAG_OUTPUT); diff --git a/esphome/components/inkplate6/inkplate.h b/esphome/components/inkplate6/inkplate.h index 6cbb24805d..9355154c5a 100644 --- a/esphome/components/inkplate6/inkplate.h +++ b/esphome/components/inkplate6/inkplate.h @@ -13,32 +13,28 @@ namespace inkplate6 { enum InkplateModel : uint8_t { INKPLATE_6 = 0, INKPLATE_10 = 1, + INKPLATE_6_PLUS = 2, }; class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public i2c::I2CDevice { public: - const uint8_t LUT2[16] = {0b10101010, 0b10101001, 0b10100110, 0b10100101, 0b10011010, 0b10011001, - 0b10010110, 0b10010101, 0b01101010, 0b01101001, 0b01100110, 0b01100101, - 0b01011010, 0b01011001, 0b01010110, 0b01010101}; - const uint8_t LUTW[16] = {0b11111111, 0b11111110, 0b11111011, 0b11111010, 0b11101111, 0b11101110, - 0b11101011, 0b11101010, 0b10111111, 0b10111110, 0b10111011, 0b10111010, - 0b10101111, 0b10101110, 0b10101011, 0b10101010}; - const uint8_t LUTB[16] = {0b11111111, 0b11111101, 0b11110111, 0b11110101, 0b11011111, 0b11011101, - 0b11010111, 0b11010101, 0b01111111, 0b01111101, 0b01110111, 0b01110101, - 0b01011111, 0b01011101, 0b01010111, 0b01010101}; - const uint8_t pixelMaskLUT[8] = {0b00000001, 0b00000010, 0b00000100, 0b00001000, - 0b00010000, 0b00100000, 0b01000000, 0b10000000}; - const uint8_t pixelMaskGLUT[2] = {0b00001111, 0b11110000}; - const uint8_t waveform3Bit[8][8] = {{0, 0, 0, 0, 1, 1, 1, 0}, {1, 2, 2, 2, 1, 1, 1, 0}, {0, 1, 2, 1, 1, 2, 1, 0}, - {0, 2, 1, 2, 1, 2, 1, 0}, {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0}, + const uint8_t LUT2[16] = {0xAA, 0xA9, 0xA6, 0xA5, 0x9A, 0x99, 0x96, 0x95, + 0x6A, 0x69, 0x66, 0x65, 0x5A, 0x59, 0x56, 0x55}; + const uint8_t LUTW[16] = {0xFF, 0xFE, 0xFB, 0xFA, 0xEF, 0xEE, 0xEB, 0xEA, + 0xBF, 0xBE, 0xBB, 0xBA, 0xAF, 0xAE, 0xAB, 0xAA}; + const uint8_t LUTB[16] = {0xFF, 0xFD, 0xF7, 0xF5, 0xDF, 0xDD, 0xD7, 0xD5, + 0x7F, 0x7D, 0x77, 0x75, 0x5F, 0x5D, 0x57, 0x55}; + + const uint8_t pixelMaskLUT[8] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80}; + const uint8_t pixelMaskGLUT[2] = {0x0F, 0xF0}; + + const uint8_t waveform3Bit[8][8] = {{0, 1, 1, 0, 0, 1, 1, 0}, {0, 1, 2, 1, 1, 2, 1, 0}, {1, 1, 1, 2, 2, 1, 0, 0}, + {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0}, {2, 2, 1, 1, 2, 1, 2, 0}, {1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}}; - const uint32_t waveform[50] = { - 0x00000008, 0x00000008, 0x00200408, 0x80281888, 0x60a81898, 0x60a8a8a8, 0x60a8a8a8, 0x6068a868, 0x6868a868, - 0x6868a868, 0x68686868, 0x6a686868, 0x5a686868, 0x5a686868, 0x5a586a68, 0x5a5a6a68, 0x5a5a6a68, 0x55566a68, - 0x55565a64, 0x55555654, 0x55555556, 0x55555556, 0x55555556, 0x55555516, 0x55555596, 0x15555595, 0x95955595, - 0x95959595, 0x95949495, 0x94949495, 0x94949495, 0xa4949494, 0x9494a4a4, 0x84a49494, 0x84948484, 0x84848484, - 0x84848484, 0x84848484, 0xa5a48484, 0xa9a4a4a8, 0xa9a8a8a8, 0xa5a9a9a4, 0xa5a5a5a4, 0xa1a5a5a1, 0xa9a9a9a9, - 0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0x15151515, 0x11111111}; + const uint8_t waveform3Bit6Plus[8][9] = {{0, 0, 0, 0, 0, 2, 1, 1, 0}, {0, 0, 2, 1, 1, 1, 2, 1, 0}, + {0, 2, 2, 2, 1, 1, 2, 1, 0}, {0, 0, 2, 2, 2, 1, 2, 1, 0}, + {0, 0, 0, 0, 2, 2, 2, 1, 0}, {0, 0, 2, 1, 2, 1, 1, 2, 0}, + {0, 0, 2, 2, 2, 1, 1, 2, 0}, {0, 0, 0, 0, 2, 2, 2, 2, 0}}; void set_greyscale(bool greyscale) { this->greyscale_ = greyscale; @@ -88,6 +84,8 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public bool get_partial_updating() { return this->partial_updating_; } uint8_t get_temperature() { return this->temperature_; } + void block_partial() { this->block_partial_ = true; } + protected: void draw_absolute_pixel_internal(int x, int y, Color color) override; void display1b_(); @@ -99,10 +97,10 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public void hscan_start_(uint32_t d); void vscan_end_(); void vscan_start_(); - void vscan_write_(); void eink_off_(); void eink_on_(); + bool read_power_status_(); void setup_pins_(); void pins_z_state_(); @@ -113,6 +111,8 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public return 800; } else if (this->model_ == INKPLATE_10) { return 1200; + } else if (this->model_ == INKPLATE_6_PLUS) { + return 1024; } return 0; } @@ -122,6 +122,8 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public return 600; } else if (this->model_ == INKPLATE_10) { return 825; + } else if (this->model_ == INKPLATE_6_PLUS) { + return 758; } return 0; } @@ -141,16 +143,20 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public return data; } - uint8_t panel_on_ = 0; + bool panel_on_{false}; uint8_t temperature_; uint8_t *partial_buffer_{nullptr}; uint8_t *partial_buffer_2_{nullptr}; + uint32_t *glut_{nullptr}; + uint32_t *glut2_{nullptr}; + uint32_t pin_lut_[256]; + uint32_t full_update_every_; uint32_t partial_updates_{0}; - bool block_partial_; + bool block_partial_{true}; bool greyscale_; bool partial_updating_;