mirror of
https://github.com/esphome/esphome.git
synced 2025-09-04 04:12:23 +01:00
4755 lines
142 KiB
C++
4755 lines
142 KiB
C++
#include "waveshare_epaper.h"
|
|
#include <bitset>
|
|
#include <cinttypes>
|
|
#include "esphome/core/application.h"
|
|
#include "esphome/core/helpers.h"
|
|
#include "esphome/core/log.h"
|
|
|
|
namespace esphome {
|
|
namespace waveshare_epaper {
|
|
|
|
static const char *const TAG = "waveshare_epaper";
|
|
|
|
static const uint8_t LUT_SIZE_WAVESHARE = 30;
|
|
|
|
static const uint8_t FULL_UPDATE_LUT[LUT_SIZE_WAVESHARE] = {0x02, 0x02, 0x01, 0x11, 0x12, 0x12, 0x22, 0x22, 0x66, 0x69,
|
|
0x69, 0x59, 0x58, 0x99, 0x99, 0x88, 0x00, 0x00, 0x00, 0x00,
|
|
0xF8, 0xB4, 0x13, 0x51, 0x35, 0x51, 0x51, 0x19, 0x01, 0x00};
|
|
|
|
static const uint8_t PARTIAL_UPDATE_LUT[LUT_SIZE_WAVESHARE] = {
|
|
0x10, 0x18, 0x18, 0x08, 0x18, 0x18, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x14, 0x44, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
static const uint8_t LUT_SIZE_TTGO = 70;
|
|
|
|
static const uint8_t FULL_UPDATE_LUT_TTGO[LUT_SIZE_TTGO] = {
|
|
0x80, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, // LUT0: BB: VS 0 ~7
|
|
0x10, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, // LUT1: BW: VS 0 ~7
|
|
0x80, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00, // LUT2: WB: VS 0 ~7
|
|
0x10, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, // LUT3: WW: VS 0 ~7
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT4: VCOM: VS 0 ~7
|
|
0x03, 0x03, 0x00, 0x00, 0x02, // TP0 A~D RP0
|
|
0x09, 0x09, 0x00, 0x00, 0x02, // TP1 A~D RP1
|
|
0x03, 0x03, 0x00, 0x00, 0x02, // TP2 A~D RP2
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP3 A~D RP3
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP4 A~D RP4
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP5 A~D RP5
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP6 A~D RP6
|
|
};
|
|
|
|
static const uint8_t PARTIAL_UPDATE_LUT_TTGO[LUT_SIZE_TTGO] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT0: BB: VS 0 ~7
|
|
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT1: BW: VS 0 ~7
|
|
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT2: WB: VS 0 ~7
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT3: WW: VS 0 ~7
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // LUT4: VCOM: VS 0 ~7
|
|
0x0A, 0x00, 0x00, 0x00, 0x00, // TP0 A~D RP0
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP1 A~D RP1
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP2 A~D RP2
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP3 A~D RP3
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP4 A~D RP4
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP5 A~D RP5
|
|
0x00, 0x00, 0x00, 0x00, 0x00, // TP6 A~D RP6
|
|
};
|
|
|
|
static const uint8_t LUT_SIZE_TTGO_B73 = 100;
|
|
|
|
static const uint8_t FULL_UPDATE_LUT_TTGO_B73[LUT_SIZE_TTGO_B73] = {
|
|
0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0xA0, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0xA0, 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x90, 0xA0, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x03, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t PARTIAL_UPDATE_LUT_TTGO_B73[LUT_SIZE_TTGO_B73] = {
|
|
0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
|
|
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_SIZE_TTGO_B1 = 29;
|
|
|
|
static const uint8_t FULL_UPDATE_LUT_TTGO_B1[LUT_SIZE_TTGO_B1] = {
|
|
0x22, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x01, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
static const uint8_t PARTIAL_UPDATE_LUT_TTGO_B1[LUT_SIZE_TTGO_B1] = {
|
|
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x0F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
// clang-format off
|
|
// Disable formatting to preserve the same look as in Waveshare examples
|
|
static const uint8_t PARTIAL_UPD_2IN9_LUT_SIZE = 159;
|
|
static const uint8_t PARTIAL_UPD_2IN9_LUT[PARTIAL_UPD_2IN9_LUT_SIZE] =
|
|
{
|
|
0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00,
|
|
0x22, 0x17, 0x41, 0xB0, 0x32, 0x36,
|
|
};
|
|
// clang-format on
|
|
|
|
void WaveshareEPaperBase::setup() {
|
|
this->init_internal_(this->get_buffer_length_());
|
|
this->setup_pins_();
|
|
this->spi_setup();
|
|
this->reset_();
|
|
this->initialize();
|
|
}
|
|
void WaveshareEPaperBase::setup_pins_() {
|
|
this->dc_pin_->setup(); // OUTPUT
|
|
this->dc_pin_->digital_write(false);
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->setup(); // OUTPUT
|
|
this->reset_pin_->digital_write(true);
|
|
}
|
|
if (this->busy_pin_ != nullptr) {
|
|
this->busy_pin_->setup(); // INPUT
|
|
}
|
|
}
|
|
float WaveshareEPaperBase::get_setup_priority() const { return setup_priority::PROCESSOR; }
|
|
void WaveshareEPaperBase::command(uint8_t value) {
|
|
this->start_command_();
|
|
this->write_byte(value);
|
|
this->end_command_();
|
|
}
|
|
void WaveshareEPaperBase::data(uint8_t value) {
|
|
this->start_data_();
|
|
this->write_byte(value);
|
|
this->end_data_();
|
|
}
|
|
|
|
// write a command followed by one or more bytes of data.
|
|
// The command is the first byte, length is the total including cmd.
|
|
void WaveshareEPaperBase::cmd_data(const uint8_t *c_data, size_t length) {
|
|
this->dc_pin_->digital_write(false);
|
|
this->enable();
|
|
this->write_byte(c_data[0]);
|
|
this->dc_pin_->digital_write(true);
|
|
this->write_array(c_data + 1, length - 1);
|
|
this->disable();
|
|
}
|
|
|
|
bool WaveshareEPaperBase::wait_until_idle_() {
|
|
if (this->busy_pin_ == nullptr || !this->busy_pin_->digital_read()) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t start = millis();
|
|
while (this->busy_pin_->digital_read()) {
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGE(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
delay(1);
|
|
}
|
|
return true;
|
|
}
|
|
void WaveshareEPaperBase::update() {
|
|
this->do_update_();
|
|
this->display();
|
|
}
|
|
void WaveshareEPaper::fill(Color color) {
|
|
// flip logic
|
|
const uint8_t fill = color.is_on() ? 0x00 : 0xFF;
|
|
for (uint32_t i = 0; i < this->get_buffer_length_(); i++)
|
|
this->buffer_[i] = fill;
|
|
}
|
|
void WaveshareEPaper7C::setup() {
|
|
this->init_internal_7c_(this->get_buffer_length_());
|
|
this->setup_pins_();
|
|
this->spi_setup();
|
|
this->reset_();
|
|
this->initialize();
|
|
}
|
|
void WaveshareEPaper7C::init_internal_7c_(uint32_t buffer_length) {
|
|
RAMAllocator<uint8_t> allocator;
|
|
uint32_t small_buffer_length = buffer_length / NUM_BUFFERS;
|
|
|
|
for (int i = 0; i < NUM_BUFFERS; i++) {
|
|
this->buffers_[i] = allocator.allocate(small_buffer_length);
|
|
if (this->buffers_[i] == nullptr) {
|
|
ESP_LOGE(TAG, "Could not allocate buffer %d for display!", i);
|
|
for (auto &buffer : this->buffers_) {
|
|
allocator.deallocate(buffer, small_buffer_length);
|
|
buffer = nullptr;
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
this->clear();
|
|
}
|
|
uint8_t WaveshareEPaper7C::color_to_hex(Color color) {
|
|
uint8_t hex_code;
|
|
if (color.red > 127) {
|
|
if (color.green > 170) {
|
|
if (color.blue > 127) {
|
|
hex_code = 0x1; // White
|
|
} else {
|
|
hex_code = 0x5; // Yellow
|
|
}
|
|
} else if (color.green > 85) {
|
|
hex_code = 0x6; // Orange
|
|
} else {
|
|
hex_code = 0x4; // Red (or Magenta)
|
|
}
|
|
} else {
|
|
if (color.green > 127) {
|
|
if (color.blue > 127) {
|
|
hex_code = 0x3; // Cyan -> Blue
|
|
} else {
|
|
hex_code = 0x2; // Green
|
|
}
|
|
} else {
|
|
if (color.blue > 127) {
|
|
hex_code = 0x3; // Blue
|
|
} else {
|
|
hex_code = 0x0; // Black
|
|
}
|
|
}
|
|
}
|
|
|
|
return hex_code;
|
|
}
|
|
void WaveshareEPaper7C::fill(Color color) {
|
|
uint8_t pixel_color;
|
|
if (color.is_on()) {
|
|
pixel_color = this->color_to_hex(color);
|
|
} else {
|
|
pixel_color = 0x1;
|
|
}
|
|
|
|
if (this->buffers_[0] == nullptr) {
|
|
ESP_LOGE(TAG, "Buffer unavailable!");
|
|
} else {
|
|
uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
|
|
for (auto &buffer : this->buffers_) {
|
|
for (uint32_t buffer_pos = 0; buffer_pos < small_buffer_length; buffer_pos += 3) {
|
|
// We store 8 bitset<3> in 3 bytes
|
|
// | byte 1 | byte 2 | byte 3 |
|
|
// |aaabbbaa|abbbaaab|bbaaabbb|
|
|
buffer[buffer_pos + 0] = pixel_color << 5 | pixel_color << 2 | pixel_color >> 1;
|
|
buffer[buffer_pos + 1] = pixel_color << 7 | pixel_color << 4 | pixel_color << 1 | pixel_color >> 2;
|
|
buffer[buffer_pos + 2] = pixel_color << 6 | pixel_color << 3 | pixel_color << 0;
|
|
}
|
|
App.feed_wdt();
|
|
}
|
|
}
|
|
}
|
|
void WaveshareEPaper7C::send_buffers_() {
|
|
if (this->buffers_[0] == nullptr) {
|
|
ESP_LOGE(TAG, "Buffer unavailable!");
|
|
return;
|
|
}
|
|
|
|
uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
|
|
uint8_t byte_to_send;
|
|
for (auto &buffer : this->buffers_) {
|
|
for (uint32_t buffer_pos = 0; buffer_pos < small_buffer_length; buffer_pos += 3) {
|
|
std::bitset<24> triplet =
|
|
buffer[buffer_pos + 0] << 16 | buffer[buffer_pos + 1] << 8 | buffer[buffer_pos + 2] << 0;
|
|
// 8 bitset<3> are stored in 3 bytes
|
|
// |aaabbbaa|abbbaaab|bbaaabbb|
|
|
// | byte 1 | byte 2 | byte 3 |
|
|
byte_to_send = ((triplet >> 17).to_ulong() & 0b01110000) | ((triplet >> 18).to_ulong() & 0b00000111);
|
|
this->data(byte_to_send);
|
|
|
|
byte_to_send = ((triplet >> 11).to_ulong() & 0b01110000) | ((triplet >> 12).to_ulong() & 0b00000111);
|
|
this->data(byte_to_send);
|
|
|
|
byte_to_send = ((triplet >> 5).to_ulong() & 0b01110000) | ((triplet >> 6).to_ulong() & 0b00000111);
|
|
this->data(byte_to_send);
|
|
|
|
byte_to_send = ((triplet << 1).to_ulong() & 0b01110000) | ((triplet << 0).to_ulong() & 0b00000111);
|
|
this->data(byte_to_send);
|
|
}
|
|
App.feed_wdt();
|
|
}
|
|
}
|
|
void WaveshareEPaper7C::reset_() {
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->digital_write(true);
|
|
delay(20);
|
|
this->reset_pin_->digital_write(false);
|
|
delay(1);
|
|
this->reset_pin_->digital_write(true);
|
|
delay(20);
|
|
}
|
|
}
|
|
|
|
void HOT WaveshareEPaper::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;
|
|
|
|
const uint32_t pos = (x + y * this->get_width_controller()) / 8u;
|
|
const uint8_t subpos = x & 0x07;
|
|
// flip logic
|
|
if (!color.is_on()) {
|
|
this->buffer_[pos] |= 0x80 >> subpos;
|
|
} else {
|
|
this->buffer_[pos] &= ~(0x80 >> subpos);
|
|
}
|
|
}
|
|
|
|
uint32_t WaveshareEPaper::get_buffer_length_() {
|
|
return this->get_width_controller() * this->get_height_internal() / 8u;
|
|
} // just a black buffer
|
|
uint32_t WaveshareEPaperBWR::get_buffer_length_() {
|
|
return this->get_width_controller() * this->get_height_internal() / 4u;
|
|
} // black and red buffer
|
|
uint32_t WaveshareEPaper7C::get_buffer_length_() {
|
|
return this->get_width_controller() * this->get_height_internal() / 8u * 3u;
|
|
} // 7 colors buffer, 1 pixel = 3 bits, we will store 8 pixels in 24 bits = 3 bytes
|
|
|
|
void WaveshareEPaperBWR::fill(Color color) {
|
|
this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color);
|
|
}
|
|
void HOT WaveshareEPaperBWR::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;
|
|
|
|
const uint32_t buf_half_len = this->get_buffer_length_() / 2u;
|
|
|
|
const uint32_t pos = (x + y * this->get_width_internal()) / 8u;
|
|
const uint8_t subpos = x & 0x07;
|
|
// flip logic
|
|
if (color.is_on()) {
|
|
this->buffer_[pos] |= 0x80 >> subpos;
|
|
} else {
|
|
this->buffer_[pos] &= ~(0x80 >> subpos);
|
|
}
|
|
|
|
// draw red pixels only, if the color contains red only
|
|
if (((color.red > 0) && (color.green == 0) && (color.blue == 0))) {
|
|
this->buffer_[pos + buf_half_len] |= 0x80 >> subpos;
|
|
} else {
|
|
this->buffer_[pos + buf_half_len] &= ~(0x80 >> subpos);
|
|
}
|
|
}
|
|
void HOT WaveshareEPaper7C::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;
|
|
|
|
uint8_t pixel_bits = this->color_to_hex(color);
|
|
uint32_t small_buffer_length = this->get_buffer_length_() / NUM_BUFFERS;
|
|
uint32_t pixel_position = x + y * this->get_width_controller();
|
|
uint32_t first_bit_position = pixel_position * 3;
|
|
uint32_t byte_position = first_bit_position / 8u;
|
|
uint32_t byte_subposition = first_bit_position % 8u;
|
|
uint32_t buffer_position = byte_position / small_buffer_length;
|
|
uint32_t buffer_subposition = byte_position % small_buffer_length;
|
|
|
|
if (byte_subposition <= 5) {
|
|
this->buffers_[buffer_position][buffer_subposition] =
|
|
(this->buffers_[buffer_position][buffer_subposition] & (0xFF ^ (0b111 << (5 - byte_subposition)))) |
|
|
(pixel_bits << (5 - byte_subposition));
|
|
} else {
|
|
this->buffers_[buffer_position][buffer_subposition + 0] =
|
|
(this->buffers_[buffer_position][buffer_subposition + 0] & (0xFF ^ (0b111 >> (byte_subposition - 5)))) |
|
|
(pixel_bits >> (byte_subposition - 5));
|
|
|
|
this->buffers_[buffer_position][buffer_subposition + 1] = (this->buffers_[buffer_position][buffer_subposition + 1] &
|
|
(0xFF ^ (0xFF & (0b111 << (13 - byte_subposition))))) |
|
|
(pixel_bits << (13 - byte_subposition));
|
|
}
|
|
}
|
|
void WaveshareEPaperBase::start_command_() {
|
|
this->dc_pin_->digital_write(false);
|
|
this->enable();
|
|
}
|
|
void WaveshareEPaperBase::end_command_() { this->disable(); }
|
|
void WaveshareEPaperBase::start_data_() {
|
|
this->dc_pin_->digital_write(true);
|
|
this->enable();
|
|
}
|
|
void WaveshareEPaperBase::end_data_() { this->disable(); }
|
|
void WaveshareEPaperBase::on_safe_shutdown() { this->deep_sleep(); }
|
|
|
|
// ========================================================
|
|
// Type A
|
|
// ========================================================
|
|
|
|
void WaveshareEPaperTypeA::initialize() {
|
|
// Achieve display intialization
|
|
this->init_display_();
|
|
// If a reset pin is configured, eligible displays can be set to deep sleep
|
|
// between updates, as recommended by the hardware provider
|
|
if (this->reset_pin_ != nullptr) {
|
|
switch (this->model_) {
|
|
// More models can be added here to enable deep sleep if eligible
|
|
case WAVESHARE_EPAPER_1_54_IN:
|
|
case WAVESHARE_EPAPER_1_54_IN_V2:
|
|
this->deep_sleep_between_updates_ = true;
|
|
ESP_LOGI(TAG, "Set the display to deep sleep");
|
|
this->deep_sleep();
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
void WaveshareEPaperTypeA::init_display_() {
|
|
if (this->model_ == TTGO_EPAPER_2_13_IN_B74 || this->model_ == WAVESHARE_EPAPER_2_13_IN_V2) {
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->digital_write(false);
|
|
delay(10);
|
|
this->reset_pin_->digital_write(true);
|
|
delay(10);
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
this->command(0x12); // SWRESET
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
// COMMAND DRIVER OUTPUT CONTROL
|
|
this->command(0x01);
|
|
this->data(this->get_height_internal() - 1);
|
|
this->data((this->get_height_internal() - 1) >> 8);
|
|
this->data(0x00); // ? GD = 0, SM = 0, TB = 0
|
|
|
|
// COMMAND BOOSTER SOFT START CONTROL
|
|
this->command(0x0C);
|
|
this->data(0xD7);
|
|
this->data(0xD6);
|
|
this->data(0x9D);
|
|
|
|
// COMMAND WRITE VCOM REGISTER
|
|
this->command(0x2C);
|
|
this->data(0xA8);
|
|
|
|
// COMMAND SET DUMMY LINE PERIOD
|
|
this->command(0x3A);
|
|
this->data(0x1A);
|
|
|
|
// COMMAND SET GATE TIME
|
|
this->command(0x3B);
|
|
this->data(0x08); // 2µs per row
|
|
|
|
// COMMAND DATA ENTRY MODE SETTING
|
|
this->command(0x11);
|
|
switch (this->model_) {
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
this->data(0x01); // x increase, y decrease : as in demo code
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
case WAVESHARE_EPAPER_2_9_IN_V2:
|
|
this->data(0x03); // from top left to bottom right
|
|
// RAM content option for Display Update
|
|
this->command(0x21);
|
|
this->data(0x00);
|
|
this->data(0x80);
|
|
break;
|
|
default:
|
|
this->data(0x03); // from top left to bottom right
|
|
}
|
|
}
|
|
void WaveshareEPaperTypeA::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
switch (this->model_) {
|
|
case WAVESHARE_EPAPER_1_54_IN:
|
|
ESP_LOGCONFIG(TAG, " Model: 1.54in");
|
|
break;
|
|
case WAVESHARE_EPAPER_1_54_IN_V2:
|
|
ESP_LOGCONFIG(TAG, " Model: 1.54inV2");
|
|
break;
|
|
case WAVESHARE_EPAPER_2_13_IN:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.13in");
|
|
break;
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.13inV2");
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO)");
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B73:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO B73)");
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO B74)");
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.13in (TTGO B1)");
|
|
break;
|
|
case WAVESHARE_EPAPER_2_9_IN:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9in");
|
|
break;
|
|
case WAVESHARE_EPAPER_2_9_IN_V2:
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9inV2");
|
|
break;
|
|
}
|
|
ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
void HOT WaveshareEPaperTypeA::display() {
|
|
bool full_update = this->at_update_ == 0;
|
|
bool prev_full_update = this->at_update_ == 1;
|
|
|
|
if (this->deep_sleep_between_updates_) {
|
|
ESP_LOGI(TAG, "Wake up the display");
|
|
this->reset_();
|
|
this->wait_until_idle_();
|
|
this->init_display_();
|
|
}
|
|
|
|
if (!this->wait_until_idle_()) {
|
|
this->status_set_warning();
|
|
return;
|
|
}
|
|
|
|
if (this->full_update_every_ >= 1) {
|
|
if (full_update != prev_full_update) {
|
|
switch (this->model_) {
|
|
case TTGO_EPAPER_2_13_IN:
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
// Waveshare 2.13" V2 uses the same LUTs as TTGO
|
|
this->write_lut_(full_update ? FULL_UPDATE_LUT_TTGO : PARTIAL_UPDATE_LUT_TTGO, LUT_SIZE_TTGO);
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B73:
|
|
this->write_lut_(full_update ? FULL_UPDATE_LUT_TTGO_B73 : PARTIAL_UPDATE_LUT_TTGO_B73, LUT_SIZE_TTGO_B73);
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
// there is no LUT
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
this->write_lut_(full_update ? FULL_UPDATE_LUT_TTGO_B1 : PARTIAL_UPDATE_LUT_TTGO_B1, LUT_SIZE_TTGO_B1);
|
|
break;
|
|
default:
|
|
this->write_lut_(full_update ? FULL_UPDATE_LUT : PARTIAL_UPDATE_LUT, LUT_SIZE_WAVESHARE);
|
|
}
|
|
}
|
|
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
|
}
|
|
|
|
if (this->model_ == WAVESHARE_EPAPER_2_13_IN_V2) {
|
|
// Set VCOM for full or partial update
|
|
this->command(0x2C);
|
|
this->data(full_update ? 0x55 : 0x26);
|
|
|
|
if (!full_update) {
|
|
// Enable "ping-pong"
|
|
this->command(0x37);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x40);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->command(0x22);
|
|
this->data(0xc0);
|
|
this->command(0x20);
|
|
}
|
|
}
|
|
|
|
// Border waveform
|
|
switch (this->model_) {
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
this->command(0x3C);
|
|
this->data(full_update ? 0x05 : 0x80);
|
|
break;
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
this->command(0x3C);
|
|
this->data(full_update ? 0x03 : 0x01);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Set x & y regions we want to write to (full)
|
|
switch (this->model_) {
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
// COMMAND SET RAM X ADDRESS START END POSITION
|
|
this->command(0x44);
|
|
this->data(0x00);
|
|
this->data((this->get_width_controller() - 1) >> 3);
|
|
// COMMAND SET RAM Y ADDRESS START END POSITION
|
|
this->command(0x45);
|
|
this->data(this->get_height_internal() - 1);
|
|
this->data((this->get_height_internal() - 1) >> 8);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
// COMMAND SET RAM X ADDRESS COUNTER
|
|
this->command(0x4E);
|
|
this->data(0x00);
|
|
// COMMAND SET RAM Y ADDRESS COUNTER
|
|
this->command(0x4F);
|
|
this->data(this->get_height_internal() - 1);
|
|
this->data((this->get_height_internal() - 1) >> 8);
|
|
|
|
break;
|
|
default:
|
|
// COMMAND SET RAM X ADDRESS START END POSITION
|
|
this->command(0x44);
|
|
this->data(0x00);
|
|
this->data((this->get_width_internal() - 1) >> 3);
|
|
// COMMAND SET RAM Y ADDRESS START END POSITION
|
|
this->command(0x45);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(this->get_height_internal() - 1);
|
|
this->data((this->get_height_internal() - 1) >> 8);
|
|
|
|
// COMMAND SET RAM X ADDRESS COUNTER
|
|
this->command(0x4E);
|
|
this->data(0x00);
|
|
// COMMAND SET RAM Y ADDRESS COUNTER
|
|
this->command(0x4F);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
}
|
|
|
|
if (!this->wait_until_idle_()) {
|
|
this->status_set_warning();
|
|
return;
|
|
}
|
|
|
|
// COMMAND WRITE RAM
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
switch (this->model_) {
|
|
case TTGO_EPAPER_2_13_IN_B1: { // block needed because of variable initializations
|
|
int16_t wb = ((this->get_width_controller()) >> 3);
|
|
for (int i = 0; i < this->get_height_internal(); i++) {
|
|
for (int j = 0; j < wb; j++) {
|
|
int idx = j + (this->get_height_internal() - 1 - i) * wb;
|
|
this->write_byte(this->buffer_[idx]);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
}
|
|
this->end_data_();
|
|
|
|
if (this->model_ == WAVESHARE_EPAPER_2_13_IN_V2 && full_update) {
|
|
// Write base image again on full refresh
|
|
this->command(0x26);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
}
|
|
|
|
// COMMAND DISPLAY UPDATE CONTROL 2
|
|
this->command(0x22);
|
|
switch (this->model_) {
|
|
case WAVESHARE_EPAPER_2_9_IN_V2:
|
|
case WAVESHARE_EPAPER_1_54_IN_V2:
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
this->data(full_update ? 0xF7 : 0xFF);
|
|
break;
|
|
case TTGO_EPAPER_2_13_IN_B73:
|
|
this->data(0xC7);
|
|
break;
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
this->data(full_update ? 0xC7 : 0x0C);
|
|
break;
|
|
default:
|
|
this->data(0xC4);
|
|
break;
|
|
}
|
|
|
|
// COMMAND MASTER ACTIVATION
|
|
this->command(0x20);
|
|
// COMMAND TERMINATE FRAME READ WRITE
|
|
this->command(0xFF);
|
|
|
|
this->status_clear_warning();
|
|
|
|
if (this->deep_sleep_between_updates_) {
|
|
ESP_LOGI(TAG, "Set the display back to deep sleep");
|
|
this->deep_sleep();
|
|
}
|
|
}
|
|
int WaveshareEPaperTypeA::get_width_internal() {
|
|
switch (this->model_) {
|
|
case WAVESHARE_EPAPER_1_54_IN:
|
|
case WAVESHARE_EPAPER_1_54_IN_V2:
|
|
return 200;
|
|
case WAVESHARE_EPAPER_2_13_IN:
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
case TTGO_EPAPER_2_13_IN:
|
|
case TTGO_EPAPER_2_13_IN_B73:
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
return 122;
|
|
case WAVESHARE_EPAPER_2_9_IN:
|
|
case WAVESHARE_EPAPER_2_9_IN_V2:
|
|
return 128;
|
|
}
|
|
return 0;
|
|
}
|
|
// The controller of the 2.13" displays has a buffer larger than screen size
|
|
int WaveshareEPaperTypeA::get_width_controller() {
|
|
switch (this->model_) {
|
|
case WAVESHARE_EPAPER_2_13_IN:
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
case TTGO_EPAPER_2_13_IN:
|
|
case TTGO_EPAPER_2_13_IN_B73:
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
return 128;
|
|
default:
|
|
return this->get_width_internal();
|
|
}
|
|
}
|
|
int WaveshareEPaperTypeA::get_height_internal() {
|
|
switch (this->model_) {
|
|
case WAVESHARE_EPAPER_1_54_IN:
|
|
case WAVESHARE_EPAPER_1_54_IN_V2:
|
|
return 200;
|
|
case WAVESHARE_EPAPER_2_13_IN:
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
case TTGO_EPAPER_2_13_IN:
|
|
case TTGO_EPAPER_2_13_IN_B73:
|
|
case TTGO_EPAPER_2_13_IN_B74:
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
return 250;
|
|
case WAVESHARE_EPAPER_2_9_IN:
|
|
case WAVESHARE_EPAPER_2_9_IN_V2:
|
|
return 296;
|
|
}
|
|
return 0;
|
|
}
|
|
void WaveshareEPaperTypeA::write_lut_(const uint8_t *lut, const uint8_t size) {
|
|
// COMMAND WRITE LUT REGISTER
|
|
this->command(0x32);
|
|
for (uint8_t i = 0; i < size; i++)
|
|
this->data(lut[i]);
|
|
}
|
|
WaveshareEPaperTypeA::WaveshareEPaperTypeA(WaveshareEPaperTypeAModel model) : model_(model) {}
|
|
void WaveshareEPaperTypeA::set_full_update_every(uint32_t full_update_every) {
|
|
this->full_update_every_ = full_update_every;
|
|
}
|
|
|
|
uint32_t WaveshareEPaperTypeA::idle_timeout_() {
|
|
switch (this->model_) {
|
|
case WAVESHARE_EPAPER_1_54_IN:
|
|
case WAVESHARE_EPAPER_1_54_IN_V2:
|
|
case WAVESHARE_EPAPER_2_13_IN_V2:
|
|
case TTGO_EPAPER_2_13_IN_B1:
|
|
return 2500;
|
|
default:
|
|
return WaveshareEPaperBase::idle_timeout_();
|
|
}
|
|
}
|
|
|
|
// ========================================================
|
|
// Type B
|
|
// ========================================================
|
|
// Datasheet:
|
|
// - https://www.waveshare.com/w/upload/7/7f/4.2inch-e-paper-b-specification.pdf
|
|
// - https://github.com/soonuse/epd-library-arduino/blob/master/4.2inch_e-paper/epd4in2/
|
|
|
|
static const uint8_t LUT_VCOM_DC_2_7[44] = {
|
|
0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x00, 0x32, 0x32, 0x00, 0x00, 0x02, 0x00,
|
|
0x0F, 0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_WHITE_TO_WHITE_2_7[42] = {
|
|
0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0xA0, 0x0F,
|
|
0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_BLACK_TO_WHITE_2_7[42] = {
|
|
0x50, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0xA0, 0x0F,
|
|
0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_WHITE_TO_BLACK_2_7[] = {
|
|
0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0x50, 0x0F,
|
|
0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_BLACK_TO_BLACK_2_7[42] = {
|
|
0xA0, 0x0F, 0x0F, 0x00, 0x00, 0x05, 0x60, 0x32, 0x32, 0x00, 0x00, 0x02, 0x50, 0x0F,
|
|
0x0F, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
void WaveshareEPaper2P7In::initialize() {
|
|
// command power setting
|
|
this->command(0x01);
|
|
this->data(0x03); // VDS_EN, VDG_EN
|
|
this->data(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
|
|
this->data(0x2B); // VDH
|
|
this->data(0x2B); // VDL
|
|
this->data(0x09); // VDHR
|
|
|
|
// command booster soft start
|
|
this->command(0x06);
|
|
this->data(0x07);
|
|
this->data(0x07);
|
|
this->data(0x17);
|
|
|
|
// Power optimization - ???
|
|
this->command(0xF8);
|
|
this->data(0x60);
|
|
this->data(0xA5);
|
|
this->command(0xF8);
|
|
this->data(0x89);
|
|
this->data(0xA5);
|
|
this->command(0xF8);
|
|
this->data(0x90);
|
|
this->data(0x00);
|
|
this->command(0xF8);
|
|
this->data(0x93);
|
|
this->data(0x2A);
|
|
this->command(0xF8);
|
|
this->data(0xA0);
|
|
this->data(0xA5);
|
|
this->command(0xF8);
|
|
this->data(0xA1);
|
|
this->data(0x00);
|
|
this->command(0xF8);
|
|
this->data(0x73);
|
|
this->data(0x41);
|
|
|
|
// command partial display refresh
|
|
this->command(0x16);
|
|
this->data(0x00);
|
|
|
|
// command power on
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
delay(10);
|
|
|
|
// Command panel setting
|
|
this->command(0x00);
|
|
this->data(0xAF); // KW-BF KWR-AF BWROTP 0f
|
|
// command pll control
|
|
this->command(0x30);
|
|
this->data(0x3A); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
|
|
// COMMAND VCM DC SETTING
|
|
this->command(0x82);
|
|
this->data(0x12);
|
|
|
|
delay(2);
|
|
// COMMAND LUT FOR VCOM
|
|
this->command(0x20);
|
|
for (uint8_t i : LUT_VCOM_DC_2_7)
|
|
this->data(i);
|
|
|
|
// COMMAND LUT WHITE TO WHITE
|
|
this->command(0x21);
|
|
for (uint8_t i : LUT_WHITE_TO_WHITE_2_7)
|
|
this->data(i);
|
|
// COMMAND LUT BLACK TO WHITE
|
|
this->command(0x22);
|
|
for (uint8_t i : LUT_BLACK_TO_WHITE_2_7)
|
|
this->data(i);
|
|
// COMMAND LUT WHITE TO BLACK
|
|
this->command(0x23);
|
|
for (uint8_t i : LUT_WHITE_TO_BLACK_2_7)
|
|
this->data(i);
|
|
// COMMAND LUT BLACK TO BLACK
|
|
this->command(0x24);
|
|
for (uint8_t i : LUT_BLACK_TO_BLACK_2_7)
|
|
this->data(i);
|
|
}
|
|
void HOT WaveshareEPaper2P7In::display() {
|
|
uint32_t buf_len = this->get_buffer_length_();
|
|
|
|
// COMMAND DATA START TRANSMISSION 1
|
|
this->command(0x10);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2
|
|
this->command(0x13);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
}
|
|
int WaveshareEPaper2P7In::get_width_internal() { return 176; }
|
|
int WaveshareEPaper2P7In::get_height_internal() { return 264; }
|
|
void WaveshareEPaper2P7In::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.7in");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper2P7InV2::initialize() {
|
|
this->reset_();
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x12); // SWRESET
|
|
this->wait_until_idle_();
|
|
|
|
// SET WINDOWS
|
|
// XRAM_START_AND_END_POSITION
|
|
this->command(0x44);
|
|
this->data(0x00);
|
|
this->data(((this->get_width_controller() - 1) >> 3) & 0xFF);
|
|
// YRAM_START_AND_END_POSITION
|
|
this->command(0x45);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data((get_height_internal() - 1) & 0xFF);
|
|
this->data(((get_height_internal() - 1) >> 8) & 0xFF);
|
|
|
|
// SET CURSOR
|
|
// XRAM_ADDRESS
|
|
this->command(0x4E);
|
|
this->data(0x00);
|
|
// YRAM_ADDRESS
|
|
this->command(0x4F);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
this->command(0x11); // data entry mode
|
|
this->data(0x03);
|
|
}
|
|
void HOT WaveshareEPaper2P7InV2::display() {
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x22);
|
|
this->data(0xF7);
|
|
this->command(0x20);
|
|
}
|
|
int WaveshareEPaper2P7InV2::get_width_internal() { return 176; }
|
|
int WaveshareEPaper2P7InV2::get_height_internal() { return 264; }
|
|
void WaveshareEPaper2P7InV2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.7in V2");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 1.54inch_v2_e-paper_b
|
|
// ========================================================
|
|
// Datasheet:
|
|
// - https://files.waveshare.com/upload/9/9e/1.54inch-e-paper-b-v2-specification.pdf
|
|
// - https://www.waveshare.com/wiki/1.54inch_e-Paper_Module_(B)_Manual
|
|
|
|
void WaveshareEPaper1P54InBV2::initialize() {
|
|
this->reset_();
|
|
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x12);
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x01);
|
|
this->data(0xC7);
|
|
this->data(0x00);
|
|
this->data(0x01);
|
|
|
|
this->command(0x11); // data entry mode
|
|
this->data(0x01);
|
|
|
|
this->command(0x44); // set Ram-X address start/end position
|
|
this->data(0x00);
|
|
this->data(0x18); // 0x18-->(24+1)*8=200
|
|
|
|
this->command(0x45); // set Ram-Y address start/end position
|
|
this->data(0xC7); // 0xC7-->(199+1)=200
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
this->command(0x3C); // BorderWavefrom
|
|
this->data(0x05);
|
|
|
|
this->command(0x18); // Read built-in temperature sensor
|
|
this->data(0x80);
|
|
|
|
this->command(0x4E); // set RAM x address count to 0;
|
|
this->data(0x00);
|
|
this->command(0x4F); // set RAM y address count to 0x199;
|
|
this->data(0xC7);
|
|
this->data(0x00);
|
|
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
void HOT WaveshareEPaper1P54InBV2::display() {
|
|
uint32_t buf_len_half = this->get_buffer_length_() >> 1;
|
|
this->initialize();
|
|
|
|
// COMMAND DATA START TRANSMISSION 1 (BLACK)
|
|
this->command(0x24);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len_half; i++) {
|
|
this->data(~this->buffer_[i]);
|
|
}
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (RED)
|
|
this->command(0x26);
|
|
delay(2);
|
|
for (uint32_t i = buf_len_half; i < buf_len_half * 2u; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
this->command(0x22);
|
|
this->data(0xf7);
|
|
this->command(0x20);
|
|
this->wait_until_idle_();
|
|
|
|
this->deep_sleep();
|
|
}
|
|
int WaveshareEPaper1P54InBV2::get_height_internal() { return 200; }
|
|
int WaveshareEPaper1P54InBV2::get_width_internal() { return 200; }
|
|
void WaveshareEPaper1P54InBV2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 1.54in V2 B");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 2.7inch_e-paper_b
|
|
// ========================================================
|
|
// Datasheet:
|
|
// - https://www.waveshare.com/w/upload/d/d8/2.7inch-e-paper-b-specification.pdf
|
|
// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_2in7b.c
|
|
|
|
static const uint8_t LUT_VCOM_DC_2_7B[44] = {0x00, 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x0A,
|
|
0x00, 0x00, 0x08, 0x00, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x00, 0x0A,
|
|
0x0A, 0x00, 0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00,
|
|
0x03, 0x0E, 0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
|
|
|
|
static const uint8_t LUT_WHITE_TO_WHITE_2_7B[42] = {0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x40, 0x0A, 0x0A, 0x00, 0x00,
|
|
0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x80, 0x0A, 0x0A, 0x00,
|
|
0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00, 0x03, 0x0E,
|
|
0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
|
|
|
|
static const uint8_t LUT_BLACK_TO_WHITE_2_7B[42] = {0xA0, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x0A, 0x00, 0x00,
|
|
0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x90, 0x0A, 0x0A, 0x00,
|
|
0x00, 0x08, 0xB0, 0x04, 0x10, 0x00, 0x00, 0x05, 0xB0, 0x03, 0x0E,
|
|
0x00, 0x00, 0x0A, 0xC0, 0x23, 0x00, 0x00, 0x00, 0x01};
|
|
|
|
static const uint8_t LUT_WHITE_TO_BLACK_2_7B[] = {0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x20, 0x0A, 0x0A, 0x00, 0x00,
|
|
0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x10, 0x0A, 0x0A, 0x00,
|
|
0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00, 0x03, 0x0E,
|
|
0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
|
|
|
|
static const uint8_t LUT_BLACK_TO_BLACK_2_7B[42] = {0x90, 0x1A, 0x1A, 0x00, 0x00, 0x01, 0x40, 0x0A, 0x0A, 0x00, 0x00,
|
|
0x08, 0x84, 0x0E, 0x01, 0x0E, 0x01, 0x10, 0x80, 0x0A, 0x0A, 0x00,
|
|
0x00, 0x08, 0x00, 0x04, 0x10, 0x00, 0x00, 0x05, 0x00, 0x03, 0x0E,
|
|
0x00, 0x00, 0x0A, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01};
|
|
|
|
void WaveshareEPaper2P7InB::initialize() {
|
|
this->reset_();
|
|
|
|
// command power on
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
delay(10);
|
|
|
|
// Command panel setting
|
|
this->command(0x00);
|
|
this->data(0xAF); // KW-BF KWR-AF BWROTP 0f
|
|
// command pll control
|
|
this->command(0x30);
|
|
this->data(0x3A); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
|
|
|
|
// command power setting
|
|
this->command(0x01);
|
|
this->data(0x03); // VDS_EN, VDG_EN
|
|
this->data(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
|
|
this->data(0x2B); // VDH
|
|
this->data(0x2B); // VDL
|
|
this->data(0x09); // VDHR
|
|
|
|
// command booster soft start
|
|
this->command(0x06);
|
|
this->data(0x07);
|
|
this->data(0x07);
|
|
this->data(0x17);
|
|
|
|
// Power optimization - ???
|
|
this->command(0xF8);
|
|
this->data(0x60);
|
|
this->data(0xA5);
|
|
this->command(0xF8);
|
|
this->data(0x89);
|
|
this->data(0xA5);
|
|
this->command(0xF8);
|
|
this->data(0x90);
|
|
this->data(0x00);
|
|
this->command(0xF8);
|
|
this->data(0x93);
|
|
this->data(0x2A);
|
|
this->command(0xF8);
|
|
this->data(0x73);
|
|
this->data(0x41);
|
|
|
|
// COMMAND VCM DC SETTING
|
|
this->command(0x82);
|
|
this->data(0x12);
|
|
|
|
// VCOM_AND_DATA_INTERVAL_SETTING
|
|
this->command(0x50);
|
|
this->data(0x87); // define by OTP
|
|
|
|
delay(2);
|
|
// COMMAND LUT FOR VCOM
|
|
this->command(0x20);
|
|
for (uint8_t i : LUT_VCOM_DC_2_7B)
|
|
this->data(i);
|
|
// COMMAND LUT WHITE TO WHITE
|
|
this->command(0x21);
|
|
for (uint8_t i : LUT_WHITE_TO_WHITE_2_7B)
|
|
this->data(i);
|
|
// COMMAND LUT BLACK TO WHITE
|
|
this->command(0x22);
|
|
for (uint8_t i : LUT_BLACK_TO_WHITE_2_7B)
|
|
this->data(i);
|
|
// COMMAND LUT WHITE TO BLACK
|
|
this->command(0x23);
|
|
for (uint8_t i : LUT_WHITE_TO_BLACK_2_7B) {
|
|
this->data(i);
|
|
}
|
|
// COMMAND LUT BLACK TO BLACK
|
|
this->command(0x24);
|
|
|
|
for (uint8_t i : LUT_BLACK_TO_BLACK_2_7B) {
|
|
this->data(i);
|
|
}
|
|
|
|
delay(2);
|
|
}
|
|
|
|
void HOT WaveshareEPaper2P7InB::display() {
|
|
uint32_t buf_len_half = this->get_buffer_length_() >> 1;
|
|
this->initialize();
|
|
|
|
// TCON_RESOLUTION
|
|
this->command(0x61);
|
|
this->data(this->get_width_controller() >> 8);
|
|
this->data(this->get_width_controller() & 0xff); // 176
|
|
this->data(this->get_height_internal() >> 8);
|
|
this->data(this->get_height_internal() & 0xff); // 264
|
|
|
|
// COMMAND DATA START TRANSMISSION 1 (BLACK)
|
|
this->command(0x10);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len_half; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
this->command(0x11);
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (RED)
|
|
this->command(0x13);
|
|
delay(2);
|
|
for (uint32_t i = buf_len_half; i < buf_len_half * 2u; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
this->command(0x11);
|
|
|
|
delay(2);
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
this->wait_until_idle_();
|
|
|
|
this->deep_sleep();
|
|
}
|
|
int WaveshareEPaper2P7InB::get_width_internal() { return 176; }
|
|
int WaveshareEPaper2P7InB::get_height_internal() { return 264; }
|
|
void WaveshareEPaper2P7InB::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.7in B");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 2.7inch_e-paper_b_v2
|
|
// ========================================================
|
|
// Datasheet:
|
|
// - https://www.waveshare.com/w/upload/7/7b/2.7inch-e-paper-b-v2-specification.pdf
|
|
// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_2in7b_V2.c
|
|
|
|
void WaveshareEPaper2P7InBV2::initialize() {
|
|
this->reset_();
|
|
|
|
this->wait_until_idle_();
|
|
this->command(0x12);
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x00);
|
|
this->data(0x27);
|
|
this->data(0x01);
|
|
this->data(0x00);
|
|
|
|
this->command(0x11);
|
|
this->data(0x03);
|
|
|
|
// self.SetWindows(0, 0, self.width-1, self.height-1)
|
|
// SetWindows(self, Xstart, Ystart, Xend, Yend):
|
|
|
|
uint32_t xend = this->get_width_controller() - 1;
|
|
uint32_t yend = this->get_height_internal() - 1;
|
|
this->command(0x44);
|
|
this->data(0x00);
|
|
this->data((xend >> 3) & 0xff);
|
|
|
|
this->command(0x45);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(yend & 0xff);
|
|
this->data((yend >> 8) & 0xff);
|
|
|
|
// SetCursor(self, Xstart, Ystart):
|
|
this->command(0x4E);
|
|
this->data(0x00);
|
|
this->command(0x4F);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
}
|
|
|
|
void HOT WaveshareEPaper2P7InBV2::display() {
|
|
uint32_t buf_len = this->get_buffer_length_();
|
|
// COMMAND DATA START TRANSMISSION 1 (BLACK)
|
|
this->command(0x24);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (RED)
|
|
this->command(0x26);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
|
|
delay(2);
|
|
|
|
this->command(0x20);
|
|
|
|
this->wait_until_idle_();
|
|
}
|
|
int WaveshareEPaper2P7InBV2::get_width_internal() { return 176; }
|
|
int WaveshareEPaper2P7InBV2::get_height_internal() { return 264; }
|
|
void WaveshareEPaper2P7InBV2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.7in B V2");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 2.90in Type B (LUT from OTP)
|
|
// Datasheet:
|
|
// - https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf
|
|
// - https://github.com/soonuse/epd-library-arduino/blob/master/2.9inch_e-paper_b/epd2in9b/epd2in9b.cpp
|
|
// ========================================================
|
|
|
|
void WaveshareEPaper2P9InB::initialize() {
|
|
// from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37
|
|
// EPD hardware init start
|
|
this->reset_();
|
|
|
|
// COMMAND BOOSTER SOFT START
|
|
this->command(0x06);
|
|
this->data(0x17);
|
|
this->data(0x17);
|
|
this->data(0x17);
|
|
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
// 128x296 resolution: 10
|
|
// LUT from OTP: 0
|
|
// B/W mode (doesn't work): 1
|
|
// scan-up: 1
|
|
// shift-right: 1
|
|
// booster ON: 1
|
|
// no soft reset: 1
|
|
this->data(0x9F);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
// set to 128x296 by COMMAND PANEL SETTING
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
// use defaults for white border and ESPHome image polarity
|
|
|
|
// EPD hardware init end
|
|
}
|
|
void HOT WaveshareEPaper2P9InB::display() {
|
|
// COMMAND DATA START TRANSMISSION 1 (B/W data)
|
|
this->command(0x10);
|
|
delay(2);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (RED data)
|
|
this->command(0x13);
|
|
delay(2);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++)
|
|
this->write_byte(0x00);
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
delay(2);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND POWER OFF
|
|
// NOTE: power off < deep sleep
|
|
this->command(0x02);
|
|
}
|
|
int WaveshareEPaper2P9InB::get_width_internal() { return 128; }
|
|
int WaveshareEPaper2P9InB::get_height_internal() { return 296; }
|
|
void WaveshareEPaper2P9InB::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9in (B)");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// Waveshare 2.9-inch E-Paper (Type D)
|
|
// Waveshare WIKI: https://www.waveshare.com/wiki/Pico-ePaper-2.9-D
|
|
// Datasheet: https://www.waveshare.com/w/upload/b/b5/2.9inch_e-Paper_(D)_Specification.pdf
|
|
// ========================================================
|
|
|
|
void WaveshareEPaper2P9InD::initialize() {
|
|
// EPD hardware init start
|
|
this->reset_();
|
|
|
|
// Booster Soft Start
|
|
this->command(0x06); // Command: BTST
|
|
this->data(0x17); // Soft start configuration Phase A
|
|
this->data(0x17); // Soft start configuration Phase B
|
|
this->data(0x17); // Soft start configuration Phase C
|
|
|
|
// Power Setting
|
|
this->command(0x01); // Command: PWR
|
|
this->data(0x03); // Intern DC/DC for VDH/VDL and VGH/VGL
|
|
this->data(0x00); // Default configuration VCOM_HV and VGHL_LV
|
|
this->data(0x2b); // VDH = 10.8 V
|
|
this->data(0x2b); // VDL = -10.8 V
|
|
|
|
// Power ON
|
|
this->command(0x04); // Command: PON
|
|
this->wait_until_idle_();
|
|
|
|
// Panel settings
|
|
this->command(0x00); // Command: PSR
|
|
this->data(0x1F); // LUT from OTP, black and white mode, default scan
|
|
|
|
// PLL Control
|
|
this->command(0x30); // Command: PLL
|
|
this->data(0x3A); // Default PLL frequency
|
|
|
|
// Resolution settings
|
|
this->command(0x61); // Command: TRES
|
|
this->data(0x80); // Width: 128
|
|
this->data(0x01); // Height MSB: 296
|
|
this->data(0x28); // Height LSB: 296
|
|
|
|
// VCOM and data interval settings
|
|
this->command(0x50); // Command: CDI
|
|
this->data(0x77);
|
|
|
|
// VCOM_DC settings
|
|
this->command(0x82); // Command: VDCS
|
|
this->data(0x12); // Dafault VCOM_DC
|
|
}
|
|
|
|
void WaveshareEPaper2P9InD::display() {
|
|
// Start transmitting old data (clearing buffer)
|
|
this->command(0x10); // Command: DTM1 (OLD frame data)
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// Start transmitting new data (updated content)
|
|
this->command(0x13); // Command: DTM2 (NEW frame data)
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// Refresh Display
|
|
this->command(0x12); // Command: DRF
|
|
this->wait_until_idle_();
|
|
|
|
// Enter Power Off
|
|
this->command(0x02); // Command: POF
|
|
this->wait_until_idle_();
|
|
|
|
// Enter Deep Sleep
|
|
this->command(0x07); // Command: DSLP
|
|
this->data(0xA5);
|
|
}
|
|
|
|
int WaveshareEPaper2P9InD::get_width_internal() { return 128; }
|
|
int WaveshareEPaper2P9InD::get_height_internal() { return 296; }
|
|
void WaveshareEPaper2P9InD::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9in (D)");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// DKE 2.9
|
|
// https://www.badge.team/docs/badges/sha2017/hardware/#e-ink-display-the-dke-group-depg0290b1
|
|
// https://www.badge.team/docs/badges/sha2017/hardware/DEPG0290B01V3.0.pdf
|
|
static const uint8_t LUT_SIZE_DKE = 70;
|
|
static const uint8_t UPDATE_LUT_DKE[LUT_SIZE_DKE] = {
|
|
0xA0, 0x90, 0x50, 0x0, 0x0, 0x0, 0x0, 0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0, 0xA0, 0x90, 0x50, 0x0,
|
|
0x0, 0x0, 0x0, 0x50, 0x90, 0xA0, 0x0, 0x0, 0x0, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0, 0x0, 0x0, 0xF,
|
|
0xF, 0x0, 0x0, 0x0, 0xF, 0xF, 0x0, 0x0, 0x02, 0xF, 0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
static const uint8_t PART_UPDATE_LUT_DKE[LUT_SIZE_DKE] = {
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
|
0x05, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
static const uint8_t FULL_UPDATE_LUT_DKE[LUT_SIZE_DKE] = {
|
|
0x90, 0x50, 0xa0, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0xa0, 0x80, 0x00, 0x90, 0x50, 0xa0, 0x50,
|
|
0x50, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17,
|
|
0x04, 0x00, 0x00, 0x00, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x06, 0x05, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00,
|
|
0x00, 0x01, 0x0e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
void WaveshareEPaper2P9InDKE::initialize() {
|
|
// Hardware reset
|
|
delay(10);
|
|
this->reset_pin_->digital_write(false);
|
|
delayMicroseconds(200);
|
|
this->reset_pin_->digital_write(true);
|
|
delayMicroseconds(200);
|
|
// Wait for busy low
|
|
this->wait_until_idle_();
|
|
// Software reset
|
|
this->command(0x12);
|
|
// Wait for busy low
|
|
this->wait_until_idle_();
|
|
// Set Analog Block Control
|
|
this->command(0x74);
|
|
this->data(0x54);
|
|
// Set Digital Block Control
|
|
this->command(0x7E);
|
|
this->data(0x3B);
|
|
// Set display size and driver output control
|
|
this->command(0x01);
|
|
// this->data(0x27);
|
|
// this->data(0x01);
|
|
// this->data(0x00);
|
|
this->data(this->get_height_internal() - 1);
|
|
this->data((this->get_height_internal() - 1) >> 8);
|
|
this->data(0x00); // ? GD = 0, SM = 0, TB = 0
|
|
// Ram data entry mode
|
|
this->command(0x11);
|
|
this->data(0x03);
|
|
// Set Ram X address
|
|
this->command(0x44);
|
|
this->data(0x00);
|
|
this->data(0x0F);
|
|
// Set Ram Y address
|
|
this->command(0x45);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x27);
|
|
this->data(0x01);
|
|
// Set border
|
|
this->command(0x3C);
|
|
// this->data(0x80);
|
|
this->data(0x01);
|
|
// Set VCOM value
|
|
this->command(0x2C);
|
|
this->data(0x26);
|
|
// Gate voltage setting
|
|
this->command(0x03);
|
|
this->data(0x17);
|
|
// Source voltage setting
|
|
this->command(0x04);
|
|
this->data(0x41);
|
|
this->data(0x00);
|
|
this->data(0x32);
|
|
// Frame setting 50hz
|
|
this->command(0x3A);
|
|
this->data(0x30);
|
|
this->command(0x3B);
|
|
this->data(0x0A);
|
|
// Load LUT
|
|
this->command(0x32);
|
|
for (uint8_t v : FULL_UPDATE_LUT_DKE)
|
|
this->data(v);
|
|
}
|
|
|
|
void HOT WaveshareEPaper2P9InDKE::display() {
|
|
ESP_LOGI(TAG, "Performing e-paper update.");
|
|
// Set Ram X address counter
|
|
this->command(0x4e);
|
|
this->data(0);
|
|
// Set Ram Y address counter
|
|
this->command(0x4f);
|
|
this->data(0);
|
|
this->data(0);
|
|
// Load image (128/8*296)
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
// Image update
|
|
this->command(0x22);
|
|
this->data(0xC7);
|
|
this->command(0x20);
|
|
// Wait for busy low
|
|
this->wait_until_idle_();
|
|
// Enter deep sleep mode
|
|
this->command(0x10);
|
|
this->data(0x01);
|
|
}
|
|
int WaveshareEPaper2P9InDKE::get_width_internal() { return 128; }
|
|
int WaveshareEPaper2P9InDKE::get_height_internal() { return 296; }
|
|
void WaveshareEPaper2P9InDKE::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9in DKE");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
void WaveshareEPaper2P9InDKE::set_full_update_every(uint32_t full_update_every) {
|
|
this->full_update_every_ = full_update_every;
|
|
}
|
|
|
|
// ========================================================
|
|
// 2.90in Type B (LUT from OTP)
|
|
// Datasheet:
|
|
// - https://files.waveshare.com/upload/a/af/2.9inch-e-paper-b-v3-specification.pdf
|
|
// ========================================================
|
|
|
|
void WaveshareEPaper2P9InBV3::initialize() {
|
|
// from https://github.com/waveshareteam/e-Paper/blob/master/Arduino/epd2in9b_V3/epd2in9b_V3.cpp
|
|
this->reset_();
|
|
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x0F);
|
|
this->data(0x89);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x80);
|
|
this->data(0x01);
|
|
this->data(0x28);
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x77);
|
|
}
|
|
void HOT WaveshareEPaper2P9InBV3::display() {
|
|
// COMMAND DATA START TRANSMISSION 1 (B/W data)
|
|
this->command(0x10);
|
|
delay(2);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
this->command(0x92);
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (RED data)
|
|
this->command(0x13);
|
|
delay(2);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++)
|
|
this->write_byte(0xFF);
|
|
this->end_data_();
|
|
this->command(0x92);
|
|
delay(2);
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
delay(2);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND POWER OFF
|
|
// NOTE: power off < deep sleep
|
|
this->command(0x02);
|
|
}
|
|
int WaveshareEPaper2P9InBV3::get_width_internal() { return 128; }
|
|
int WaveshareEPaper2P9InBV3::get_height_internal() { return 296; }
|
|
void WaveshareEPaper2P9InBV3::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9in (B) V3");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 2.90in v2 rev2
|
|
// based on SDK and examples in ZIP file from:
|
|
// https://www.waveshare.com/pico-epaper-2.9.htm
|
|
// ========================================================
|
|
|
|
void WaveshareEPaper2P9InV2R2::initialize() {
|
|
this->reset_();
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x12); // SWRESET
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x01);
|
|
this->data(0x27);
|
|
this->data(0x01);
|
|
this->data(0x00);
|
|
|
|
this->command(0x11);
|
|
this->data(0x03);
|
|
|
|
// SetWindows(0, 0, w, h)
|
|
this->command(0x44);
|
|
this->data(0x00);
|
|
this->data(((this->get_width_controller() - 1) >> 3) & 0xFF);
|
|
|
|
this->command(0x45);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data((this->get_height_internal() - 1) & 0xFF);
|
|
this->data(((this->get_height_internal() - 1) >> 8) & 0xFF);
|
|
|
|
this->command(0x21);
|
|
this->data(0x00);
|
|
this->data(0x80);
|
|
|
|
// SetCursor(0, 0)
|
|
this->command(0x4E);
|
|
this->data(0x00);
|
|
this->command(0x4f);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
WaveshareEPaper2P9InV2R2::WaveshareEPaper2P9InV2R2() { this->reset_duration_ = 10; }
|
|
|
|
void WaveshareEPaper2P9InV2R2::reset_() {
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->digital_write(false);
|
|
delay(reset_duration_); // NOLINT
|
|
this->reset_pin_->digital_write(true);
|
|
delay(reset_duration_); // NOLINT
|
|
}
|
|
}
|
|
|
|
void WaveshareEPaper2P9InV2R2::display() {
|
|
if (!this->wait_until_idle_()) {
|
|
this->status_set_warning();
|
|
ESP_LOGE(TAG, "fail idle 1");
|
|
return;
|
|
}
|
|
|
|
if (this->full_update_every_ == 1) {
|
|
// do single full update
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// TurnOnDisplay
|
|
this->command(0x22);
|
|
this->data(0xF7);
|
|
this->command(0x20);
|
|
return;
|
|
}
|
|
|
|
// if (this->full_update_every_ == 1 ||
|
|
if (this->at_update_ == 0) {
|
|
// do base update
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
this->command(0x26);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// TurnOnDisplay
|
|
this->command(0x22);
|
|
this->data(0xF7);
|
|
this->command(0x20);
|
|
} else {
|
|
// do partial update
|
|
this->reset_();
|
|
|
|
this->write_lut_(PARTIAL_UPD_2IN9_LUT, PARTIAL_UPD_2IN9_LUT_SIZE);
|
|
|
|
this->command(0x37);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x40);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
this->command(0x3C);
|
|
this->data(0x80);
|
|
|
|
this->command(0x22);
|
|
this->data(0xC0);
|
|
this->command(0x20);
|
|
|
|
if (!this->wait_until_idle_()) {
|
|
ESP_LOGE(TAG, "fail idle 2");
|
|
}
|
|
|
|
// SetWindows(0, 0, w, h)
|
|
this->command(0x44);
|
|
this->data(0x00);
|
|
this->data(((this->get_width_controller() - 1) >> 3) & 0xFF);
|
|
|
|
this->command(0x45);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data((this->get_height_internal() - 1) & 0xFF);
|
|
this->data(((this->get_height_internal() - 1) >> 8) & 0xFF);
|
|
|
|
// SetCursor(0, 0)
|
|
this->command(0x4E);
|
|
this->data(0x00);
|
|
this->command(0x4f);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
// write b/w
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// TurnOnDisplayPartial
|
|
this->command(0x22);
|
|
this->data(0x0F);
|
|
this->command(0x20);
|
|
}
|
|
|
|
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
|
}
|
|
|
|
void WaveshareEPaper2P9InV2R2::write_lut_(const uint8_t *lut, const uint8_t size) {
|
|
// COMMAND WRITE LUT REGISTER
|
|
this->command(0x32);
|
|
for (uint8_t i = 0; i < size; i++)
|
|
this->data(lut[i]);
|
|
}
|
|
|
|
void WaveshareEPaper2P9InV2R2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9inV2R2");
|
|
ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper2P9InV2R2::deep_sleep() {
|
|
this->command(0x10);
|
|
this->data(0x01);
|
|
}
|
|
|
|
int WaveshareEPaper2P9InV2R2::get_width_internal() { return 128; }
|
|
int WaveshareEPaper2P9InV2R2::get_height_internal() { return 296; }
|
|
int WaveshareEPaper2P9InV2R2::get_width_controller() { return this->get_width_internal(); }
|
|
void WaveshareEPaper2P9InV2R2::set_full_update_every(uint32_t full_update_every) {
|
|
this->full_update_every_ = full_update_every;
|
|
}
|
|
// ========================================================
|
|
// Good Display 2.9in black/white
|
|
// Datasheet:
|
|
// - https://files.seeedstudio.com/wiki/Other_Display/29-epaper/GDEY029T94.pdf
|
|
// -
|
|
// https://github.com/Allen-Kuang/e-ink_Demo/blob/main/2.9%20inch%20E-paper%20-%20monocolor%20128x296/example/Display_EPD_W21.cpp
|
|
// ========================================================
|
|
|
|
void GDEY029T94::initialize() {
|
|
// EPD hardware init start
|
|
this->reset_();
|
|
|
|
this->wait_until_idle_();
|
|
this->command(0x12); // SWRESET
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x01); // Driver output control
|
|
this->data((this->get_height_internal() - 1) % 256);
|
|
this->data((this->get_height_internal() - 1) / 256);
|
|
this->data(0x00);
|
|
|
|
this->command(0x11); // data entry mode
|
|
this->data(0x03);
|
|
|
|
this->command(0x44); // set Ram-X address start/end position
|
|
this->data(0x00);
|
|
this->data(this->get_width_internal() / 8 - 1);
|
|
|
|
this->command(0x45); // set Ram-Y address start/end position
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data((this->get_height_internal() - 1) % 256);
|
|
this->data((this->get_height_internal() - 1) / 256);
|
|
|
|
this->command(0x3C); // BorderWavefrom
|
|
this->data(0x05);
|
|
|
|
this->command(0x21); // Display update control
|
|
this->data(0x00);
|
|
this->data(0x80);
|
|
|
|
this->command(0x18); // Read built-in temperature sensor
|
|
this->data(0x80);
|
|
|
|
this->command(0x4E); // set RAM x address count to 0;
|
|
this->data(0x00);
|
|
this->command(0x4F); // set RAM y address count to 0x199;
|
|
this->command(0x00);
|
|
this->command(0x00);
|
|
this->wait_until_idle_();
|
|
}
|
|
void HOT GDEY029T94::display() {
|
|
this->command(0x24); // write RAM for black(0)/white (1)
|
|
this->start_data_();
|
|
for (uint32_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
this->write_byte(this->buffer_[i]);
|
|
}
|
|
this->end_data_();
|
|
this->command(0x22); // Display Update Control
|
|
this->data(0xF7);
|
|
this->command(0x20); // Activate Display Update Sequence
|
|
this->wait_until_idle_();
|
|
}
|
|
int GDEY029T94::get_width_internal() { return 128; }
|
|
int GDEY029T94::get_height_internal() { return 296; }
|
|
void GDEY029T94::dump_config() {
|
|
LOG_DISPLAY("", "E-Paper (Good Display)", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9in GDEY029T94");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// Good Display 2.9in black/white
|
|
// Datasheet:
|
|
// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1680.pdf
|
|
// - https://github.com/adafruit/Adafruit_EPD/blob/master/src/panels/ThinkInk_290_Grayscale4_T5.h
|
|
// - https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
|
|
// - http://www.e-paper-display.com/GDEW029T5%20V3.1%20Specification5c22.pdf?
|
|
// ========================================================
|
|
|
|
// full screen update LUT
|
|
static const uint8_t LUT_20_VCOMDC_29_5[] = {
|
|
0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x60, 0x28, 0x28, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00,
|
|
0x00, 0x00, 0x01, 0x00, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_21_WW_29_5[] = {
|
|
0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
|
|
0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_22_BW_29_5[] = {
|
|
0x40, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x40, 0x14,
|
|
0x00, 0x00, 0x00, 0x01, 0xA0, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_23_WB_29_5[] = {
|
|
0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
|
|
0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_24_BB_29_5[] = {
|
|
0x80, 0x08, 0x00, 0x00, 0x00, 0x02, 0x90, 0x28, 0x28, 0x00, 0x00, 0x01, 0x80, 0x14,
|
|
0x00, 0x00, 0x00, 0x01, 0x50, 0x12, 0x12, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
// partial screen update LUT
|
|
static const uint8_t LUT_20_VCOMDC_PARTIAL_29_5[] = {
|
|
0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_21_WW_PARTIAL_29_5[] = {
|
|
0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_22_BW_PARTIAL_29_5[] = {
|
|
0x80, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_23_WB_PARTIAL_29_5[] = {
|
|
0x40, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_24_BB_PARTIAL_29_5[] = {
|
|
0x00, 0x20, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
void GDEW029T5::power_on_() {
|
|
if (!this->power_is_on_) {
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
}
|
|
this->power_is_on_ = true;
|
|
}
|
|
|
|
void GDEW029T5::power_off_() {
|
|
this->command(0x02);
|
|
this->wait_until_idle_();
|
|
this->power_is_on_ = false;
|
|
}
|
|
|
|
void GDEW029T5::deep_sleep() {
|
|
this->power_off_();
|
|
if (this->deep_sleep_between_updates_) {
|
|
this->command(0x07); // deep sleep
|
|
this->data(0xA5); // check code
|
|
ESP_LOGD(TAG, "go to deep sleep");
|
|
this->is_deep_sleep_ = true;
|
|
}
|
|
}
|
|
|
|
void GDEW029T5::init_display_() {
|
|
// from https://github.com/ZinggJM/GxEPD2/blob/master/src/epd/GxEPD2_290_T5.cpp
|
|
|
|
// Hardware Initialization
|
|
if (this->deep_sleep_between_updates_ && this->is_deep_sleep_) {
|
|
ESP_LOGI(TAG, "wake up from deep sleep");
|
|
this->reset_();
|
|
this->is_deep_sleep_ = false;
|
|
}
|
|
|
|
// COMMAND POWER SETTINGS
|
|
this->command(0x01);
|
|
this->data(0x03);
|
|
this->data(0x00);
|
|
this->data(0x2b);
|
|
this->data(0x2b);
|
|
this->data(0x03); /* for b/w */
|
|
|
|
// COMMAND BOOSTER SOFT START
|
|
this->command(0x06);
|
|
this->data(0x17);
|
|
this->data(0x17);
|
|
this->data(0x17);
|
|
|
|
this->power_on_();
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
// 128x296 resolution: 10
|
|
// LUT from register: 1
|
|
// B/W mode (doesn't work): 1
|
|
// scan-up: 1
|
|
// shift-right: 1
|
|
// booster ON: 1
|
|
// no soft reset: 1
|
|
this->data(0b10111111);
|
|
this->data(0x0d); // VCOM to 0V fast
|
|
this->command(0x30); // PLL setting
|
|
this->data(0x3a); // 3a 100HZ 29 150Hz 39 200HZ 31 171HZ
|
|
this->command(0x61); // resolution setting
|
|
this->data(this->get_width_internal());
|
|
this->data(this->get_height_internal() >> 8);
|
|
this->data(this->get_height_internal() & 0xFF);
|
|
|
|
ESP_LOGD(TAG, "panel setting done");
|
|
}
|
|
|
|
void GDEW029T5::initialize() {
|
|
// from https://www.waveshare.com/w/upload/b/bb/2.9inch-e-paper-b-specification.pdf, page 37
|
|
if (this->reset_pin_ != nullptr)
|
|
this->deep_sleep_between_updates_ = true;
|
|
|
|
// old buffer for partial update
|
|
RAMAllocator<uint8_t> allocator;
|
|
this->old_buffer_ = allocator.allocate(this->get_buffer_length_());
|
|
if (this->old_buffer_ == nullptr) {
|
|
ESP_LOGE(TAG, "Could not allocate old buffer for display!");
|
|
return;
|
|
}
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
this->old_buffer_[i] = 0xFF;
|
|
}
|
|
}
|
|
|
|
// initialize for full(normal) update
|
|
void GDEW029T5::init_full_() {
|
|
this->init_display_();
|
|
this->command(0x82); // vcom_DC setting
|
|
this->data(0x08);
|
|
this->command(0x50); // VCOM AND DATA INTERVAL SETTING
|
|
this->data(0x97); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
|
|
this->command(0x20);
|
|
this->write_lut_(LUT_20_VCOMDC_29_5, sizeof(LUT_20_VCOMDC_29_5));
|
|
this->command(0x21);
|
|
this->write_lut_(LUT_21_WW_29_5, sizeof(LUT_21_WW_29_5));
|
|
this->command(0x22);
|
|
this->write_lut_(LUT_22_BW_29_5, sizeof(LUT_22_BW_29_5));
|
|
this->command(0x23);
|
|
this->write_lut_(LUT_23_WB_29_5, sizeof(LUT_23_WB_29_5));
|
|
this->command(0x24);
|
|
this->write_lut_(LUT_24_BB_29_5, sizeof(LUT_24_BB_29_5));
|
|
ESP_LOGD(TAG, "initialized full update");
|
|
}
|
|
|
|
// initialzie for partial update
|
|
void GDEW029T5::init_partial_() {
|
|
this->init_display_();
|
|
this->command(0x82); // vcom_DC setting
|
|
this->data(0x08);
|
|
this->command(0x50); // VCOM AND DATA INTERVAL SETTING
|
|
this->data(0x17); // WBmode:VBDF 17|D7 VBDW 97 VBDB 57 WBRmode:VBDF F7 VBDW 77 VBDB 37 VBDR B7
|
|
this->command(0x20);
|
|
this->write_lut_(LUT_20_VCOMDC_PARTIAL_29_5, sizeof(LUT_20_VCOMDC_PARTIAL_29_5));
|
|
this->command(0x21);
|
|
this->write_lut_(LUT_21_WW_PARTIAL_29_5, sizeof(LUT_21_WW_PARTIAL_29_5));
|
|
this->command(0x22);
|
|
this->write_lut_(LUT_22_BW_PARTIAL_29_5, sizeof(LUT_22_BW_PARTIAL_29_5));
|
|
this->command(0x23);
|
|
this->write_lut_(LUT_23_WB_PARTIAL_29_5, sizeof(LUT_23_WB_PARTIAL_29_5));
|
|
this->command(0x24);
|
|
this->write_lut_(LUT_24_BB_PARTIAL_29_5, sizeof(LUT_24_BB_PARTIAL_29_5));
|
|
ESP_LOGD(TAG, "initialized partial update");
|
|
}
|
|
|
|
void HOT GDEW029T5::display() {
|
|
bool full_update = this->at_update_ == 0;
|
|
if (full_update) {
|
|
this->init_full_();
|
|
} else {
|
|
this->init_partial_();
|
|
this->command(0x91); // partial in
|
|
// set partial window
|
|
this->command(0x90);
|
|
// this->data(0);
|
|
this->data(0);
|
|
// this->data(0);
|
|
this->data((this->get_width_internal() - 1) % 256);
|
|
this->data(0);
|
|
this->data(0);
|
|
this->data(((this->get_height_internal() - 1)) / 256);
|
|
this->data(((this->get_height_internal() - 1)) % 256);
|
|
this->data(0x01);
|
|
}
|
|
// input old buffer data
|
|
this->command(0x10);
|
|
delay(2);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
this->write_byte(this->old_buffer_[i]);
|
|
}
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (B/W only)
|
|
this->command(0x13);
|
|
delay(2);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
this->write_byte(this->buffer_[i]);
|
|
this->old_buffer_[i] = this->buffer_[i];
|
|
}
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
delay(2);
|
|
this->wait_until_idle_();
|
|
|
|
if (full_update) {
|
|
ESP_LOGD(TAG, "full update done");
|
|
} else {
|
|
this->command(0x92); // partial out
|
|
ESP_LOGD(TAG, "partial update done");
|
|
}
|
|
|
|
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
|
// COMMAND deep sleep
|
|
this->deep_sleep();
|
|
}
|
|
|
|
void GDEW029T5::write_lut_(const uint8_t *lut, const uint8_t size) {
|
|
// COMMAND WRITE LUT REGISTER
|
|
this->start_data_();
|
|
for (uint8_t i = 0; i < size; i++)
|
|
this->write_byte(lut[i]);
|
|
this->end_data_();
|
|
}
|
|
|
|
void GDEW029T5::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
|
|
|
|
int GDEW029T5::get_width_internal() { return 128; }
|
|
int GDEW029T5::get_height_internal() { return 296; }
|
|
void GDEW029T5::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper (Good Display)", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.9in Greyscale GDEW029T5");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// Good Display 1.54in black/white/grey GDEW0154M09
|
|
// As used in M5Stack Core Ink
|
|
// Datasheet:
|
|
// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEW0154M09-200709.pdf
|
|
// - https://github.com/m5stack/M5Core-Ink
|
|
// Reference code from GoodDisplay:
|
|
// - https://github.com/GoodDisplay/E-paper-Display-Library-of-GoodDisplay/
|
|
// -> /Monochrome_E-paper-Display/1.54inch_JD79653_GDEW0154M09_200x200/ESP32-Arduino%20IDE/GDEW0154M09_Arduino.ino
|
|
// M5Stack Core Ink spec:
|
|
// - https://docs.m5stack.com/en/core/coreink
|
|
// ========================================================
|
|
|
|
void GDEW0154M09::initialize() {
|
|
this->init_internal_();
|
|
RAMAllocator<uint8_t> allocator;
|
|
this->lastbuff_ = allocator.allocate(this->get_buffer_length_());
|
|
if (this->lastbuff_ != nullptr) {
|
|
memset(this->lastbuff_, 0xff, sizeof(uint8_t) * this->get_buffer_length_());
|
|
}
|
|
this->clear_();
|
|
}
|
|
|
|
void GDEW0154M09::reset_() {
|
|
// RST is inverse from other einks in this project
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->digital_write(false);
|
|
delay(10);
|
|
this->reset_pin_->digital_write(true);
|
|
delay(10);
|
|
}
|
|
}
|
|
|
|
void GDEW0154M09::init_internal_() {
|
|
this->reset_();
|
|
|
|
// clang-format off
|
|
// 200x200 resolution: 11
|
|
// LUT from OTP: 0
|
|
// B/W mode (doesn't work): 1
|
|
// scan-up: 1
|
|
// shift-right: 1
|
|
// booster ON: 1
|
|
// no soft reset: 1
|
|
const uint8_t panel_setting_1 = 0b11011111;
|
|
|
|
// VCOM status off 0
|
|
// Temp sensing default 1
|
|
// VGL Power Off Floating 1
|
|
// NORG expect refresh 1
|
|
// VCOM Off on displ off 0
|
|
const uint8_t panel_setting_2 = 0b01110;
|
|
|
|
const uint8_t wf_t0154_cz_b3_list[] = {
|
|
11, // 11 commands in list
|
|
CMD_PSR_PANEL_SETTING, 2, panel_setting_1, panel_setting_2,
|
|
CMD_UNDOCUMENTED_0x4D, 1, 0x55,
|
|
CMD_UNDOCUMENTED_0xAA, 1, 0x0f,
|
|
CMD_UNDOCUMENTED_0xE9, 1, 0x02,
|
|
CMD_UNDOCUMENTED_0xB6, 1, 0x11,
|
|
CMD_UNDOCUMENTED_0xF3, 1, 0x0a,
|
|
CMD_TRES_RESOLUTION_SETTING, 3, 0xc8, 0x00, 0xc8,
|
|
CMD_TCON_TCONSETTING, 1, 0x00,
|
|
CMD_CDI_VCOM_DATA_INTERVAL, 1, 0xd7,
|
|
CMD_PWS_POWER_SAVING, 1, 0x00,
|
|
CMD_PON_POWER_ON, 0
|
|
};
|
|
// clang-format on
|
|
|
|
this->write_init_list_(wf_t0154_cz_b3_list);
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
void GDEW0154M09::write_init_list_(const uint8_t *list) {
|
|
uint8_t list_limit = list[0];
|
|
uint8_t *start_ptr = ((uint8_t *) list + 1);
|
|
for (uint8_t i = 0; i < list_limit; i++) {
|
|
this->command(*(start_ptr + 0));
|
|
for (uint8_t dnum = 0; dnum < *(start_ptr + 1); dnum++) {
|
|
this->data(*(start_ptr + 2 + dnum));
|
|
}
|
|
start_ptr += (*(start_ptr + 1) + 2);
|
|
}
|
|
}
|
|
|
|
void GDEW0154M09::clear_() {
|
|
uint32_t pixsize = this->get_buffer_length_();
|
|
for (uint8_t j = 0; j < 2; j++) {
|
|
this->command(CMD_DTM1_DATA_START_TRANS);
|
|
for (int count = 0; count < pixsize; count++) {
|
|
this->data(0x00);
|
|
}
|
|
this->command(CMD_DTM2_DATA_START_TRANS2);
|
|
for (int count = 0; count < pixsize; count++) {
|
|
this->data(0xff);
|
|
}
|
|
this->command(CMD_DISPLAY_REFRESH);
|
|
delay(10);
|
|
this->wait_until_idle_();
|
|
}
|
|
}
|
|
|
|
void HOT GDEW0154M09::display() {
|
|
this->init_internal_();
|
|
// "Mode 0 display" for now
|
|
this->command(CMD_DTM1_DATA_START_TRANS);
|
|
for (int i = 0; i < this->get_buffer_length_(); i++) {
|
|
this->data(0xff);
|
|
}
|
|
this->command(CMD_DTM2_DATA_START_TRANS2); // write 'new' data to SRAM
|
|
for (int i = 0; i < this->get_buffer_length_(); i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
this->command(CMD_DISPLAY_REFRESH);
|
|
delay(10);
|
|
this->wait_until_idle_();
|
|
this->deep_sleep();
|
|
}
|
|
|
|
void GDEW0154M09::deep_sleep() {
|
|
// COMMAND DEEP SLEEP
|
|
this->command(CMD_POF_POWER_OFF);
|
|
this->wait_until_idle_();
|
|
delay(1000); // NOLINT
|
|
this->command(CMD_DSLP_DEEP_SLEEP);
|
|
this->data(DATA_DSLP_DEEP_SLEEP);
|
|
}
|
|
|
|
int GDEW0154M09::get_width_internal() { return 200; }
|
|
int GDEW0154M09::get_height_internal() { return 200; }
|
|
void GDEW0154M09::dump_config() {
|
|
LOG_DISPLAY("", "M5Stack CoreInk E-Paper (Good Display)", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 1.54in Greyscale GDEW0154M09");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// Good Display 4.2in black/white GDEY042T81 (SSD1683)
|
|
// Product page:
|
|
// - https://www.good-display.com/product/386.html
|
|
// Datasheet:
|
|
// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf
|
|
// - https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF
|
|
// Reference code from GoodDisplay:
|
|
// - https://www.good-display.com/companyfile/1572.html (2024-08-01 15:40:41)
|
|
// Other reference code:
|
|
// - https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp
|
|
// ========================================================
|
|
|
|
void GDEY042T81::initialize() {
|
|
this->init_display_();
|
|
ESP_LOGD(TAG, "Initialization complete, set the display to deep sleep");
|
|
this->deep_sleep();
|
|
}
|
|
|
|
// conflicting documentation / examples regarding reset timings
|
|
// https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF -> 10ms
|
|
// GD sample code (Display_EPD_W21.cpp, see above) -> 10 ms
|
|
// https://v4.cecdn.yun300.cn/100001_1909185148/GDEY042T81.pdf (section 14.2) -> 0.2ms (200us)
|
|
// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L351
|
|
// -> 10ms
|
|
// 10 ms seems to work, so we use this
|
|
GDEY042T81::GDEY042T81() { this->reset_duration_ = 10; }
|
|
|
|
void GDEY042T81::reset_() {
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->digital_write(false);
|
|
delay(reset_duration_); // NOLINT
|
|
this->reset_pin_->digital_write(true);
|
|
delay(reset_duration_); // NOLINT
|
|
}
|
|
}
|
|
|
|
void GDEY042T81::init_display_() {
|
|
this->reset_();
|
|
|
|
this->wait_until_idle_();
|
|
this->command(0x12); // SWRESET
|
|
this->wait_until_idle_();
|
|
|
|
// Specify number of lines for the driver: 300 (MUX 300)
|
|
// https://v4.cecdn.yun300.cn/100001_1909185148/SSD1683.PDF (section 8.1)
|
|
// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L354
|
|
this->command(0x01); // driver output control
|
|
this->data(0x2B); // (height - 1) % 256
|
|
this->data(0x01); // (height - 1) / 256
|
|
this->data(0x00);
|
|
|
|
// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L360
|
|
this->command(0x3C); // BorderWaveform
|
|
this->data(0x01);
|
|
this->command(0x18); // Read built-in temperature sensor
|
|
this->data(0x80);
|
|
|
|
// GD sample code (Display_EPD_W21.cpp@90ff)
|
|
this->command(0x11); // data entry mode
|
|
this->data(0x03);
|
|
// set windows (0,0,400,300)
|
|
this->command(0x44); // set Ram-X address start/end position
|
|
this->data(0);
|
|
this->data(0x31); // (width / 8 -1)
|
|
|
|
this->command(0x45); // set Ram-y address start/end position
|
|
this->data(0);
|
|
this->data(0);
|
|
this->data(0x2B); // (height - 1) % 256
|
|
this->data(0x01); // (height - 1) / 256
|
|
|
|
// set cursor (0,0)
|
|
this->command(0x4E); // set RAM x address count to 0;
|
|
this->data(0);
|
|
this->command(0x4F); // set RAM y address count to 0;
|
|
this->data(0);
|
|
this->data(0);
|
|
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L366
|
|
void GDEY042T81::update_full_() {
|
|
this->command(0x21); // display update control
|
|
this->data(0x40); // bypass RED as 0
|
|
this->data(0x00); // single chip application
|
|
|
|
// only ever do a fast update because slow updates are only relevant
|
|
// for lower operating temperatures
|
|
// see
|
|
// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_290_GDEY029T94.h#L30
|
|
//
|
|
// Should slow/fast updates be made configurable similar to how GxEPD2 does it? No idea if anyone would need it...
|
|
this->command(0x1A); // Write to temperature register
|
|
this->data(0x6E);
|
|
this->command(0x22);
|
|
this->data(0xd7);
|
|
|
|
this->command(0x20);
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L389
|
|
void GDEY042T81::update_part_() {
|
|
this->command(0x21); // display update control
|
|
this->data(0x00); // RED normal
|
|
this->data(0x00); // single chip application
|
|
|
|
this->command(0x22);
|
|
this->data(0xfc);
|
|
|
|
this->command(0x20);
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
void HOT GDEY042T81::display() {
|
|
ESP_LOGD(TAG, "Wake up the display");
|
|
this->init_display_();
|
|
|
|
if (!this->wait_until_idle_()) {
|
|
this->status_set_warning();
|
|
ESP_LOGE(TAG, "Failed to perform update, display is busy");
|
|
return;
|
|
}
|
|
|
|
// basic code structure copied from WaveshareEPaper2P9InV2R2
|
|
if (this->full_update_every_ == 1) {
|
|
ESP_LOGD(TAG, "Full update");
|
|
// do single full update
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// TurnOnDisplay
|
|
this->update_full_();
|
|
return;
|
|
}
|
|
|
|
// if (this->full_update_every_ == 1 ||
|
|
if (this->at_update_ == 0) {
|
|
ESP_LOGD(TAG, "Update");
|
|
// do base update
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
this->command(0x26);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// TurnOnDisplay;
|
|
this->update_full_();
|
|
} else {
|
|
// do partial update (full screen)
|
|
// no need to load a LUT for GoodDisplays as they seem to have the LUT onboard
|
|
// GD example code (Display_EPD_W21.cpp@283ff)
|
|
//
|
|
// not setting the BorderWaveform here again (contrary to the GD example) because according to
|
|
// https://github.com/ZinggJM/GxEPD2/blob/03d8e7a533c1493f762e392ead12f1bcb7fab8f9/src/gdey/GxEPD2_420_GDEY042T81.cpp#L358
|
|
// it seems to be enough to set it during display initialization
|
|
ESP_LOGD(TAG, "Partial update");
|
|
this->reset_();
|
|
if (!this->wait_until_idle_()) {
|
|
this->status_set_warning();
|
|
ESP_LOGE(TAG, "Failed to perform partial update, display is busy");
|
|
return;
|
|
}
|
|
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// TurnOnDisplay
|
|
this->update_part_();
|
|
}
|
|
|
|
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
|
this->wait_until_idle_();
|
|
ESP_LOGD(TAG, "Set the display back to deep sleep");
|
|
this->deep_sleep();
|
|
}
|
|
void GDEY042T81::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
|
|
int GDEY042T81::get_width_internal() { return 400; }
|
|
int GDEY042T81::get_height_internal() { return 300; }
|
|
uint32_t GDEY042T81::idle_timeout_() { return 5000; }
|
|
void GDEY042T81::dump_config() {
|
|
LOG_DISPLAY("", "GoodDisplay E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 4.2in B/W GDEY042T81");
|
|
ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
static const uint8_t LUT_VCOM_DC_4_2[] = {
|
|
0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, 0x00, 0x0A, 0x01,
|
|
0x00, 0x00, 0x01, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
static const uint8_t LUT_WHITE_TO_WHITE_4_2[] = {
|
|
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
static const uint8_t LUT_BLACK_TO_WHITE_4_2[] = {
|
|
0x40, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x40, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_BLACK_TO_BLACK_4_2[] = {
|
|
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
static const uint8_t LUT_WHITE_TO_BLACK_4_2[] = {
|
|
0x80, 0x17, 0x00, 0x00, 0x00, 0x02, 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, 0x80, 0x0A,
|
|
0x01, 0x00, 0x00, 0x01, 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
};
|
|
|
|
void WaveshareEPaper4P2In::initialize() {
|
|
// https://www.waveshare.com/w/upload/7/7f/4.2inch-e-paper-b-specification.pdf - page 8
|
|
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x03); // VDS_EN, VDG_EN
|
|
this->data(0x00); // VCOM_HV, VGHL_LV[1], VGHL_LV[0]
|
|
this->data(0x2B); // VDH
|
|
this->data(0x2B); // VDL
|
|
this->data(0xFF); // VDHR
|
|
|
|
// COMMAND BOOSTER SOFT START
|
|
this->command(0x06);
|
|
this->data(0x17); // PHA
|
|
this->data(0x17); // PHB
|
|
this->data(0x17); // PHC
|
|
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
delay(10);
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0xBF); // KW-BF KWR-AF BWROTP 0f
|
|
this->data(0x0B);
|
|
// COMMAND PLL CONTROL
|
|
this->command(0x30);
|
|
this->data(0x3C); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
|
|
|
|
delay(2);
|
|
// COMMAND LUT FOR VCOM
|
|
this->command(0x20);
|
|
for (uint8_t i : LUT_VCOM_DC_4_2)
|
|
this->data(i);
|
|
// COMMAND LUT WHITE TO WHITE
|
|
this->command(0x21);
|
|
for (uint8_t i : LUT_WHITE_TO_WHITE_4_2)
|
|
this->data(i);
|
|
// COMMAND LUT BLACK TO WHITE
|
|
this->command(0x22);
|
|
for (uint8_t i : LUT_BLACK_TO_WHITE_4_2)
|
|
this->data(i);
|
|
// COMMAND LUT WHITE TO BLACK
|
|
this->command(0x23);
|
|
for (uint8_t i : LUT_WHITE_TO_BLACK_4_2)
|
|
this->data(i);
|
|
// COMMAND LUT BLACK TO BLACK
|
|
this->command(0x24);
|
|
for (uint8_t i : LUT_BLACK_TO_BLACK_4_2)
|
|
this->data(i);
|
|
}
|
|
void HOT WaveshareEPaper4P2In::display() {
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x01);
|
|
this->data(0x90);
|
|
this->data(0x01);
|
|
this->data(0x2C);
|
|
|
|
// COMMAND VCM DC SETTING REGISTER
|
|
this->command(0x82);
|
|
this->data(0x12);
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x97);
|
|
|
|
// COMMAND DATA START TRANSMISSION 1
|
|
this->command(0x10);
|
|
delay(2);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
delay(2);
|
|
// COMMAND DATA START TRANSMISSION 2
|
|
this->command(0x13);
|
|
delay(2);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
}
|
|
int WaveshareEPaper4P2In::get_width_internal() { return 400; }
|
|
int WaveshareEPaper4P2In::get_height_internal() { return 300; }
|
|
void WaveshareEPaper4P2In::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 4.2in");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 4.20in Type B (LUT from OTP)
|
|
// Datasheet:
|
|
// - https://www.waveshare.com/w/upload/2/20/4.2inch-e-paper-module-user-manual-en.pdf
|
|
// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_4in2b_V2.c
|
|
// ========================================================
|
|
void WaveshareEPaper4P2InBV2::initialize() {
|
|
// these exact timings are required for a proper reset/init
|
|
this->reset_pin_->digital_write(false);
|
|
delay(2);
|
|
this->reset_pin_->digital_write(true);
|
|
delay(200); // NOLINT
|
|
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x0f); // LUT from OTP
|
|
}
|
|
|
|
void HOT WaveshareEPaper4P2InBV2::display() {
|
|
// COMMAND DATA START TRANSMISSION 1 (B/W data)
|
|
this->command(0x10);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (RED data)
|
|
this->command(0x13);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++)
|
|
this->write_byte(0xFF);
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND POWER OFF
|
|
// NOTE: power off < deep sleep
|
|
this->command(0x02);
|
|
}
|
|
int WaveshareEPaper4P2InBV2::get_width_internal() { return 400; }
|
|
int WaveshareEPaper4P2InBV2::get_height_internal() { return 300; }
|
|
void WaveshareEPaper4P2InBV2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 4.2in (B V2)");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 4.20in Type B With Red colour support (LUT from OTP)
|
|
// Datasheet:
|
|
// - https://www.waveshare.com/w/upload/2/20/4.2inch-e-paper-module-user-manual-en.pdf
|
|
// - https://github.com/waveshare/e-Paper/blob/master/RaspberryPi_JetsonNano/c/lib/e-Paper/EPD_4in2b_V2.c
|
|
// The implementation is an adaptation of WaveshareEPaper4P2InBV2 class
|
|
// ========================================================
|
|
void WaveshareEPaper4P2InBV2BWR::initialize() {
|
|
// these exact timings are required for a proper reset/init
|
|
this->reset_pin_->digital_write(false);
|
|
delay(2);
|
|
this->reset_pin_->digital_write(true);
|
|
delay(200); // NOLINT
|
|
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x0f); // LUT from OTP
|
|
}
|
|
|
|
void HOT WaveshareEPaper4P2InBV2BWR::display() {
|
|
const uint32_t buf_len = this->get_buffer_length_() / 2u;
|
|
|
|
this->command(0x10); // Send BW data Transmission
|
|
delay(2); // Delay to prevent Watchdog error
|
|
for (uint32_t i = 0; i < buf_len; ++i) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
|
|
this->command(0x13); // Send red data Transmission
|
|
delay(2); // Delay to prevent Watchdog error
|
|
for (uint32_t i = 0; i < buf_len; ++i) {
|
|
// Red color need to flip bit from the buffer. Otherwise, red will conqure the screen!
|
|
this->data(~this->buffer_[buf_len + i]);
|
|
}
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND POWER OFF
|
|
// NOTE: power off < deep sleep
|
|
this->command(0x02);
|
|
}
|
|
int WaveshareEPaper4P2InBV2BWR::get_width_internal() { return 400; }
|
|
int WaveshareEPaper4P2InBV2BWR::get_height_internal() { return 300; }
|
|
void WaveshareEPaper4P2InBV2BWR::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 4.2in (B V2) BWR-Mode");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper5P8In::initialize() {
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x37);
|
|
this->data(0x00);
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0xCF);
|
|
this->data(0x0B);
|
|
|
|
// COMMAND BOOSTER SOFT START
|
|
this->command(0x06);
|
|
this->data(0xC7);
|
|
this->data(0xCC);
|
|
this->data(0x28);
|
|
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
delay(10);
|
|
|
|
// COMMAND PLL CONTROL
|
|
this->command(0x30);
|
|
this->data(0x3C);
|
|
|
|
// COMMAND TEMPERATURE SENSOR CALIBRATION
|
|
this->command(0x41);
|
|
this->data(0x00);
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x77);
|
|
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x02);
|
|
this->data(0x58);
|
|
this->data(0x01);
|
|
this->data(0xC0);
|
|
|
|
// COMMAND VCM DC SETTING REGISTER
|
|
this->command(0x82);
|
|
this->data(0x1E);
|
|
|
|
this->command(0xE5);
|
|
this->data(0x03);
|
|
}
|
|
void HOT WaveshareEPaper5P8In::display() {
|
|
// COMMAND DATA START TRANSMISSION 1
|
|
this->command(0x10);
|
|
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
uint8_t temp1 = this->buffer_[i];
|
|
for (uint8_t j = 0; j < 8; j++) {
|
|
uint8_t temp2;
|
|
if (temp1 & 0x80) {
|
|
temp2 = 0x03;
|
|
} else {
|
|
temp2 = 0x00;
|
|
}
|
|
|
|
temp2 <<= 4;
|
|
temp1 <<= 1;
|
|
j++;
|
|
if (temp1 & 0x80) {
|
|
temp2 |= 0x03;
|
|
} else {
|
|
temp2 |= 0x00;
|
|
}
|
|
temp1 <<= 1;
|
|
this->write_byte(temp2);
|
|
}
|
|
|
|
App.feed_wdt();
|
|
}
|
|
this->end_data_();
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
}
|
|
int WaveshareEPaper5P8In::get_width_internal() { return 600; }
|
|
int WaveshareEPaper5P8In::get_height_internal() { return 448; }
|
|
void WaveshareEPaper5P8In::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 5.83in");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// 5.83in V2
|
|
// Datasheet/Specification/Reference:
|
|
// - https://www.waveshare.com/w/upload/3/37/5.83inch_e-Paper_V2_Specification.pdf
|
|
// - https://github.com/waveshare/e-Paper/blob/master/Arduino/epd5in83_V2/epd5in83_V2.cpp
|
|
// ========================================================
|
|
void WaveshareEPaper5P8InV2::initialize() {
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x07);
|
|
this->data(0x07);
|
|
this->data(0x3f);
|
|
this->data(0x3f);
|
|
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
delay(10);
|
|
this->wait_until_idle_();
|
|
|
|
// PANNEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x1F);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x02);
|
|
this->data(0x88);
|
|
this->data(0x01);
|
|
this->data(0xE0);
|
|
|
|
this->command(0x15);
|
|
this->data(0x00);
|
|
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
|
|
// Do we need this?
|
|
// COMMAND PLL CONTROL
|
|
this->command(0x30);
|
|
this->data(0x3C); // 3A 100HZ 29 150Hz 39 200HZ 31 171HZ
|
|
}
|
|
void HOT WaveshareEPaper5P8InV2::display() {
|
|
// Reuse the code from WaveshareEPaper4P2In::display()
|
|
// COMMAND VCM DC SETTING REGISTER
|
|
this->command(0x82);
|
|
this->data(0x12);
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x97);
|
|
|
|
// COMMAND DATA START TRANSMISSION 1
|
|
this->command(0x10);
|
|
delay(2);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2
|
|
this->command(0x13);
|
|
delay(2);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
}
|
|
int WaveshareEPaper5P8InV2::get_width_internal() { return 648; }
|
|
int WaveshareEPaper5P8InV2::get_height_internal() { return 480; }
|
|
void WaveshareEPaper5P8InV2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 5.83inv2");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// ========================================================
|
|
// Good Display 5.83in black/white GDEY0583T81
|
|
// Product page:
|
|
// - https://www.good-display.com/product/440.html
|
|
// - https://www.seeedstudio.com/5-83-Monochrome-ePaper-Display-with-648x480-Pixels-p-5785.html
|
|
// Datasheet:
|
|
// -
|
|
// https://www.good-display.com/public/html/pdfjs/viewer/viewernew.html?file=https://v4.cecdn.yun300.cn/100001_1909185148/GDEY0583T81-new.pdf
|
|
// - https://v4.cecdn.yun300.cn/100001_1909185148/GDEY0583T81-new.pdf
|
|
// Reference code from GoodDisplay:
|
|
// - https://www.good-display.com/companyfile/903.html
|
|
// ========================================================
|
|
|
|
void GDEY0583T81::initialize() {
|
|
// Allocate buffer for old data for partial updates
|
|
RAMAllocator<uint8_t> allocator{};
|
|
this->old_buffer_ = allocator.allocate(this->get_buffer_length_());
|
|
if (this->old_buffer_ == nullptr) {
|
|
ESP_LOGE(TAG, "Could not allocate old buffer for display!");
|
|
return;
|
|
}
|
|
memset(this->old_buffer_, 0xFF, this->get_buffer_length_());
|
|
|
|
this->init_full_();
|
|
|
|
this->wait_until_idle_();
|
|
|
|
this->deep_sleep();
|
|
}
|
|
|
|
void GDEY0583T81::power_on_() {
|
|
if (!this->power_is_on_) {
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
}
|
|
this->power_is_on_ = true;
|
|
this->is_deep_sleep_ = false;
|
|
}
|
|
|
|
void GDEY0583T81::power_off_() {
|
|
this->command(0x02);
|
|
this->wait_until_idle_();
|
|
this->power_is_on_ = false;
|
|
}
|
|
|
|
void GDEY0583T81::deep_sleep() {
|
|
if (this->is_deep_sleep_) {
|
|
return;
|
|
}
|
|
|
|
// VCOM and data interval setting (CDI)
|
|
this->command(0x50);
|
|
this->data(0xf7);
|
|
|
|
this->power_off_();
|
|
delay(10);
|
|
|
|
// Deep sleep (DSLP)
|
|
this->command(0x07);
|
|
this->data(0xA5);
|
|
this->is_deep_sleep_ = true;
|
|
}
|
|
|
|
void GDEY0583T81::reset_() {
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->digital_write(false);
|
|
delay(10);
|
|
this->reset_pin_->digital_write(true);
|
|
delay(10);
|
|
}
|
|
}
|
|
|
|
// Initialize for full screen update in fast mode
|
|
void GDEY0583T81::init_full_() {
|
|
this->init_display_();
|
|
|
|
// Based on the GD sample code
|
|
// VCOM and data interval setting (CDI)
|
|
this->command(0x50);
|
|
this->data(0x29);
|
|
this->data(0x07);
|
|
|
|
// Cascade Setting (CCSET)
|
|
this->command(0xE0);
|
|
this->data(0x02);
|
|
|
|
// Force Temperature (TSSET)
|
|
this->command(0xE5);
|
|
this->data(0x5A);
|
|
}
|
|
|
|
// Initialize for a partial update of the full screen
|
|
void GDEY0583T81::init_partial_() {
|
|
this->init_display_();
|
|
|
|
// Cascade Setting (CCSET)
|
|
this->command(0xE0);
|
|
this->data(0x02);
|
|
|
|
// Force Temperature (TSSET)
|
|
this->command(0xE5);
|
|
this->data(0x6E);
|
|
}
|
|
|
|
void GDEY0583T81::init_display_() {
|
|
this->reset_();
|
|
|
|
// Panel Setting (PSR)
|
|
this->command(0x00);
|
|
// Sets: REG=0, LUT from OTP (set by CDI)
|
|
// KW/R=1, Sets KW mode (Black/White)
|
|
// as opposed to the default KWR mode (Black/White/Red)
|
|
// UD=1, Gate Scan Direction, 1 = up (default)
|
|
// SHL=1, Source Shift Direction, 1 = right (default)
|
|
// SHD_N=1, Booster Switch, 1 = ON (default)
|
|
// RST_N=1, Soft reset, 1 = No effect (default)
|
|
this->data(0x1F);
|
|
|
|
// Resolution setting (TRES)
|
|
this->command(0x61);
|
|
|
|
// Horizontal display resolution (HRES)
|
|
this->data(get_width_internal() / 256);
|
|
this->data(get_width_internal() % 256);
|
|
|
|
// Vertical display resolution (VRES)
|
|
this->data(get_height_internal() / 256);
|
|
this->data(get_height_internal() % 256);
|
|
|
|
this->power_on_();
|
|
}
|
|
|
|
void HOT GDEY0583T81::display() {
|
|
bool full_update = this->at_update_ == 0;
|
|
if (full_update) {
|
|
this->init_full_();
|
|
} else {
|
|
this->init_partial_();
|
|
|
|
// VCOM and data interval setting (CDI)
|
|
this->command(0x50);
|
|
this->data(0xA9);
|
|
this->data(0x07);
|
|
|
|
// Partial In (PTIN), makes the display enter partial mode
|
|
this->command(0x91);
|
|
|
|
// Partial Window (PTL)
|
|
// We use the full screen as the window
|
|
this->command(0x90);
|
|
|
|
// Horizontal start/end channel bank (HRST/HRED)
|
|
this->data(0);
|
|
this->data(0);
|
|
this->data((get_width_internal() - 1) / 256);
|
|
this->data((get_width_internal() - 1) % 256);
|
|
|
|
// Vertical start/end line (VRST/VRED)
|
|
this->data(0);
|
|
this->data(0);
|
|
this->data((get_height_internal() - 1) / 256);
|
|
this->data((get_height_internal() - 1) % 256);
|
|
|
|
this->data(0x01);
|
|
|
|
// Display Start Transmission 1 (DTM1)
|
|
// in KW mode this writes "OLD" data to SRAM
|
|
this->command(0x10);
|
|
this->start_data_();
|
|
this->write_array(this->old_buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
}
|
|
|
|
// Display Start Transmission 2 (DTM2)
|
|
// in KW mode this writes "NEW" data to SRAM
|
|
this->command(0x13);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
this->old_buffer_[i] = this->buffer_[i];
|
|
}
|
|
|
|
// Display Refresh (DRF)
|
|
this->command(0x12);
|
|
delay(10);
|
|
this->wait_until_idle_();
|
|
|
|
if (full_update) {
|
|
ESP_LOGD(TAG, "Full update done");
|
|
} else {
|
|
// Partial out (PTOUT), makes the display exit partial mode
|
|
this->command(0x92);
|
|
ESP_LOGD(TAG, "Partial update done, next full update after %" PRIu32 " cycles",
|
|
this->full_update_every_ - this->at_update_ - 1);
|
|
}
|
|
|
|
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
|
|
|
this->deep_sleep();
|
|
}
|
|
|
|
void GDEY0583T81::set_full_update_every(uint32_t full_update_every) { this->full_update_every_ = full_update_every; }
|
|
int GDEY0583T81::get_width_internal() { return 648; }
|
|
int GDEY0583T81::get_height_internal() { return 480; }
|
|
uint32_t GDEY0583T81::idle_timeout_() { return 5000; }
|
|
void GDEY0583T81::dump_config() {
|
|
LOG_DISPLAY("", "GoodDisplay E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 5.83in B/W GDEY0583T81");
|
|
ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper7P5InBV2::initialize() {
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x07);
|
|
this->data(0x07); // VGH=20V,VGL=-20V
|
|
this->data(0x3f); // VDH=15V
|
|
this->data(0x3f); // VDL=-15V
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x0F); // KW3f, KWR-2F, BWROTP 0f, BWOTP 1f
|
|
this->command(0x61); // tres
|
|
this->data(0x03); // 800px
|
|
this->data(0x20);
|
|
this->data(0x01); // 400px
|
|
this->data(0xE0);
|
|
this->command(0x15);
|
|
this->data(0x00);
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x11);
|
|
this->data(0x07);
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
|
|
this->command(0x82);
|
|
this->data(0x08);
|
|
this->command(0x30);
|
|
this->data(0x06);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x65);
|
|
this->data(0x00);
|
|
this->data(0x00); // 800*480
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
}
|
|
void HOT WaveshareEPaper7P5InBV2::display() {
|
|
// COMMAND DATA START TRANSMISSION 1 (B/W data)
|
|
this->command(0x10);
|
|
delay(2);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DATA START TRANSMISSION 2 (RED data)
|
|
this->command(0x13);
|
|
delay(2);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++)
|
|
this->write_byte(0x00);
|
|
this->end_data_();
|
|
delay(2);
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
this->deep_sleep();
|
|
}
|
|
int WaveshareEPaper7P5InBV2::get_width_internal() { return 800; }
|
|
int WaveshareEPaper7P5InBV2::get_height_internal() { return 480; }
|
|
void WaveshareEPaper7P5InBV2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5in-bv2");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper7P5InBV3::initialize() { this->init_display_(); }
|
|
bool WaveshareEPaper7P5InBV3::wait_until_idle_() {
|
|
if (this->busy_pin_ == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t start = millis();
|
|
while (this->busy_pin_->digital_read()) {
|
|
this->command(0x71);
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGI(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
App.feed_wdt();
|
|
delay(10);
|
|
}
|
|
delay(200); // NOLINT
|
|
return true;
|
|
};
|
|
void WaveshareEPaper7P5InBV3::init_display_() {
|
|
this->reset_();
|
|
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
|
|
// 1-0=11: internal power
|
|
this->data(0x07);
|
|
this->data(0x17); // VGH&VGL
|
|
this->data(0x3F); // VSH
|
|
this->data(0x26); // VSL
|
|
this->data(0x11); // VSHR
|
|
|
|
// VCOM DC Setting
|
|
this->command(0x82);
|
|
this->data(0x24); // VCOM
|
|
|
|
// Booster Setting
|
|
this->command(0x06);
|
|
this->data(0x27);
|
|
this->data(0x27);
|
|
this->data(0x2F);
|
|
this->data(0x17);
|
|
|
|
// POWER ON
|
|
this->command(0x04);
|
|
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x3F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x03); // source 800
|
|
this->data(0x20);
|
|
this->data(0x01); // gate 480
|
|
this->data(0xE0);
|
|
// COMMAND ...?
|
|
this->command(0x15);
|
|
this->data(0x00);
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x10);
|
|
this->data(0x00);
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
// Resolution setting
|
|
this->command(0x65);
|
|
this->data(0x00);
|
|
this->data(0x00); // 800*480
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
uint8_t lut_vcom_7_i_n5_v2[] = {
|
|
0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_ww_7_i_n5_v2[] = {
|
|
0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_bw_7_i_n5_v2[] = {
|
|
0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_wb_7_i_n5_v2[] = {
|
|
0x80, 0xF, 0xF, 0x0, 0x0, 0x3, 0x84, 0xF, 0x1, 0xF, 0x1, 0x4, 0x40, 0xF, 0xF, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_bb_7_i_n5_v2[] = {
|
|
0x80, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t count;
|
|
this->command(0x20); // VCOM
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_vcom_7_i_n5_v2[count]);
|
|
|
|
this->command(0x21); // LUTBW
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_ww_7_i_n5_v2[count]);
|
|
|
|
this->command(0x22); // LUTBW
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_bw_7_i_n5_v2[count]);
|
|
|
|
this->command(0x23); // LUTWB
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_wb_7_i_n5_v2[count]);
|
|
|
|
this->command(0x24); // LUTBB
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_bb_7_i_n5_v2[count]);
|
|
};
|
|
void HOT WaveshareEPaper7P5InBV3::display() {
|
|
this->init_display_();
|
|
uint32_t buf_len = this->get_buffer_length_();
|
|
|
|
this->command(0x10);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(0xFF);
|
|
}
|
|
|
|
this->command(0x13); // Start Transmission
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(~this->buffer_[i]);
|
|
}
|
|
|
|
this->command(0x12); // Display Refresh
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
this->deep_sleep();
|
|
}
|
|
int WaveshareEPaper7P5InBV3::get_width_internal() { return 800; }
|
|
int WaveshareEPaper7P5InBV3::get_height_internal() { return 480; }
|
|
void WaveshareEPaper7P5InBV3::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper7P5InBV3BWR::initialize() { this->init_display_(); }
|
|
bool WaveshareEPaper7P5InBV3BWR::wait_until_idle_() {
|
|
if (this->busy_pin_ == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t start = millis();
|
|
while (this->busy_pin_->digital_read()) {
|
|
this->command(0x71);
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGI(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
App.feed_wdt();
|
|
delay(10);
|
|
}
|
|
delay(200); // NOLINT
|
|
return true;
|
|
};
|
|
void WaveshareEPaper7P5InBV3BWR::init_display_() {
|
|
this->reset_();
|
|
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
|
|
// 1-0=11: internal power
|
|
this->data(0x07); // VRS_EN=1, VS_EN=1, VG_EN=1
|
|
this->data(0x17); // VGH&VGL ??? VCOM_SLEW=1 but this is fixed, VG_LVL[2:0]=111 => VGH=20V VGL=-20V, it could be 0x07
|
|
this->data(0x3F); // VSH=15V?
|
|
this->data(0x26); // VSL=-9.4V?
|
|
this->data(0x11); // VSHR=5.8V?
|
|
|
|
// VCOM DC Setting
|
|
this->command(0x82);
|
|
this->data(0x24); // VCOM=-1.9V
|
|
|
|
// POWER ON
|
|
this->command(0x04);
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x0F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x03); // source 800
|
|
this->data(0x20);
|
|
this->data(0x01); // gate 480
|
|
this->data(0xE0);
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x20);
|
|
this->data(0x00);
|
|
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
|
|
// Resolution setting
|
|
this->command(0x65);
|
|
this->data(0x00);
|
|
this->data(0x00); // 800*480
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
};
|
|
void HOT WaveshareEPaper7P5InBV3BWR::display() {
|
|
this->init_display_();
|
|
const uint32_t buf_len = this->get_buffer_length_() / 2u;
|
|
|
|
this->command(0x10); // Send BW data Transmission
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
|
|
this->command(0x13); // Send red data Transmission
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i + buf_len]);
|
|
}
|
|
|
|
this->command(0x12); // Display Refresh
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
this->deep_sleep();
|
|
}
|
|
int WaveshareEPaper7P5InBV3BWR::get_width_internal() { return 800; }
|
|
int WaveshareEPaper7P5InBV3BWR::get_height_internal() { return 480; }
|
|
void WaveshareEPaper7P5InBV3BWR::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5in-bv3 BWR-Mode");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper7P5In::initialize() {
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x37);
|
|
this->data(0x00);
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0xCF);
|
|
this->data(0x0B);
|
|
// COMMAND BOOSTER SOFT START
|
|
this->command(0x06);
|
|
this->data(0xC7);
|
|
this->data(0xCC);
|
|
this->data(0x28);
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
delay(10);
|
|
// COMMAND PLL CONTROL
|
|
this->command(0x30);
|
|
this->data(0x3C);
|
|
// COMMAND TEMPERATURE SENSOR CALIBRATION
|
|
this->command(0x41);
|
|
this->data(0x00);
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x77);
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x02);
|
|
this->data(0x80);
|
|
this->data(0x01);
|
|
this->data(0x80);
|
|
// COMMAND VCM DC SETTING REGISTER
|
|
this->command(0x82);
|
|
this->data(0x1E);
|
|
this->command(0xE5);
|
|
this->data(0x03);
|
|
}
|
|
void HOT WaveshareEPaper7P5In::display() {
|
|
// COMMAND DATA START TRANSMISSION 1
|
|
this->command(0x10);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
uint8_t temp1 = this->buffer_[i];
|
|
for (uint8_t j = 0; j < 8; j++) {
|
|
uint8_t temp2;
|
|
if (temp1 & 0x80) {
|
|
temp2 = 0x03;
|
|
} else {
|
|
temp2 = 0x00;
|
|
}
|
|
temp2 <<= 4;
|
|
temp1 <<= 1;
|
|
j++;
|
|
if (temp1 & 0x80) {
|
|
temp2 |= 0x03;
|
|
} else {
|
|
temp2 |= 0x00;
|
|
}
|
|
temp1 <<= 1;
|
|
this->write_byte(temp2);
|
|
}
|
|
App.feed_wdt();
|
|
}
|
|
this->end_data_();
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
}
|
|
int WaveshareEPaper7P5In::get_width_internal() { return 640; }
|
|
int WaveshareEPaper7P5In::get_height_internal() { return 384; }
|
|
void WaveshareEPaper7P5In::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5in");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
// Waveshare 5.65F ========================================================
|
|
|
|
namespace cmddata_5P65InF {
|
|
// WaveshareEPaper5P65InF commands
|
|
// https://www.waveshare.com/wiki/5.65inch_e-Paper_Module_(F)
|
|
|
|
// R00H (PSR): Panel setting Register
|
|
// UD(1): scan up
|
|
// SHL(1) shift right
|
|
// SHD_N(1) DC-DC on
|
|
// RST_N(1) no reset
|
|
static const uint8_t R00_CMD_PSR[] = {0x00, 0xEF, 0x08};
|
|
|
|
// R01H (PWR): Power setting Register
|
|
// internal DC-DC power generation
|
|
static const uint8_t R01_CMD_PWR[] = {0x01, 0x07, 0x00, 0x00, 0x00};
|
|
|
|
// R02H (POF): Power OFF Command
|
|
static const uint8_t R02_CMD_POF[] = {0x02};
|
|
|
|
// R03H (PFS): Power off sequence setting Register
|
|
// T_VDS_OFF (00) = 1 frame
|
|
static const uint8_t R03_CMD_PFS[] = {0x03, 0x00};
|
|
|
|
// R04H (PON): Power ON Command
|
|
static const uint8_t R04_CMD_PON[] = {0x04};
|
|
|
|
// R06h (BTST): Booster Soft Start
|
|
static const uint8_t R06_CMD_BTST[] = {0x06, 0xC7, 0xC7, 0x1D};
|
|
|
|
// R07H (DSLP): Deep sleep#
|
|
// Note Documentation @ Waveshare shows cmd code as 0x10 in table, but
|
|
// 0x10 is DTM1.
|
|
static const uint8_t R07_CMD_DSLP[] = {0x07, 0xA5};
|
|
|
|
// R10H (DTM1): Data Start Transmission 1
|
|
|
|
static const uint8_t R10_CMD_DTM1[] = {0x10};
|
|
|
|
// R11H (DSP): Data Stop
|
|
static const uint8_t R11_CMD_DSP[] = {0x11};
|
|
|
|
// R12H (DRF): Display Refresh
|
|
static const uint8_t R12_CMD_DRF[] = {0x12};
|
|
|
|
// R13H (IPC): Image Process Command
|
|
static const uint8_t R13_CMD_IPC[] = {0x13, 0x00};
|
|
|
|
// R30H (PLL): PLL Control
|
|
// 0x3C = 50Hz
|
|
static const uint8_t R30_CMD_PLL[] = {0x30, 0x3C};
|
|
|
|
// R41H (TSE): Temperature Sensor Enable
|
|
// TSE(0) enable, TO(0000) +0 degree offset
|
|
static const uint8_t R41_CMD_TSE[] = {0x41, 0x00};
|
|
|
|
// R50H (CDI) VCOM and Data interval setting
|
|
// CDI(0111) 10
|
|
// DDX(1), VBD(001) Border output "White"
|
|
static const uint8_t R50_CMD_CDI[] = {0x50, 0x37};
|
|
|
|
// R60H (TCON) Gate and Source non overlap period command
|
|
// S2G(10) 12 units
|
|
// G2S(10) 12 units
|
|
static const uint8_t R60_CMD_TCON[] = {0x60, 0x22};
|
|
|
|
// R61H (TRES) Resolution Setting
|
|
// 0x258 = 600
|
|
// 0x1C0 = 448
|
|
static const uint8_t R61_CMD_TRES[] = {0x61, 0x02, 0x58, 0x01, 0xC0};
|
|
|
|
// RE3H (PWS) Power Savings
|
|
static const uint8_t RE3_CMD_PWS[] = {0xE3, 0xAA};
|
|
} // namespace cmddata_5P65InF
|
|
|
|
void WaveshareEPaper5P65InF::initialize() {
|
|
if (this->buffers_[0] == nullptr) {
|
|
ESP_LOGE(TAG, "Buffer unavailable!");
|
|
return;
|
|
}
|
|
|
|
this->reset_();
|
|
delay(20);
|
|
this->wait_until_(IDLE);
|
|
|
|
using namespace cmddata_5P65InF;
|
|
|
|
this->cmd_data(R00_CMD_PSR, sizeof(R00_CMD_PSR));
|
|
this->cmd_data(R01_CMD_PWR, sizeof(R01_CMD_PWR));
|
|
this->cmd_data(R03_CMD_PFS, sizeof(R03_CMD_PFS));
|
|
this->cmd_data(R06_CMD_BTST, sizeof(R06_CMD_BTST));
|
|
this->cmd_data(R30_CMD_PLL, sizeof(R30_CMD_PLL));
|
|
this->cmd_data(R41_CMD_TSE, sizeof(R41_CMD_TSE));
|
|
this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
|
|
this->cmd_data(R60_CMD_TCON, sizeof(R60_CMD_TCON));
|
|
this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
|
|
this->cmd_data(RE3_CMD_PWS, sizeof(RE3_CMD_PWS));
|
|
|
|
delay(100); // NOLINT
|
|
this->cmd_data(R50_CMD_CDI, sizeof(R50_CMD_CDI));
|
|
|
|
ESP_LOGI(TAG, "Display initialized successfully");
|
|
}
|
|
|
|
void HOT WaveshareEPaper5P65InF::display() {
|
|
// INITIALIZATION
|
|
ESP_LOGI(TAG, "Initialise the display");
|
|
this->initialize();
|
|
|
|
using namespace cmddata_5P65InF;
|
|
|
|
// COMMAND DATA START TRANSMISSION
|
|
ESP_LOGI(TAG, "Sending data to the display");
|
|
this->cmd_data(R61_CMD_TRES, sizeof(R61_CMD_TRES));
|
|
this->cmd_data(R10_CMD_DTM1, sizeof(R10_CMD_DTM1));
|
|
this->send_buffers_();
|
|
|
|
// COMMAND POWER ON
|
|
ESP_LOGI(TAG, "Power on the display");
|
|
this->cmd_data(R04_CMD_PON, sizeof(R04_CMD_PON));
|
|
this->wait_until_(IDLE);
|
|
|
|
// COMMAND REFRESH SCREEN
|
|
ESP_LOGI(TAG, "Refresh the display");
|
|
this->cmd_data(R12_CMD_DRF, sizeof(R12_CMD_DRF));
|
|
this->wait_until_(IDLE);
|
|
|
|
// COMMAND POWER OFF
|
|
ESP_LOGI(TAG, "Power off the display");
|
|
this->cmd_data(R02_CMD_POF, sizeof(R02_CMD_POF));
|
|
this->wait_until_(BUSY);
|
|
|
|
if (this->deep_sleep_between_updates_) {
|
|
ESP_LOGI(TAG, "Set the display to deep sleep");
|
|
this->cmd_data(R07_CMD_DSLP, sizeof(R07_CMD_DSLP));
|
|
}
|
|
}
|
|
|
|
int WaveshareEPaper5P65InF::get_width_internal() { return 600; }
|
|
int WaveshareEPaper5P65InF::get_height_internal() { return 448; }
|
|
uint32_t WaveshareEPaper5P65InF::idle_timeout_() { return 35000; }
|
|
|
|
void WaveshareEPaper5P65InF::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 5.65in-F");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
bool WaveshareEPaper5P65InF::wait_until_(WaitForState busy_state) {
|
|
if (this->busy_pin_ == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t start = millis();
|
|
while (busy_state != this->busy_pin_->digital_read()) {
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGE(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
App.feed_wdt();
|
|
delay(10);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void WaveshareEPaper7P3InF::initialize() {
|
|
if (this->buffers_[0] == nullptr) {
|
|
ESP_LOGE(TAG, "Buffer unavailable!");
|
|
return;
|
|
}
|
|
|
|
this->reset_();
|
|
delay(20);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND CMDH
|
|
this->command(0xAA);
|
|
this->data(0x49);
|
|
this->data(0x55);
|
|
this->data(0x20);
|
|
this->data(0x08);
|
|
this->data(0x09);
|
|
this->data(0x18);
|
|
|
|
this->command(0x01);
|
|
this->data(0x3F);
|
|
this->data(0x00);
|
|
this->data(0x32);
|
|
this->data(0x2A);
|
|
this->data(0x0E);
|
|
this->data(0x2A);
|
|
|
|
this->command(0x00);
|
|
this->data(0x5F);
|
|
this->data(0x69);
|
|
|
|
this->command(0x03);
|
|
this->data(0x00);
|
|
this->data(0x54);
|
|
this->data(0x00);
|
|
this->data(0x44);
|
|
|
|
this->command(0x05);
|
|
this->data(0x40);
|
|
this->data(0x1F);
|
|
this->data(0x1F);
|
|
this->data(0x2C);
|
|
|
|
this->command(0x06);
|
|
this->data(0x6F);
|
|
this->data(0x1F);
|
|
this->data(0x1F);
|
|
this->data(0x22);
|
|
|
|
this->command(0x08);
|
|
this->data(0x6F);
|
|
this->data(0x1F);
|
|
this->data(0x1F);
|
|
this->data(0x22);
|
|
|
|
// COMMAND IPC
|
|
this->command(0x13);
|
|
this->data(0x00);
|
|
this->data(0x04);
|
|
|
|
this->command(0x30);
|
|
this->data(0x3C);
|
|
|
|
// COMMAND TSE
|
|
this->command(0x41);
|
|
this->data(0x00);
|
|
|
|
this->command(0x50);
|
|
this->data(0x3F);
|
|
|
|
this->command(0x60);
|
|
this->data(0x02);
|
|
this->data(0x00);
|
|
|
|
this->command(0x61);
|
|
this->data(0x03);
|
|
this->data(0x20);
|
|
this->data(0x01);
|
|
this->data(0xE0);
|
|
|
|
this->command(0x82);
|
|
this->data(0x1E);
|
|
|
|
this->command(0x84);
|
|
this->data(0x00);
|
|
|
|
// COMMAND AGID
|
|
this->command(0x86);
|
|
this->data(0x00);
|
|
|
|
this->command(0xE3);
|
|
this->data(0x2F);
|
|
|
|
// COMMAND CCSET
|
|
this->command(0xE0);
|
|
this->data(0x00);
|
|
|
|
// COMMAND TSSET
|
|
this->command(0xE6);
|
|
this->data(0x00);
|
|
|
|
ESP_LOGI(TAG, "Display initialized successfully");
|
|
}
|
|
void HOT WaveshareEPaper7P3InF::display() {
|
|
// INITIALIZATION
|
|
ESP_LOGI(TAG, "Initialise the display");
|
|
this->initialize();
|
|
|
|
// COMMAND DATA START TRANSMISSION
|
|
ESP_LOGI(TAG, "Sending data to the display");
|
|
this->command(0x10);
|
|
this->send_buffers_();
|
|
|
|
// COMMAND POWER ON
|
|
ESP_LOGI(TAG, "Power on the display");
|
|
this->command(0x04);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND REFRESH SCREEN
|
|
ESP_LOGI(TAG, "Refresh the display");
|
|
this->command(0x12);
|
|
this->data(0x00);
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND POWER OFF
|
|
ESP_LOGI(TAG, "Power off the display");
|
|
this->command(0x02);
|
|
this->data(0x00);
|
|
this->wait_until_idle_();
|
|
|
|
if (this->deep_sleep_between_updates_) {
|
|
ESP_LOGI(TAG, "Set the display to deep sleep");
|
|
this->command(0x07);
|
|
this->data(0xA5);
|
|
}
|
|
}
|
|
int WaveshareEPaper7P3InF::get_width_internal() { return 800; }
|
|
int WaveshareEPaper7P3InF::get_height_internal() { return 480; }
|
|
uint32_t WaveshareEPaper7P3InF::idle_timeout_() { return 35000; }
|
|
void WaveshareEPaper7P3InF::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.3in-F");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
bool WaveshareEPaper7P3InF::wait_until_idle_() {
|
|
if (this->busy_pin_ == nullptr) {
|
|
return true;
|
|
}
|
|
const uint32_t start = millis();
|
|
while (this->busy_pin_->digital_read()) {
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGE(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
App.feed_wdt();
|
|
delay(10);
|
|
}
|
|
delay(200); // NOLINT
|
|
return true;
|
|
}
|
|
bool WaveshareEPaper7P5InV2::wait_until_idle_() {
|
|
if (this->busy_pin_ == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t start = millis();
|
|
while (this->busy_pin_->digital_read()) {
|
|
this->command(0x71);
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGE(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
App.feed_wdt();
|
|
delay(10);
|
|
}
|
|
return true;
|
|
}
|
|
void WaveshareEPaper7P5InV2::initialize() {
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x07);
|
|
this->data(0x07);
|
|
this->data(0x3f);
|
|
this->data(0x3f);
|
|
|
|
// We don't want the display to be powered at this point
|
|
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x10);
|
|
this->data(0x07);
|
|
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x1F);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x03);
|
|
this->data(0x20);
|
|
this->data(0x01);
|
|
this->data(0xE0);
|
|
|
|
// COMMAND DUAL SPI MM_EN, DUSPI_EN
|
|
this->command(0x15);
|
|
this->data(0x00);
|
|
|
|
// COMMAND POWER DRIVER HAT DOWN
|
|
// This command will turn off booster, controller, source driver, gate driver, VCOM, and
|
|
// temperature sensor, but register data will be kept until VDD turned OFF or Deep Sleep Mode.
|
|
// Source/Gate/Border/VCOM will be released to floating.
|
|
this->command(0x02);
|
|
}
|
|
void HOT WaveshareEPaper7P5InV2::display() {
|
|
uint32_t buf_len = this->get_buffer_length_();
|
|
|
|
// COMMAND POWER ON
|
|
ESP_LOGI(TAG, "Power on the display and hat");
|
|
|
|
// This command will turn on booster, controller, regulators, and temperature sensor will be
|
|
// activated for one-time sensing before enabling booster. When all voltages are ready, the
|
|
// BUSY_N signal will return to high.
|
|
this->command(0x04);
|
|
delay(200); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND DATA START TRANSMISSION NEW DATA
|
|
this->command(0x13);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(~(this->buffer_[i]));
|
|
}
|
|
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
ESP_LOGV(TAG, "Before command(0x02) (>> power off)");
|
|
this->command(0x02);
|
|
this->wait_until_idle_();
|
|
ESP_LOGV(TAG, "After command(0x02) (>> power off)");
|
|
}
|
|
|
|
int WaveshareEPaper7P5InV2::get_width_internal() { return 800; }
|
|
int WaveshareEPaper7P5InV2::get_height_internal() { return 480; }
|
|
uint32_t WaveshareEPaper7P5InV2::idle_timeout_() { return 10000; }
|
|
void WaveshareEPaper7P5InV2::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5inV2rev2");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
/* 7.50inV2alt */
|
|
bool WaveshareEPaper7P5InV2alt::wait_until_idle_() {
|
|
if (this->busy_pin_ == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t start = millis();
|
|
while (this->busy_pin_->digital_read()) {
|
|
this->command(0x71);
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGI(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
delay(10);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void WaveshareEPaper7P5InV2alt::initialize() {
|
|
this->reset_();
|
|
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
|
|
// 1-0=11: internal power
|
|
this->data(0x07);
|
|
this->data(0x17); // VGH&VGL
|
|
this->data(0x3F); // VSH
|
|
this->data(0x26); // VSL
|
|
this->data(0x11); // VSHR
|
|
|
|
// VCOM DC Setting
|
|
this->command(0x82);
|
|
this->data(0x24); // VCOM
|
|
|
|
// Booster Setting
|
|
this->command(0x06);
|
|
this->data(0x27);
|
|
this->data(0x27);
|
|
this->data(0x2F);
|
|
this->data(0x17);
|
|
|
|
// POWER ON
|
|
this->command(0x04);
|
|
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x3F); // KW-3f KWR-2F BWROTP 0f BWOTP 1f
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x03); // source 800
|
|
this->data(0x20);
|
|
this->data(0x01); // gate 480
|
|
this->data(0xE0);
|
|
// COMMAND ...?
|
|
this->command(0x15);
|
|
this->data(0x00);
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x10);
|
|
this->data(0x00);
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
// Resolution setting
|
|
this->command(0x65);
|
|
this->data(0x00);
|
|
this->data(0x00); // 800*480
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
this->wait_until_idle_();
|
|
|
|
uint8_t lut_vcom_7_i_n5_v2[] = {
|
|
0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0xF, 0x1, 0xF, 0x1, 0x2, 0x0, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_ww_7_i_n5_v2[] = {
|
|
0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_bw_7_i_n5_v2[] = {
|
|
0x10, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x20, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_wb_7_i_n5_v2[] = {
|
|
0x80, 0xF, 0xF, 0x0, 0x0, 0x3, 0x84, 0xF, 0x1, 0xF, 0x1, 0x4, 0x40, 0xF, 0xF, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t lut_bb_7_i_n5_v2[] = {
|
|
0x80, 0xF, 0xF, 0x0, 0x0, 0x1, 0x84, 0xF, 0x1, 0xF, 0x1, 0x2, 0x40, 0xF, 0xF, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
};
|
|
|
|
uint8_t count;
|
|
this->command(0x20); // VCOM
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_vcom_7_i_n5_v2[count]);
|
|
|
|
this->command(0x21); // LUTBW
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_ww_7_i_n5_v2[count]);
|
|
|
|
this->command(0x22); // LUTBW
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_bw_7_i_n5_v2[count]);
|
|
|
|
this->command(0x23); // LUTWB
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_wb_7_i_n5_v2[count]);
|
|
|
|
this->command(0x24); // LUTBB
|
|
for (count = 0; count < 42; count++)
|
|
this->data(lut_bb_7_i_n5_v2[count]);
|
|
}
|
|
|
|
void WaveshareEPaper7P5InV2alt::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5inV2");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
/* 7.50inV2 with partial and fast refresh */
|
|
bool WaveshareEPaper7P5InV2P::wait_until_idle_() {
|
|
if (this->busy_pin_ == nullptr) {
|
|
return true;
|
|
}
|
|
|
|
const uint32_t start = millis();
|
|
while (this->busy_pin_->digital_read()) {
|
|
this->command(0x71);
|
|
if (millis() - start > this->idle_timeout_()) {
|
|
ESP_LOGE(TAG, "Timeout while displaying image!");
|
|
return false;
|
|
}
|
|
App.feed_wdt();
|
|
delay(10);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void WaveshareEPaper7P5InV2P::reset_() {
|
|
if (this->reset_pin_ != nullptr) {
|
|
this->reset_pin_->digital_write(true);
|
|
delay(20);
|
|
this->reset_pin_->digital_write(false);
|
|
delay(2);
|
|
this->reset_pin_->digital_write(true);
|
|
delay(20);
|
|
}
|
|
}
|
|
|
|
void WaveshareEPaper7P5InV2P::turn_on_display_() {
|
|
this->command(0x12);
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
}
|
|
|
|
void WaveshareEPaper7P5InV2P::initialize() {
|
|
this->reset_();
|
|
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x07);
|
|
this->data(0x07);
|
|
this->data(0x3f);
|
|
this->data(0x3f);
|
|
|
|
// COMMAND BOOSTER SOFT START
|
|
this->command(0x06);
|
|
this->data(0x17);
|
|
this->data(0x17);
|
|
this->data(0x28);
|
|
this->data(0x17);
|
|
|
|
// COMMAND POWER DRIVER HAT UP
|
|
this->command(0x04);
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0x1F);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x03);
|
|
this->data(0x20);
|
|
this->data(0x01);
|
|
this->data(0xE0);
|
|
|
|
// COMMAND DUAL SPI MM_EN, DUSPI_EN
|
|
this->command(0x15);
|
|
this->data(0x00);
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x10);
|
|
this->data(0x07);
|
|
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
|
|
// COMMAND ENABLE FAST UPDATE
|
|
this->command(0xE0);
|
|
this->data(0x02);
|
|
this->command(0xE5);
|
|
this->data(0x5A);
|
|
|
|
// COMMAND POWER DRIVER HAT DOWN
|
|
this->command(0x02);
|
|
}
|
|
|
|
void HOT WaveshareEPaper7P5InV2P::display() {
|
|
uint32_t buf_len = this->get_buffer_length_();
|
|
|
|
// COMMAND POWER ON
|
|
ESP_LOGI(TAG, "Power on the display and hat");
|
|
|
|
this->command(0x04);
|
|
delay(200); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
if (this->full_update_every_ == 1) {
|
|
this->command(0x13);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(~(this->buffer_[i]));
|
|
}
|
|
|
|
this->turn_on_display_();
|
|
|
|
this->command(0x02);
|
|
this->wait_until_idle_();
|
|
return;
|
|
}
|
|
|
|
this->command(0x50);
|
|
this->data(0xA9);
|
|
this->data(0x07);
|
|
|
|
if (this->at_update_ == 0) {
|
|
// Enable fast refresh
|
|
this->command(0xE5);
|
|
this->data(0x5A);
|
|
|
|
this->command(0x92);
|
|
|
|
this->command(0x10);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(~(this->buffer_[i]));
|
|
}
|
|
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x13);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
this->turn_on_display_();
|
|
|
|
} else {
|
|
// Enable partial refresh
|
|
this->command(0xE5);
|
|
this->data(0x6E);
|
|
|
|
// Activate partial refresh and set window bounds
|
|
this->command(0x91);
|
|
this->command(0x90);
|
|
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data((get_width_internal() - 1) >> 8 & 0xFF);
|
|
this->data((get_width_internal() - 1) & 0xFF);
|
|
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data((get_height_internal() - 1) >> 8 & 0xFF);
|
|
this->data((get_height_internal() - 1) & 0xFF);
|
|
|
|
this->data(0x01);
|
|
|
|
this->command(0x13);
|
|
delay(2);
|
|
for (uint32_t i = 0; i < buf_len; i++) {
|
|
this->data(this->buffer_[i]);
|
|
}
|
|
|
|
delay(100); // NOLINT
|
|
this->wait_until_idle_();
|
|
|
|
this->turn_on_display_();
|
|
}
|
|
|
|
ESP_LOGV(TAG, "Before command(0x02) (>> power off)");
|
|
this->command(0x02);
|
|
this->wait_until_idle_();
|
|
ESP_LOGV(TAG, "After command(0x02) (>> power off)");
|
|
|
|
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
|
}
|
|
|
|
int WaveshareEPaper7P5InV2P::get_width_internal() { return 800; }
|
|
int WaveshareEPaper7P5InV2P::get_height_internal() { return 480; }
|
|
uint32_t WaveshareEPaper7P5InV2P::idle_timeout_() { return 10000; }
|
|
void WaveshareEPaper7P5InV2P::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.50inv2p");
|
|
ESP_LOGCONFIG(TAG, " Full Update Every: %" PRIu32, this->full_update_every_);
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
void WaveshareEPaper7P5InV2P::set_full_update_every(uint32_t full_update_every) {
|
|
this->full_update_every_ = full_update_every;
|
|
}
|
|
|
|
/* 7.50in-bc */
|
|
void WaveshareEPaper7P5InBC::initialize() {
|
|
/* The command sequence is similar to the 7P5In display but differs in subtle ways
|
|
to allow for faster updates. */
|
|
// COMMAND POWER SETTING
|
|
this->command(0x01);
|
|
this->data(0x37);
|
|
this->data(0x00);
|
|
|
|
// COMMAND PANEL SETTING
|
|
this->command(0x00);
|
|
this->data(0xCF);
|
|
this->data(0x08);
|
|
|
|
// COMMAND PLL CONTROL
|
|
this->command(0x30);
|
|
this->data(0x3A);
|
|
|
|
// COMMAND VCM_DC_SETTING: all temperature range
|
|
this->command(0x82);
|
|
this->data(0x28);
|
|
|
|
// COMMAND BOOSTER SOFT START
|
|
this->command(0x06);
|
|
this->data(0xC7);
|
|
this->data(0xCC);
|
|
this->data(0x15);
|
|
|
|
// COMMAND VCOM AND DATA INTERVAL SETTING
|
|
this->command(0x50);
|
|
this->data(0x77);
|
|
|
|
// COMMAND TCON SETTING
|
|
this->command(0x60);
|
|
this->data(0x22);
|
|
|
|
// COMMAND FLASH CONTROL
|
|
this->command(0x65);
|
|
this->data(0x00);
|
|
|
|
// COMMAND RESOLUTION SETTING
|
|
this->command(0x61);
|
|
this->data(0x02); // 640 >> 8
|
|
this->data(0x80);
|
|
this->data(0x01); // 384 >> 8
|
|
this->data(0x80);
|
|
|
|
// COMMAND FLASH MODE
|
|
this->command(0xE5);
|
|
this->data(0x03);
|
|
}
|
|
|
|
void HOT WaveshareEPaper7P5InBC::display() {
|
|
// COMMAND DATA START TRANSMISSION 1
|
|
this->command(0x10);
|
|
this->start_data_();
|
|
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++) {
|
|
// A line of eight source pixels (each a bit in this byte)
|
|
uint8_t eight_pixels = this->buffer_[i];
|
|
|
|
for (uint8_t j = 0; j < 8; j += 2) {
|
|
/* For bichromatic displays, each byte represents two pixels. Each nibble encodes a pixel: 0=white, 3=black,
|
|
4=color. Therefore, e.g. 0x44 = two adjacent color pixels, 0x33 is two adjacent black pixels, etc. If you want
|
|
to draw using the color pixels, change '0x30' with '0x40' and '0x03' with '0x04' below. */
|
|
uint8_t left_nibble = (eight_pixels & 0x80) ? 0x30 : 0x00;
|
|
eight_pixels <<= 1;
|
|
uint8_t right_nibble = (eight_pixels & 0x80) ? 0x03 : 0x00;
|
|
eight_pixels <<= 1;
|
|
this->write_byte(left_nibble | right_nibble);
|
|
}
|
|
App.feed_wdt();
|
|
}
|
|
this->end_data_();
|
|
|
|
// Unlike the 7P5In display, we send the "power on" command here rather than during initialization
|
|
// COMMAND POWER ON
|
|
this->command(0x04);
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x12);
|
|
}
|
|
|
|
int WaveshareEPaper7P5InBC::get_width_internal() { return 640; }
|
|
|
|
int WaveshareEPaper7P5InBC::get_height_internal() { return 384; }
|
|
|
|
void WaveshareEPaper7P5InBC::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5in-bc");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper7P5InHDB::initialize() {
|
|
this->command(0x12); // SWRESET
|
|
|
|
this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
|
|
|
|
this->command(0x46); // Auto Write RAM
|
|
this->data(0xF7);
|
|
|
|
this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
|
|
|
|
this->command(0x47); // Auto Write RAM
|
|
this->data(0xF7);
|
|
|
|
this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
|
|
|
|
this->command(0x0C); // Soft start setting
|
|
this->data(0xAE);
|
|
this->data(0xC7);
|
|
this->data(0xC3);
|
|
this->data(0xC0);
|
|
this->data(0x40);
|
|
|
|
this->command(0x01); // Set MUX as 527
|
|
this->data(0xAF);
|
|
this->data(0x02);
|
|
this->data(0x01);
|
|
|
|
this->command(0x11); // Data entry mode
|
|
this->data(0x01);
|
|
|
|
this->command(0x44);
|
|
this->data(0x00); // RAM x address start at 0
|
|
this->data(0x00);
|
|
this->data(0x6F); // RAM x address end at 36Fh -> 879
|
|
this->data(0x03);
|
|
|
|
this->command(0x45);
|
|
this->data(0xAF); // RAM y address start at 20Fh;
|
|
this->data(0x02);
|
|
this->data(0x00); // RAM y address end at 00h;
|
|
this->data(0x00);
|
|
|
|
this->command(0x3C); // VBD
|
|
this->data(0x01); // LUT1, for white
|
|
|
|
this->command(0x18);
|
|
this->data(0x80);
|
|
|
|
this->command(0x22);
|
|
this->data(0xB1); // Load Temperature and waveform setting.
|
|
|
|
this->command(0x20);
|
|
|
|
this->wait_until_idle_(); // waiting for the electronic paper IC to release the idle signal
|
|
|
|
this->command(0x4E);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
this->command(0x4F);
|
|
this->data(0xAF);
|
|
this->data(0x02);
|
|
}
|
|
|
|
void HOT WaveshareEPaper7P5InHDB::display() {
|
|
this->command(0x4F);
|
|
this->data(0xAf);
|
|
this->data(0x02);
|
|
|
|
// BLACK
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// RED
|
|
this->command(0x26);
|
|
this->start_data_();
|
|
for (size_t i = 0; i < this->get_buffer_length_(); i++)
|
|
this->write_byte(0x00);
|
|
this->end_data_();
|
|
|
|
this->command(0x22);
|
|
this->data(0xC7);
|
|
this->command(0x20);
|
|
delay(100); // NOLINT
|
|
}
|
|
|
|
int WaveshareEPaper7P5InHDB::get_width_internal() { return 880; }
|
|
|
|
int WaveshareEPaper7P5InHDB::get_height_internal() { return 528; }
|
|
|
|
void WaveshareEPaper7P5InHDB::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 7.5in-HD-b");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
static const uint8_t LUT_SIZE_TTGO_DKE_PART = 153;
|
|
|
|
static const uint8_t PART_UPDATE_LUT_TTGO_DKE[LUT_SIZE_TTGO_DKE_PART] = {
|
|
0x0, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0xF, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0, 0x0, 0x0, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
|
|
// 0x22, 0x17, 0x41, 0x0, 0x32, 0x32
|
|
};
|
|
|
|
void WaveshareEPaper2P13InDKE::initialize() {}
|
|
void HOT WaveshareEPaper2P13InDKE::display() {
|
|
bool partial = this->at_update_ != 0;
|
|
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
|
|
|
if (partial) {
|
|
ESP_LOGI(TAG, "Performing partial e-paper update.");
|
|
} else {
|
|
ESP_LOGI(TAG, "Performing full e-paper update.");
|
|
}
|
|
|
|
// start and set up data format
|
|
this->command(0x12);
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x11);
|
|
this->data(0x03);
|
|
this->command(0x44);
|
|
this->data(1);
|
|
this->data(this->get_width_internal() / 8);
|
|
this->command(0x45);
|
|
this->data(0);
|
|
this->data(0);
|
|
this->data(this->get_height_internal());
|
|
this->data(0);
|
|
this->command(0x4e);
|
|
this->data(1);
|
|
this->command(0x4f);
|
|
this->data(0);
|
|
this->data(0);
|
|
|
|
if (!partial) {
|
|
// send data
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// commit
|
|
this->command(0x20);
|
|
this->wait_until_idle_();
|
|
} else {
|
|
// set up partial update
|
|
this->command(0x32);
|
|
this->start_data_();
|
|
this->write_array(PART_UPDATE_LUT_TTGO_DKE, sizeof(PART_UPDATE_LUT_TTGO_DKE));
|
|
this->end_data_();
|
|
this->command(0x3F);
|
|
this->data(0x22);
|
|
|
|
this->command(0x03);
|
|
this->data(0x17);
|
|
this->command(0x04);
|
|
this->data(0x41);
|
|
this->data(0x00);
|
|
this->data(0x32);
|
|
this->command(0x2C);
|
|
this->data(0x32);
|
|
|
|
this->command(0x37);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x40);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
this->data(0x00);
|
|
|
|
this->command(0x3C);
|
|
this->data(0x80);
|
|
this->command(0x22);
|
|
this->data(0xC0);
|
|
this->command(0x20);
|
|
this->wait_until_idle_();
|
|
|
|
// send data
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// commit as partial
|
|
this->command(0x22);
|
|
this->data(0xCF);
|
|
this->command(0x20);
|
|
this->wait_until_idle_();
|
|
|
|
// data must be sent again on partial update
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Completed e-paper update.");
|
|
}
|
|
|
|
int WaveshareEPaper2P13InDKE::get_width_internal() { return 128; }
|
|
int WaveshareEPaper2P13InDKE::get_height_internal() { return 250; }
|
|
uint32_t WaveshareEPaper2P13InDKE::idle_timeout_() { return 5000; }
|
|
void WaveshareEPaper2P13InDKE::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 2.13inDKE");
|
|
LOG_PIN(" CS Pin: ", this->cs_);
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
void WaveshareEPaper2P13InDKE::set_full_update_every(uint32_t full_update_every) {
|
|
this->full_update_every_ = full_update_every;
|
|
}
|
|
|
|
// ========================================================
|
|
// 13.3in (K version)
|
|
// Datasheet/Specification/Reference:
|
|
// - https://files.waveshare.com/wiki/13.3inch-e-Paper-HAT-(K)/13.3-inch-e-Paper-(K)-user-manual.pdf
|
|
// - https://github.com/waveshareteam/e-Paper/tree/master/Arduino/epd13in3k
|
|
// ========================================================
|
|
|
|
// using default wait_until_idle_() function
|
|
void WaveshareEPaper13P3InK::initialize() {
|
|
this->wait_until_idle_();
|
|
this->command(0x12); // SWRESET
|
|
this->wait_until_idle_();
|
|
|
|
this->command(0x0c); // set soft start
|
|
this->data(0xae);
|
|
this->data(0xc7);
|
|
this->data(0xc3);
|
|
this->data(0xc0);
|
|
this->data(0x80);
|
|
|
|
this->command(0x01); // driver output control
|
|
this->data((get_height_internal() - 1) % 256); // Y
|
|
this->data((get_height_internal() - 1) / 256); // Y
|
|
this->data(0x00);
|
|
|
|
this->command(0x11); // data entry mode
|
|
this->data(0x03);
|
|
|
|
// SET WINDOWS
|
|
// XRAM_START_AND_END_POSITION
|
|
this->command(0x44);
|
|
this->data(0 & 0xFF);
|
|
this->data((0 >> 8) & 0x03);
|
|
this->data((get_width_internal() - 1) & 0xFF);
|
|
this->data(((get_width_internal() - 1) >> 8) & 0x03);
|
|
// YRAM_START_AND_END_POSITION
|
|
this->command(0x45);
|
|
this->data(0 & 0xFF);
|
|
this->data((0 >> 8) & 0x03);
|
|
this->data((get_height_internal() - 1) & 0xFF);
|
|
this->data(((get_height_internal() - 1) >> 8) & 0x03);
|
|
|
|
this->command(0x3C); // Border setting
|
|
this->data(0x01);
|
|
|
|
this->command(0x18); // use the internal temperature sensor
|
|
this->data(0x80);
|
|
|
|
// SET CURSOR
|
|
// XRAM_ADDRESS
|
|
this->command(0x4E);
|
|
this->data(0 & 0xFF);
|
|
this->data((0 >> 8) & 0x03);
|
|
// YRAM_ADDRESS
|
|
this->command(0x4F);
|
|
this->data(0 & 0xFF);
|
|
this->data((0 >> 8) & 0x03);
|
|
}
|
|
void HOT WaveshareEPaper13P3InK::display() {
|
|
// do single full update
|
|
this->command(0x24);
|
|
this->start_data_();
|
|
this->write_array(this->buffer_, this->get_buffer_length_());
|
|
this->end_data_();
|
|
|
|
// COMMAND DISPLAY REFRESH
|
|
this->command(0x22);
|
|
this->data(0xF7);
|
|
this->command(0x20);
|
|
}
|
|
|
|
int WaveshareEPaper13P3InK::get_width_internal() { return 960; }
|
|
int WaveshareEPaper13P3InK::get_height_internal() { return 680; }
|
|
uint32_t WaveshareEPaper13P3InK::idle_timeout_() { return 10000; }
|
|
void WaveshareEPaper13P3InK::dump_config() {
|
|
LOG_DISPLAY("", "Waveshare E-Paper", this);
|
|
ESP_LOGCONFIG(TAG, " Model: 13.3inK");
|
|
LOG_PIN(" Reset Pin: ", this->reset_pin_);
|
|
LOG_PIN(" DC Pin: ", this->dc_pin_);
|
|
LOG_PIN(" Busy Pin: ", this->busy_pin_);
|
|
LOG_UPDATE_INTERVAL(this);
|
|
}
|
|
|
|
} // namespace waveshare_epaper
|
|
} // namespace esphome
|