Inkplate 6 PLUS (#3013)

This commit is contained in:
Jesse Hills 2022-02-08 22:56:56 +13:00 committed by GitHub
parent 4aeacfd16e
commit c66d0550e8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 281 additions and 208 deletions

View file

@ -47,6 +47,7 @@ InkplateModel = inkplate6_ns.enum("InkplateModel")
MODELS = { MODELS = {
"inkplate_6": InkplateModel.INKPLATE_6, "inkplate_6": InkplateModel.INKPLATE_6,
"inkplate_10": InkplateModel.INKPLATE_10, "inkplate_10": InkplateModel.INKPLATE_10,
"inkplate_6_plus": InkplateModel.INKPLATE_6_PLUS,
} }
CONFIG_SCHEMA = cv.All( CONFIG_SCHEMA = cv.All(

View file

@ -13,6 +13,11 @@ namespace inkplate6 {
static const char *const TAG = "inkplate"; static const char *const TAG = "inkplate";
void Inkplate6::setup() { 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->initialize_();
this->vcom_pin_->setup(); this->vcom_pin_->setup();
@ -38,11 +43,21 @@ void Inkplate6::setup() {
this->display_data_6_pin_->setup(); this->display_data_6_pin_->setup();
this->display_data_7_pin_->setup(); this->display_data_7_pin_->setup();
this->clean(); this->wakeup_pin_->digital_write(true);
this->display(); 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_() { void Inkplate6::initialize_() {
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE); ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
ExternalRAMAllocator<uint32_t> allocator32(ExternalRAMAllocator<uint32_t>::ALLOW_FAILURE);
uint32_t buffer_size = this->get_buffer_length_(); uint32_t buffer_size = this->get_buffer_length_();
if (buffer_size == 0) if (buffer_size == 0)
return; return;
@ -53,6 +68,10 @@ void Inkplate6::initialize_() {
allocator.deallocate(this->partial_buffer_2_, buffer_size * 2); allocator.deallocate(this->partial_buffer_2_, buffer_size * 2);
if (this->buffer_ != nullptr) if (this->buffer_ != nullptr)
allocator.deallocate(this->buffer_, buffer_size); 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); this->buffer_ = allocator.allocate(buffer_size);
if (this->buffer_ == nullptr) { if (this->buffer_ == nullptr) {
@ -60,7 +79,34 @@ void Inkplate6::initialize_() {
this->mark_failed(); this->mark_failed();
return; 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); this->partial_buffer_ = allocator.allocate(buffer_size);
if (this->partial_buffer_ == nullptr) { if (this->partial_buffer_ == nullptr) {
ESP_LOGE(TAG, "Could not allocate partial buffer for display!"); ESP_LOGE(TAG, "Could not allocate partial buffer for display!");
@ -73,13 +119,16 @@ void Inkplate6::initialize_() {
this->mark_failed(); this->mark_failed();
return; return;
} }
memset(this->partial_buffer_, 0, buffer_size); memset(this->partial_buffer_, 0, buffer_size);
memset(this->partial_buffer_2_, 0, buffer_size * 2); memset(this->partial_buffer_2_, 0, buffer_size * 2);
} }
memset(this->buffer_, 0, buffer_size); memset(this->buffer_, 0, buffer_size);
} }
float Inkplate6::get_setup_priority() const { return setup_priority::PROCESSOR; } float Inkplate6::get_setup_priority() const { return setup_priority::PROCESSOR; }
size_t Inkplate6::get_buffer_length_() { size_t Inkplate6::get_buffer_length_() {
if (this->greyscale_) { if (this->greyscale_) {
return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 2u; 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; return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u;
} }
} }
void Inkplate6::update() { void Inkplate6::update() {
this->do_update_(); this->do_update_();
@ -96,6 +146,7 @@ void Inkplate6::update() {
this->display(); this->display();
} }
void HOT Inkplate6::draw_absolute_pixel_internal(int x, int y, Color color) { 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) if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
return; 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]); this->partial_buffer_[pos] = (~pixelMaskLUT[x_sub] & current) | (color.is_on() ? 0 : pixelMaskLUT[x_sub]);
} }
} }
void Inkplate6::dump_config() { void Inkplate6::dump_config() {
LOG_DISPLAY("", "Inkplate", this); LOG_DISPLAY("", "Inkplate", this);
ESP_LOGCONFIG(TAG, " Greyscale: %s", YESNO(this->greyscale_)); ESP_LOGCONFIG(TAG, " Greyscale: %s", YESNO(this->greyscale_));
@ -150,44 +202,51 @@ void Inkplate6::dump_config() {
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }
void Inkplate6::eink_off_() { void Inkplate6::eink_off_() {
ESP_LOGV(TAG, "Eink off called"); ESP_LOGV(TAG, "Eink off called");
if (panel_on_ == 0) if (!panel_on_)
return; return;
panel_on_ = 0; panel_on_ = false;
this->gmod_pin_->digital_write(false);
this->oe_pin_->digital_write(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->sph_pin_->digital_write(false);
this->spv_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->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_(); pins_z_state_();
} }
void Inkplate6::eink_on_() { void Inkplate6::eink_on_() {
ESP_LOGV(TAG, "Eink on called"); ESP_LOGV(TAG, "Eink on called");
if (panel_on_ == 1) if (panel_on_)
return; return;
panel_on_ = 1; this->panel_on_ = true;
pins_as_outputs_();
this->pins_as_outputs_();
this->wakeup_pin_->digital_write(true); this->wakeup_pin_->digital_write(true);
this->powerup_pin_->digital_write(true);
this->vcom_pin_->digital_write(true); this->vcom_pin_->digital_write(true);
this->write_byte(0x01, 0x3F);
delay(40);
this->write_byte(0x0D, 0x80);
delay(2); 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->le_pin_->digital_write(false);
this->oe_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->gmod_pin_->digital_write(true);
this->spv_pin_->digital_write(true); this->spv_pin_->digital_write(true);
this->ckv_pin_->digital_write(false); 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); 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) { void Inkplate6::fill(Color color) {
ESP_LOGV(TAG, "Fill called"); ESP_LOGV(TAG, "Fill called");
uint32_t start_time = millis(); uint32_t start_time = millis();
@ -212,6 +296,7 @@ void Inkplate6::fill(Color color) {
ESP_LOGV(TAG, "Fill finished (%ums)", millis() - start_time); ESP_LOGV(TAG, "Fill finished (%ums)", millis() - start_time);
} }
void Inkplate6::display() { void Inkplate6::display() {
ESP_LOGV(TAG, "Display called"); ESP_LOGV(TAG, "Display called");
uint32_t start_time = millis(); uint32_t start_time = millis();
@ -227,201 +312,185 @@ void Inkplate6::display() {
} }
ESP_LOGV(TAG, "Display finished (full) (%ums)", millis() - start_time); ESP_LOGV(TAG, "Display finished (full) (%ums)", millis() - start_time);
} }
void Inkplate6::display1b_() { void Inkplate6::display1b_() {
ESP_LOGV(TAG, "Display1b called"); ESP_LOGV(TAG, "Display1b called");
uint32_t start_time = millis(); uint32_t start_time = millis();
memcpy(this->buffer_, this->partial_buffer_, this->get_buffer_length_()); memcpy(this->buffer_, this->partial_buffer_, this->get_buffer_length_());
uint32_t send;
uint8_t data; uint8_t data;
uint8_t buffer_value; uint8_t buffer_value;
const uint8_t *buffer_ptr; const uint8_t *buffer_ptr;
eink_on_(); eink_on_();
clean_fast_(0, 1); if (this->model_ == INKPLATE_6_PLUS) {
clean_fast_(1, 5); clean_fast_(0, 1);
clean_fast_(2, 1); clean_fast_(1, 15);
clean_fast_(0, 5); clean_fast_(2, 1);
clean_fast_(2, 1); clean_fast_(0, 5);
clean_fast_(1, 12); clean_fast_(2, 1);
clean_fast_(2, 1); clean_fast_(1, 15);
clean_fast_(0, 11); } 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 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); 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]; buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1];
vscan_start_(); 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--); buffer_value = *(buffer_ptr--);
data = LUTB[(buffer_value >> 4) & 0x0F]; data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F];
send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | hscan_start_(this->pin_lut_[data]);
(((data & 0b11100000) >> 5) << 25); data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F];
hscan_start_(send); GPIO.out_w1ts = this->pin_lut_[data] | clock;
data = LUTB[buffer_value & 0x0F]; GPIO.out_w1tc = data_mask | clock;
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;
for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) { for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
buffer_value = *(buffer_ptr--); buffer_value = *(buffer_ptr--);
data = LUTB[(buffer_value >> 4) & 0x0F]; data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value >> 4) & 0x0F] : LUTB[(buffer_value >> 4) & 0x0F];
send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | GPIO.out_w1ts = this->pin_lut_[data] | clock;
(((data & 0b11100000) >> 5) << 25) | clock; GPIO.out_w1tc = data_mask | clock;
GPIO.out_w1ts = send; data = this->model_ == INKPLATE_6_PLUS ? LUTW[(~buffer_value) & 0x0F] : LUTB[buffer_value & 0x0F];
GPIO.out_w1tc = send; GPIO.out_w1ts = this->pin_lut_[data] | clock;
data = LUTB[buffer_value & 0x0F]; GPIO.out_w1tc = data_mask | clock;
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 = send; GPIO.out_w1ts = clock;
GPIO.out_w1tc = get_data_pin_mask_() | clock; GPIO.out_w1tc = data_mask | clock;
vscan_end_(); vscan_end_();
} }
delayMicroseconds(230); 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]; buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1];
vscan_start_(); 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--); buffer_value = *(buffer_ptr--);
data = LUT2[(buffer_value >> 4) & 0x0F]; data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F];
send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | hscan_start_(this->pin_lut_[data] | clock);
(((data & 0b11100000) >> 5) << 25); data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F];
hscan_start_(send); GPIO.out_w1ts = this->pin_lut_[data] | clock;
data = LUT2[buffer_value & 0x0F]; GPIO.out_w1tc = data_mask | clock;
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;
for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) { for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
buffer_value = *(buffer_ptr--); buffer_value = *(buffer_ptr--);
data = LUT2[(buffer_value >> 4) & 0x0F]; data = this->model_ == INKPLATE_6_PLUS ? LUTB[(buffer_value >> 4) & 0x0F] : LUT2[(buffer_value >> 4) & 0x0F];
send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | GPIO.out_w1ts = this->pin_lut_[data] | clock;
(((data & 0b11100000) >> 5) << 25) | clock; GPIO.out_w1tc = data_mask | clock;
GPIO.out_w1ts = send; data = this->model_ == INKPLATE_6_PLUS ? LUTB[buffer_value & 0x0F] : LUT2[buffer_value & 0x0F];
GPIO.out_w1tc = send; GPIO.out_w1ts = this->pin_lut_[data] | clock;
data = LUT2[buffer_value & 0x0F]; GPIO.out_w1tc = data_mask | clock;
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 = send; GPIO.out_w1ts = clock;
GPIO.out_w1tc = get_data_pin_mask_() | clock; GPIO.out_w1tc = data_mask | clock;
vscan_end_(); vscan_end_();
} }
delayMicroseconds(230); delayMicroseconds(230);
ESP_LOGV(TAG, "Display1b second loop (%ums)", millis() - start_time); ESP_LOGV(TAG, "Display1b second loop (%ums)", millis() - start_time);
vscan_start_(); if (this->model_ == INKPLATE_6_PLUS) {
for (int i = 0; i < this->get_height_internal(); i++) { clean_fast_(2, 2);
data = 0b00000000; clean_fast_(3, 1);
send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | } else {
(((data & 0b11100000) >> 5) << 25); uint32_t send = this->pin_lut_[0];
hscan_start_(send); vscan_start_();
send |= clock; for (int i = 0, im = this->get_height_internal(); i < im; i++) {
GPIO.out_w1ts = send; hscan_start_(send);
GPIO.out_w1tc = send; GPIO.out_w1ts = send | clock;
for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) { GPIO.out_w1tc = data_mask | clock;
GPIO.out_w1ts = send; for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) {
GPIO.out_w1tc = send; GPIO.out_w1ts = send | clock;
GPIO.out_w1ts = send; GPIO.out_w1tc = data_mask | clock;
GPIO.out_w1tc = send; 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; delayMicroseconds(230);
GPIO.out_w1tc = get_data_pin_mask_() | clock; ESP_LOGV(TAG, "Display1b third loop (%ums)", millis() - start_time);
vscan_end_();
} }
delayMicroseconds(230);
ESP_LOGV(TAG, "Display1b third loop (%ums)", millis() - start_time);
vscan_start_(); vscan_start_();
eink_off_(); eink_off_();
this->block_partial_ = false; this->block_partial_ = false;
this->partial_updates_ = 0; this->partial_updates_ = 0;
ESP_LOGV(TAG, "Display1b finished (%ums)", millis() - start_time); ESP_LOGV(TAG, "Display1b finished (%ums)", millis() - start_time);
} }
void Inkplate6::display3b_() { void Inkplate6::display3b_() {
ESP_LOGV(TAG, "Display3b called"); ESP_LOGV(TAG, "Display3b called");
uint32_t start_time = millis(); uint32_t start_time = millis();
eink_on_(); eink_on_();
clean_fast_(0, 1); if (this->model_ == INKPLATE_6_PLUS) {
clean_fast_(1, 12); clean_fast_(0, 1);
clean_fast_(2, 1); clean_fast_(1, 15);
clean_fast_(0, 11); clean_fast_(2, 1);
clean_fast_(2, 1); clean_fast_(0, 5);
clean_fast_(1, 12); clean_fast_(2, 1);
clean_fast_(2, 1); clean_fast_(1, 15);
clean_fast_(0, 11); } 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 clock = (1 << this->cl_pin_->get_pin());
for (int k = 0; k < 8; k++) { uint32_t data_mask = this->get_data_pin_mask_();
const uint8_t *buffer_ptr = &this->buffer_[this->get_buffer_length_() - 1]; uint32_t pos;
uint32_t send; uint32_t data;
uint8_t pix1; uint8_t glut_size = this->model_ == INKPLATE_6_PLUS ? 9 : 8;
uint8_t pix2; for (int k = 0; k < glut_size; k++) {
uint8_t pix3; pos = this->get_buffer_length_();
uint8_t pix4;
uint8_t pixel;
uint8_t pixel2;
vscan_start_(); vscan_start_();
for (int i = 0; i < this->get_height_internal(); i++) { for (int i = 0; i < this->get_height_internal(); i++) {
pix1 = (*buffer_ptr--); data = this->glut2_[k * 256 + this->buffer_[--pos]];
pix2 = (*buffer_ptr--); data |= this->glut_[k * 256 + this->buffer_[--pos]];
pix3 = (*buffer_ptr--); hscan_start_(data);
pix4 = (*buffer_ptr--); data = this->glut2_[k * 256 + this->buffer_[--pos]];
pixel = (waveform3Bit[pix1 & 0x07][k] << 6) | (waveform3Bit[(pix1 >> 4) & 0x07][k] << 4) | data |= this->glut_[k * 256 + this->buffer_[--pos]];
(waveform3Bit[pix2 & 0x07][k] << 2) | (waveform3Bit[(pix2 >> 4) & 0x07][k] << 0); GPIO.out_w1ts = data | clock;
pixel2 = (waveform3Bit[pix3 & 0x07][k] << 6) | (waveform3Bit[(pix3 >> 4) & 0x07][k] << 4) | GPIO.out_w1tc = data_mask | clock;
(waveform3Bit[pix4 & 0x07][k] << 2) | (waveform3Bit[(pix4 >> 4) & 0x07][k] << 0);
send = ((pixel & 0b00000011) << 4) | (((pixel & 0b00001100) >> 2) << 18) | (((pixel & 0b00010000) >> 4) << 23) | for (int j = 0; j < (this->get_width_internal() / 8) - 1; j++) {
(((pixel & 0b11100000) >> 5) << 25); data = this->glut2_[k * 256 + this->buffer_[--pos]];
hscan_start_(send); data |= this->glut_[k * 256 + this->buffer_[--pos]];
send = ((pixel2 & 0b00000011) << 4) | (((pixel2 & 0b00001100) >> 2) << 18) | GPIO.out_w1ts = data | clock;
(((pixel2 & 0b00010000) >> 4) << 23) | (((pixel2 & 0b11100000) >> 5) << 25) | clock; GPIO.out_w1tc = data_mask | clock;
GPIO.out_w1ts = send; data = this->glut2_[k * 256 + this->buffer_[--pos]];
GPIO.out_w1tc = send; data |= this->glut_[k * 256 + this->buffer_[--pos]];
GPIO.out_w1ts = data | clock;
for (int j = 0, jm = (this->get_width_internal() / 8) - 1; j < jm; j++) { GPIO.out_w1tc = data_mask | clock;
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;
} }
GPIO.out_w1ts = send; GPIO.out_w1ts = clock;
GPIO.out_w1tc = get_data_pin_mask_() | clock; GPIO.out_w1tc = data_mask | clock;
vscan_end_(); vscan_end_();
} }
delayMicroseconds(230); delayMicroseconds(230);
} }
clean_fast_(2, 1);
clean_fast_(3, 1); clean_fast_(3, 1);
vscan_start_(); vscan_start_();
eink_off_(); eink_off_();
ESP_LOGV(TAG, "Display3b finished (%ums)", millis() - start_time); ESP_LOGV(TAG, "Display3b finished (%ums)", millis() - start_time);
} }
bool Inkplate6::partial_update_() { bool Inkplate6::partial_update_() {
ESP_LOGV(TAG, "Partial update called"); ESP_LOGV(TAG, "Partial update called");
uint32_t start_time = millis(); uint32_t start_time = millis();
@ -432,16 +501,15 @@ bool Inkplate6::partial_update_() {
this->partial_updates_++; this->partial_updates_++;
uint16_t pos = this->get_buffer_length_() - 1; uint32_t pos = this->get_buffer_length_() - 1;
uint32_t send;
uint8_t data; uint8_t data;
uint8_t diffw, diffb; uint8_t diffw, diffb;
uint32_t n = (this->get_buffer_length_() * 2) - 1; uint32_t n = (this->get_buffer_length_() * 2) - 1;
for (int i = 0, im = this->get_height_internal(); i < im; i++) { 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++) { 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]); diffw = this->buffer_[pos] & ~(this->partial_buffer_[pos]);
diffb = (this->buffer_[pos] ^ this->partial_buffer_[pos]) & this->partial_buffer_[pos]; diffb = ~(this->buffer_[pos]) & this->partial_buffer_[pos];
pos--; pos--;
this->partial_buffer_2_[n--] = LUTW[diffw >> 4] & LUTB[diffb >> 4]; this->partial_buffer_2_[n--] = LUTW[diffw >> 4] & LUTB[diffb >> 4];
this->partial_buffer_2_[n--] = LUTW[diffw & 0x0F] & LUTB[diffb & 0x0F]; this->partial_buffer_2_[n--] = LUTW[diffw & 0x0F] & LUTB[diffb & 0x0F];
@ -451,23 +519,20 @@ bool Inkplate6::partial_update_() {
eink_on_(); eink_on_();
uint32_t clock = (1 << this->cl_pin_->get_pin()); 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++) { for (int k = 0; k < 5; k++) {
vscan_start_(); vscan_start_();
const uint8_t *data_ptr = &this->partial_buffer_2_[(this->get_buffer_length_() * 2) - 1]; 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++) { for (int i = 0; i < this->get_height_internal(); i++) {
data = *(data_ptr--); data = *(data_ptr--);
send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | hscan_start_(this->pin_lut_[data]);
(((data & 0b11100000) >> 5) << 25);
hscan_start_(send);
for (int j = 0, jm = (this->get_width_internal() / 4) - 1; j < jm; j++) { for (int j = 0, jm = (this->get_width_internal() / 4) - 1; j < jm; j++) {
data = *(data_ptr--); data = *(data_ptr--);
send = ((data & 0b00000011) << 4) | (((data & 0b00001100) >> 2) << 18) | (((data & 0b00010000) >> 4) << 23) | GPIO.out_w1ts = this->pin_lut_[data] | clock;
(((data & 0b11100000) >> 5) << 25) | clock; GPIO.out_w1tc = data_mask | clock;
GPIO.out_w1ts = send;
GPIO.out_w1tc = send;
} }
GPIO.out_w1ts = send; GPIO.out_w1ts = clock;
GPIO.out_w1tc = get_data_pin_mask_() | clock; GPIO.out_w1tc = data_mask | clock;
vscan_end_(); vscan_end_();
} }
delayMicroseconds(230); delayMicroseconds(230);
@ -482,6 +547,7 @@ bool Inkplate6::partial_update_() {
ESP_LOGV(TAG, "Partial update finished (%ums)", millis() - start_time); ESP_LOGV(TAG, "Partial update finished (%ums)", millis() - start_time);
return true; return true;
} }
void Inkplate6::vscan_start_() { void Inkplate6::vscan_start_() {
this->ckv_pin_->digital_write(true); this->ckv_pin_->digital_write(true);
delayMicroseconds(7); delayMicroseconds(7);
@ -505,30 +571,23 @@ void Inkplate6::vscan_start_() {
delayMicroseconds(0); delayMicroseconds(0);
this->ckv_pin_->digital_write(true); this->ckv_pin_->digital_write(true);
} }
void Inkplate6::vscan_write_() {
this->ckv_pin_->digital_write(false); void Inkplate6::hscan_start_(uint32_t d) {
this->le_pin_->digital_write(true); uint8_t clock = (1 << this->cl_pin_->get_pin());
this->le_pin_->digital_write(false);
delayMicroseconds(0);
this->sph_pin_->digital_write(false); this->sph_pin_->digital_write(false);
this->cl_pin_->digital_write(true); GPIO.out_w1ts = d | clock;
this->cl_pin_->digital_write(false); GPIO.out_w1tc = this->get_data_pin_mask_() | clock;
this->sph_pin_->digital_write(true); this->sph_pin_->digital_write(true);
this->ckv_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_() { void Inkplate6::vscan_end_() {
this->ckv_pin_->digital_write(false); this->ckv_pin_->digital_write(false);
this->le_pin_->digital_write(true); this->le_pin_->digital_write(true);
this->le_pin_->digital_write(false); this->le_pin_->digital_write(false);
delayMicroseconds(1); delayMicroseconds(0);
this->ckv_pin_->digital_write(true);
} }
void Inkplate6::clean() { void Inkplate6::clean() {
ESP_LOGV(TAG, "Clean called"); ESP_LOGV(TAG, "Clean called");
uint32_t start_time = millis(); uint32_t start_time = millis();
@ -542,6 +601,7 @@ void Inkplate6::clean() {
clean_fast_(1, 10); // White to White clean_fast_(1, 10); // White to White
ESP_LOGV(TAG, "Clean finished (%ums)", millis() - start_time); ESP_LOGV(TAG, "Clean finished (%ums)", millis() - start_time);
} }
void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) { void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) {
ESP_LOGV(TAG, "Clean fast called with: (%d, %d)", c, rep); ESP_LOGV(TAG, "Clean fast called with: (%d, %d)", c, rep);
uint32_t start_time = millis(); uint32_t start_time = millis();
@ -568,14 +628,14 @@ void Inkplate6::clean_fast_(uint8_t c, uint8_t rep) {
hscan_start_(send); hscan_start_(send);
GPIO.out_w1ts = send | clock; GPIO.out_w1ts = send | clock;
GPIO.out_w1tc = 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_w1ts = clock;
GPIO.out_w1tc = clock; GPIO.out_w1tc = clock;
GPIO.out_w1ts = clock; GPIO.out_w1ts = clock;
GPIO.out_w1tc = clock; GPIO.out_w1tc = clock;
} }
GPIO.out_w1ts = clock; GPIO.out_w1ts = send | clock;
GPIO.out_w1tc = get_data_pin_mask_() | clock; GPIO.out_w1tc = clock;
vscan_end_(); vscan_end_();
} }
delayMicroseconds(230); 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); ESP_LOGV(TAG, "Clean fast finished (%ums)", millis() - start_time);
} }
void Inkplate6::pins_z_state_() { 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->ckv_pin_->pin_mode(gpio::FLAG_INPUT);
this->sph_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_6_pin_->pin_mode(gpio::FLAG_INPUT);
this->display_data_7_pin_->pin_mode(gpio::FLAG_INPUT); this->display_data_7_pin_->pin_mode(gpio::FLAG_INPUT);
} }
void Inkplate6::pins_as_outputs_() { 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->ckv_pin_->pin_mode(gpio::FLAG_OUTPUT);
this->sph_pin_->pin_mode(gpio::FLAG_OUTPUT); this->sph_pin_->pin_mode(gpio::FLAG_OUTPUT);

View file

@ -13,32 +13,28 @@ namespace inkplate6 {
enum InkplateModel : uint8_t { enum InkplateModel : uint8_t {
INKPLATE_6 = 0, INKPLATE_6 = 0,
INKPLATE_10 = 1, INKPLATE_10 = 1,
INKPLATE_6_PLUS = 2,
}; };
class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public i2c::I2CDevice { class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public i2c::I2CDevice {
public: public:
const uint8_t LUT2[16] = {0b10101010, 0b10101001, 0b10100110, 0b10100101, 0b10011010, 0b10011001, const uint8_t LUT2[16] = {0xAA, 0xA9, 0xA6, 0xA5, 0x9A, 0x99, 0x96, 0x95,
0b10010110, 0b10010101, 0b01101010, 0b01101001, 0b01100110, 0b01100101, 0x6A, 0x69, 0x66, 0x65, 0x5A, 0x59, 0x56, 0x55};
0b01011010, 0b01011001, 0b01010110, 0b01010101}; const uint8_t LUTW[16] = {0xFF, 0xFE, 0xFB, 0xFA, 0xEF, 0xEE, 0xEB, 0xEA,
const uint8_t LUTW[16] = {0b11111111, 0b11111110, 0b11111011, 0b11111010, 0b11101111, 0b11101110, 0xBF, 0xBE, 0xBB, 0xBA, 0xAF, 0xAE, 0xAB, 0xAA};
0b11101011, 0b11101010, 0b10111111, 0b10111110, 0b10111011, 0b10111010, const uint8_t LUTB[16] = {0xFF, 0xFD, 0xF7, 0xF5, 0xDF, 0xDD, 0xD7, 0xD5,
0b10101111, 0b10101110, 0b10101011, 0b10101010}; 0x7F, 0x7D, 0x77, 0x75, 0x5F, 0x5D, 0x57, 0x55};
const uint8_t LUTB[16] = {0b11111111, 0b11111101, 0b11110111, 0b11110101, 0b11011111, 0b11011101,
0b11010111, 0b11010101, 0b01111111, 0b01111101, 0b01110111, 0b01110101, const uint8_t pixelMaskLUT[8] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
0b01011111, 0b01011101, 0b01010111, 0b01010101}; const uint8_t pixelMaskGLUT[2] = {0x0F, 0xF0};
const uint8_t pixelMaskLUT[8] = {0b00000001, 0b00000010, 0b00000100, 0b00001000,
0b00010000, 0b00100000, 0b01000000, 0b10000000}; 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},
const uint8_t pixelMaskGLUT[2] = {0b00001111, 0b11110000}; {0, 0, 0, 1, 1, 1, 2, 0}, {2, 1, 1, 1, 2, 1, 2, 0}, {2, 2, 1, 1, 2, 1, 2, 0},
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},
{1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}}; {1, 1, 1, 2, 1, 2, 2, 0}, {0, 0, 0, 0, 0, 0, 2, 0}};
const uint32_t waveform[50] = { const uint8_t waveform3Bit6Plus[8][9] = {{0, 0, 0, 0, 0, 2, 1, 1, 0}, {0, 0, 2, 1, 1, 1, 2, 1, 0},
0x00000008, 0x00000008, 0x00200408, 0x80281888, 0x60a81898, 0x60a8a8a8, 0x60a8a8a8, 0x6068a868, 0x6868a868, {0, 2, 2, 2, 1, 1, 2, 1, 0}, {0, 0, 2, 2, 2, 1, 2, 1, 0},
0x6868a868, 0x68686868, 0x6a686868, 0x5a686868, 0x5a686868, 0x5a586a68, 0x5a5a6a68, 0x5a5a6a68, 0x55566a68, {0, 0, 0, 0, 2, 2, 2, 1, 0}, {0, 0, 2, 1, 2, 1, 1, 2, 0},
0x55565a64, 0x55555654, 0x55555556, 0x55555556, 0x55555556, 0x55555516, 0x55555596, 0x15555595, 0x95955595, {0, 0, 2, 2, 2, 1, 1, 2, 0}, {0, 0, 0, 0, 2, 2, 2, 2, 0}};
0x95959595, 0x95949495, 0x94949495, 0x94949495, 0xa4949494, 0x9494a4a4, 0x84a49494, 0x84948484, 0x84848484,
0x84848484, 0x84848484, 0xa5a48484, 0xa9a4a4a8, 0xa9a8a8a8, 0xa5a9a9a4, 0xa5a5a5a4, 0xa1a5a5a1, 0xa9a9a9a9,
0xa9a9a9a9, 0xa9a9a9a9, 0xa9a9a9a9, 0x15151515, 0x11111111};
void set_greyscale(bool greyscale) { void set_greyscale(bool greyscale) {
this->greyscale_ = greyscale; this->greyscale_ = greyscale;
@ -88,6 +84,8 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
bool get_partial_updating() { return this->partial_updating_; } bool get_partial_updating() { return this->partial_updating_; }
uint8_t get_temperature() { return this->temperature_; } uint8_t get_temperature() { return this->temperature_; }
void block_partial() { this->block_partial_ = true; }
protected: protected:
void draw_absolute_pixel_internal(int x, int y, Color color) override; void draw_absolute_pixel_internal(int x, int y, Color color) override;
void display1b_(); void display1b_();
@ -99,10 +97,10 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
void hscan_start_(uint32_t d); void hscan_start_(uint32_t d);
void vscan_end_(); void vscan_end_();
void vscan_start_(); void vscan_start_();
void vscan_write_();
void eink_off_(); void eink_off_();
void eink_on_(); void eink_on_();
bool read_power_status_();
void setup_pins_(); void setup_pins_();
void pins_z_state_(); void pins_z_state_();
@ -113,6 +111,8 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
return 800; return 800;
} else if (this->model_ == INKPLATE_10) { } else if (this->model_ == INKPLATE_10) {
return 1200; return 1200;
} else if (this->model_ == INKPLATE_6_PLUS) {
return 1024;
} }
return 0; return 0;
} }
@ -122,6 +122,8 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
return 600; return 600;
} else if (this->model_ == INKPLATE_10) { } else if (this->model_ == INKPLATE_10) {
return 825; return 825;
} else if (this->model_ == INKPLATE_6_PLUS) {
return 758;
} }
return 0; return 0;
} }
@ -141,16 +143,20 @@ class Inkplate6 : public PollingComponent, public display::DisplayBuffer, public
return data; return data;
} }
uint8_t panel_on_ = 0; bool panel_on_{false};
uint8_t temperature_; uint8_t temperature_;
uint8_t *partial_buffer_{nullptr}; uint8_t *partial_buffer_{nullptr};
uint8_t *partial_buffer_2_{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 full_update_every_;
uint32_t partial_updates_{0}; uint32_t partial_updates_{0};
bool block_partial_; bool block_partial_{true};
bool greyscale_; bool greyscale_;
bool partial_updating_; bool partial_updating_;