From 0f736ff63d7b6d32f1856db407bca40893193892 Mon Sep 17 00:00:00 2001 From: Jonas Bergler Date: Thu, 15 Feb 2024 11:18:18 +1300 Subject: [PATCH 1/5] [waveshare_epaper] add support for 2.9" weact 3 color display --- .../components/waveshare_epaper/display.py | 4 + .../waveshare_epaper/waveshare_epaper.h | 29 +++ .../waveshare_epaper/weact_2p9in3c.cpp | 182 ++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 esphome/components/waveshare_epaper/weact_2p9in3c.cpp diff --git a/esphome/components/waveshare_epaper/display.py b/esphome/components/waveshare_epaper/display.py index fa7c104951..bd4acf8b31 100644 --- a/esphome/components/waveshare_epaper/display.py +++ b/esphome/components/waveshare_epaper/display.py @@ -85,6 +85,9 @@ WaveshareEPaper2P13InDKE = waveshare_epaper_ns.class_( WaveshareEPaper2P13InV3 = waveshare_epaper_ns.class_( "WaveshareEPaper2P13InV3", WaveshareEPaper ) +WeActEPaper2P9In3C = waveshare_epaper_ns.class_( + "WeActEPaper2P9In3C", WaveshareEPaperBWR +) GDEW0154M09 = waveshare_epaper_ns.class_("GDEW0154M09", WaveshareEPaper) WaveshareEPaperTypeAModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeAModel") @@ -100,6 +103,7 @@ MODELS = { "2.13in-ttgo-b74": ("a", WaveshareEPaperTypeAModel.TTGO_EPAPER_2_13_IN_B74), "2.90in": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN), "2.90inv2": ("a", WaveshareEPaperTypeAModel.WAVESHARE_EPAPER_2_9_IN_V2), + "2.90in3c": ("b", WeActEPaper2P9In3C), "gdey029t94": ("c", GDEY029T94), "2.70in": ("b", WaveshareEPaper2P7In), "2.70in-b": ("b", WaveshareEPaper2P7InB), diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 47f0cb27b6..2a0c615278 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -709,5 +709,34 @@ class WaveshareEPaper2P13InV3 : public WaveshareEPaper { bool is_busy_{false}; void write_lut_(const uint8_t *lut); }; + +class WeActEPaper2P9In3C : public WaveshareEPaperBWR { + public: + void display() override; + + void dump_config() override; + + void deep_sleep() override; + + void setup() override; + void initialize() override; + + protected: + int get_width_internal() override; + int get_height_internal() override; + void draw_absolute_pixel_internal(int x, int y, Color color) override; + + uint32_t idle_timeout_() override; + + void write_buffer_(int top, int bottom); + void set_window_(int t, int b); + void send_reset_(); + void partial_update_(); + void full_update_() ; + + uint32_t full_update_every_{0}; + uint32_t at_update_{0}; + bool is_busy_{false}; +}; } // namespace waveshare_epaper } // namespace esphome diff --git a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp new file mode 100644 index 0000000000..2d0d51e675 --- /dev/null +++ b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp @@ -0,0 +1,182 @@ +#include "waveshare_epaper.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" + +namespace esphome { +namespace waveshare_epaper { + +static const char *const TAG = "weact_2.90_3c"; + +static const uint16_t HEIGHT = 296; +static const uint16_t WIDTH = 128; + +// General Commands +static const uint8_t SW_RESET = 0x12; +static const uint8_t ACTIVATE = 0x20; +static const uint8_t WRITE_BLACK = 0x24; +static const uint8_t WRITE_COLOR = 0x26; +static const uint8_t SLEEP[] = {0x10, 0x01}; +static const uint8_t UPDATE_FULL[] = {0x22, 0xF7}; + +// Configuration commands +static const uint8_t DRV_OUT_CTL[] = {0x01, 0x27, 0x01, 0x00}; // driver output control +static const uint8_t DATA_ENTRY[] = {0x11, 0x03}; // data entry mode +static const uint8_t BORDER_FULL[] = {0x3C, 0x05}; // border waveform +static const uint8_t TEMP_SENS[] = {0x18, 0x80}; // use internal temp sensor +static const uint8_t DISPLAY_UPDATE[] = {0x21, 0x00, 0x80}; // display update control + +// static const uint8_t GATEV[] = {0x03, 0x17}; +// static const uint8_t SRCV[] = {0x04, 0x41, 0x0C, 0x32}; +// static const uint8_t UPSEQ[] = {0x22, 0xC0}; + +// static const uint8_t ON_PARTIAL[] = {0x22, 0x0F}; +// static const uint8_t VCOM[] = {0x2C, 0x36}; +// static const uint8_t CMD5[] = {0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}; +// static const uint8_t BORDER_PART[] = {0x3C, 0x80}; // border waveform +// static const uint8_t CMD1[] = {0x3F, 0x22}; + +// For controlling which part of the image we want to write +static const uint8_t RAM_X_RANGE[] = {0x44, 0x00, WIDTH / 8u - 1}; +static const uint8_t RAM_Y_RANGE[] = {0x45, 0x00, 0x00, (uint8_t) HEIGHT - 1, (uint8_t) (HEIGHT >> 8)}; +static const uint8_t RAM_X_POS[] = {0x4E, 0x00}; // Always start at 0 +static const uint8_t RAM_Y_POS = 0x4F; + +#define SEND(x) this->cmd_data(x, sizeof(x)) + +// write the buffer starting on line top, up to line bottom. +void WeActEPaper2P9In3C::write_buffer_(int top, int bottom) { + auto width_bytes = this->get_width_internal() / 8; + auto offset = top * width_bytes; + auto length = (bottom - top) * width_bytes; + + this->wait_until_idle_(); + this->set_window_(top, bottom); + + this->command(WRITE_BLACK); + this->start_data_(); + this->write_array(this->buffer_ + offset, length); + this->end_data_(); + + this->command(WRITE_COLOR); + this->start_data_(); + offset += this->get_buffer_length_() / 2; + this->write_array(this->buffer_ + offset, length); + this->end_data_(); +} + +void WeActEPaper2P9In3C::send_reset_() { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->digital_write(false); + delay(2); + this->reset_pin_->digital_write(true); + } +} + +void WeActEPaper2P9In3C::setup() { + setup_pins_(); + delay(20); + this->send_reset_(); + // as a one-off delay this is not worth working around. + delay(100); // NOLINT + this->wait_until_idle_(); + this->command(SW_RESET); + this->wait_until_idle_(); + + SEND(DRV_OUT_CTL); + SEND(DATA_ENTRY); + SEND(BORDER_FULL); + SEND(TEMP_SENS); + SEND(DISPLAY_UPDATE); + + this->wait_until_idle_(); +} + +// t and b are y positions, i.e. line numbers. +void WeActEPaper2P9In3C::set_window_(int t, int b) { + SEND(RAM_X_RANGE); + SEND(RAM_Y_RANGE); + SEND(RAM_X_POS); + + uint8_t buffer[3]; + buffer[0] = RAM_Y_POS; + buffer[1] = (uint8_t) t % 256; + buffer[2] = (uint8_t) (t / 256); + SEND(buffer); +} + +// must implement, but we override setup to have more control +void WeActEPaper2P9In3C::initialize() {} + +void WeActEPaper2P9In3C::deep_sleep() { + SEND(SLEEP); +} + +void WeActEPaper2P9In3C::partial_update_() { + this->full_update_(); + // Figure this out later, no LUT... +} + +void WeActEPaper2P9In3C::full_update_() { + ESP_LOGI(TAG, "Performing full e-paper update."); + this->write_buffer_(0, this->get_height_internal()); + SEND(UPDATE_FULL); + this->command(ACTIVATE); // don't wait here + this->is_busy_ = false; +} + +void WeActEPaper2P9In3C::display() { + if (this->is_busy_ || (this->busy_pin_ != nullptr && this->busy_pin_->digital_read())) + return; + this->is_busy_ = true; + const bool partial = this->at_update_ != 0; + this->at_update_ = (this->at_update_ + 1) % this->full_update_every_; + if (partial) { + this->partial_update_(); + } else { + this->full_update_(); + } +} + +int WeActEPaper2P9In3C::get_width_internal() { return WIDTH; } + +int WeActEPaper2P9In3C::get_height_internal() { return HEIGHT; } + +uint32_t WeActEPaper2P9In3C::idle_timeout_() { return 20000; } // Spec says ~15s for full refresh. + +void WeActEPaper2P9In3C::dump_config() { + LOG_DISPLAY("", "WeAct E-Paper (3 Color)", this) + ESP_LOGCONFIG(TAG, " Model: 2.90in Red+Black"); + 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 HOT WeActEPaper2P9In3C::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 == display::COLOR_OFF) { + 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); + } +} + + + +} // namespace waveshare_epaper +} // namespace esphome From cce5af41023dd84cf7e0711abf214f035eb13d62 Mon Sep 17 00:00:00 2001 From: Jonas Bergler Date: Thu, 15 Feb 2024 11:26:30 +1300 Subject: [PATCH 2/5] cleanup --- .../waveshare_epaper/weact_2p9in3c.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp index 2d0d51e675..0926dfb50f 100644 --- a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp +++ b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp @@ -25,22 +25,18 @@ static const uint8_t BORDER_FULL[] = {0x3C, 0x05}; // border wavefo static const uint8_t TEMP_SENS[] = {0x18, 0x80}; // use internal temp sensor static const uint8_t DISPLAY_UPDATE[] = {0x21, 0x00, 0x80}; // display update control -// static const uint8_t GATEV[] = {0x03, 0x17}; -// static const uint8_t SRCV[] = {0x04, 0x41, 0x0C, 0x32}; -// static const uint8_t UPSEQ[] = {0x22, 0xC0}; - -// static const uint8_t ON_PARTIAL[] = {0x22, 0x0F}; -// static const uint8_t VCOM[] = {0x2C, 0x36}; -// static const uint8_t CMD5[] = {0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00}; -// static const uint8_t BORDER_PART[] = {0x3C, 0x80}; // border waveform -// static const uint8_t CMD1[] = {0x3F, 0x22}; - // For controlling which part of the image we want to write static const uint8_t RAM_X_RANGE[] = {0x44, 0x00, WIDTH / 8u - 1}; static const uint8_t RAM_Y_RANGE[] = {0x45, 0x00, 0x00, (uint8_t) HEIGHT - 1, (uint8_t) (HEIGHT >> 8)}; static const uint8_t RAM_X_POS[] = {0x4E, 0x00}; // Always start at 0 static const uint8_t RAM_Y_POS = 0x4F; +// It's worth adding some notes for this implementation +// - This display doesn't ship with a LUT, instead it relies on the internal values set during OTP +// - This display inverts Black & White in memory, requiring a different implementation for draw_absolute_pixel_internal +// - The reference implementation by the vendor points to https://github.com/ZinggJM/GxEPD2/blob/220fc5845c08b83c8dbac63e0cb83e1a774071ca/src/epd3c/GxEPD2_290_C90c.cpp +// - The datasheet is here https://github.com/WeActStudio/WeActStudio.EpaperModule/blob/master/Doc/ZJY128296-029EAAMFGN.pdf + #define SEND(x) this->cmd_data(x, sizeof(x)) // write the buffer starting on line top, up to line bottom. @@ -141,7 +137,7 @@ int WeActEPaper2P9In3C::get_width_internal() { return WIDTH; } int WeActEPaper2P9In3C::get_height_internal() { return HEIGHT; } -uint32_t WeActEPaper2P9In3C::idle_timeout_() { return 20000; } // Spec says ~15s for full refresh. +uint32_t WeActEPaper2P9In3C::idle_timeout_() { return 2500; } void WeActEPaper2P9In3C::dump_config() { LOG_DISPLAY("", "WeAct E-Paper (3 Color)", this) From 679bd3912589c30d4b3e02d9a08ac266cc575c79 Mon Sep 17 00:00:00 2001 From: Jonas Bergler Date: Thu, 15 Feb 2024 11:39:40 +1300 Subject: [PATCH 3/5] more cleanup --- .../waveshare_epaper/waveshare_epaper.h | 3 +- .../waveshare_epaper/weact_2p9in3c.cpp | 141 ++++++++---------- 2 files changed, 67 insertions(+), 77 deletions(-) diff --git a/esphome/components/waveshare_epaper/waveshare_epaper.h b/esphome/components/waveshare_epaper/waveshare_epaper.h index 2a0c615278..92a816b1cd 100644 --- a/esphome/components/waveshare_epaper/waveshare_epaper.h +++ b/esphome/components/waveshare_epaper/waveshare_epaper.h @@ -731,8 +731,7 @@ class WeActEPaper2P9In3C : public WaveshareEPaperBWR { void write_buffer_(int top, int bottom); void set_window_(int t, int b); void send_reset_(); - void partial_update_(); - void full_update_() ; + void full_update_(); uint32_t full_update_every_{0}; uint32_t at_update_{0}; diff --git a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp index 0926dfb50f..046c9d29e1 100644 --- a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp +++ b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp @@ -5,6 +5,14 @@ namespace esphome { namespace waveshare_epaper { +// It's worth adding some notes for this implementation +// - This display doesn't ship with a LUT, instead it relies on the internal values set during OTP +// - This display inverts Black & White in memory, requiring a different implementation for draw_absolute_pixel_internal +// - The reference implementation by the vendor points to +// https://github.com/ZinggJM/GxEPD2/blob/220fc5845c08b83c8dbac63e0cb83e1a774071ca/src/epd3c/GxEPD2_290_C90c.cpp +// - The datasheet is here +// https://github.com/WeActStudio/WeActStudio.EpaperModule/blob/master/Doc/ZJY128296-029EAAMFGN.pdf + static const char *const TAG = "weact_2.90_3c"; static const uint16_t HEIGHT = 296; @@ -28,45 +36,28 @@ static const uint8_t DISPLAY_UPDATE[] = {0x21, 0x00, 0x80}; // display updat // For controlling which part of the image we want to write static const uint8_t RAM_X_RANGE[] = {0x44, 0x00, WIDTH / 8u - 1}; static const uint8_t RAM_Y_RANGE[] = {0x45, 0x00, 0x00, (uint8_t) HEIGHT - 1, (uint8_t) (HEIGHT >> 8)}; -static const uint8_t RAM_X_POS[] = {0x4E, 0x00}; // Always start at 0 +static const uint8_t RAM_X_POS[] = {0x4E, 0x00}; // Always start at 0 static const uint8_t RAM_Y_POS = 0x4F; -// It's worth adding some notes for this implementation -// - This display doesn't ship with a LUT, instead it relies on the internal values set during OTP -// - This display inverts Black & White in memory, requiring a different implementation for draw_absolute_pixel_internal -// - The reference implementation by the vendor points to https://github.com/ZinggJM/GxEPD2/blob/220fc5845c08b83c8dbac63e0cb83e1a774071ca/src/epd3c/GxEPD2_290_C90c.cpp -// - The datasheet is here https://github.com/WeActStudio/WeActStudio.EpaperModule/blob/master/Doc/ZJY128296-029EAAMFGN.pdf - #define SEND(x) this->cmd_data(x, sizeof(x)) -// write the buffer starting on line top, up to line bottom. -void WeActEPaper2P9In3C::write_buffer_(int top, int bottom) { - auto width_bytes = this->get_width_internal() / 8; - auto offset = top * width_bytes; - auto length = (bottom - top) * width_bytes; +// Basics - this->wait_until_idle_(); - this->set_window_(top, bottom); +int WeActEPaper2P9In3C::get_width_internal() { return WIDTH; } +int WeActEPaper2P9In3C::get_height_internal() { return HEIGHT; } +uint32_t WeActEPaper2P9In3C::idle_timeout_() { return 2500; } - this->command(WRITE_BLACK); - this->start_data_(); - this->write_array(this->buffer_ + offset, length); - this->end_data_(); - - this->command(WRITE_COLOR); - this->start_data_(); - offset += this->get_buffer_length_() / 2; - this->write_array(this->buffer_ + offset, length); - this->end_data_(); +void WeActEPaper2P9In3C::dump_config() { + LOG_DISPLAY("", "WeAct E-Paper (3 Color)", this) + ESP_LOGCONFIG(TAG, " Model: 2.90in Red+Black"); + 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 WeActEPaper2P9In3C::send_reset_() { - if (this->reset_pin_ != nullptr) { - this->reset_pin_->digital_write(false); - delay(2); - this->reset_pin_->digital_write(true); - } -} +// Device lifecycle void WeActEPaper2P9In3C::setup() { setup_pins_(); @@ -87,6 +78,21 @@ void WeActEPaper2P9In3C::setup() { this->wait_until_idle_(); } +void WeActEPaper2P9In3C::send_reset_() { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->digital_write(false); + delay(2); + this->reset_pin_->digital_write(true); + } +} + +// must implement, but we override setup to have more control +void WeActEPaper2P9In3C::initialize() {} + +void WeActEPaper2P9In3C::deep_sleep() { SEND(SLEEP); } + +// Pixel stuff + // t and b are y positions, i.e. line numbers. void WeActEPaper2P9In3C::set_window_(int t, int b) { SEND(RAM_X_RANGE); @@ -100,53 +106,25 @@ void WeActEPaper2P9In3C::set_window_(int t, int b) { SEND(buffer); } -// must implement, but we override setup to have more control -void WeActEPaper2P9In3C::initialize() {} +// send the buffer starting on line `top`, up to line `bottom`. +void WeActEPaper2P9In3C::write_buffer_(int top, int bottom) { + auto width_bytes = this->get_width_internal() / 8; + auto offset = top * width_bytes; + auto length = (bottom - top) * width_bytes; -void WeActEPaper2P9In3C::deep_sleep() { - SEND(SLEEP); -} + this->wait_until_idle_(); + this->set_window_(top, bottom); -void WeActEPaper2P9In3C::partial_update_() { - this->full_update_(); - // Figure this out later, no LUT... -} + this->command(WRITE_BLACK); + this->start_data_(); + this->write_array(this->buffer_ + offset, length); + this->end_data_(); -void WeActEPaper2P9In3C::full_update_() { - ESP_LOGI(TAG, "Performing full e-paper update."); - this->write_buffer_(0, this->get_height_internal()); - SEND(UPDATE_FULL); - this->command(ACTIVATE); // don't wait here - this->is_busy_ = false; -} - -void WeActEPaper2P9In3C::display() { - if (this->is_busy_ || (this->busy_pin_ != nullptr && this->busy_pin_->digital_read())) - return; - this->is_busy_ = true; - const bool partial = this->at_update_ != 0; - this->at_update_ = (this->at_update_ + 1) % this->full_update_every_; - if (partial) { - this->partial_update_(); - } else { - this->full_update_(); - } -} - -int WeActEPaper2P9In3C::get_width_internal() { return WIDTH; } - -int WeActEPaper2P9In3C::get_height_internal() { return HEIGHT; } - -uint32_t WeActEPaper2P9In3C::idle_timeout_() { return 2500; } - -void WeActEPaper2P9In3C::dump_config() { - LOG_DISPLAY("", "WeAct E-Paper (3 Color)", this) - ESP_LOGCONFIG(TAG, " Model: 2.90in Red+Black"); - 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) + offset += this->get_buffer_length_() / 2; + this->command(WRITE_COLOR); + this->start_data_(); + this->write_array(this->buffer_ + offset, length); + this->end_data_(); } void HOT WeActEPaper2P9In3C::draw_absolute_pixel_internal(int x, int y, Color color) { @@ -172,7 +150,20 @@ void HOT WeActEPaper2P9In3C::draw_absolute_pixel_internal(int x, int y, Color co } } +void WeActEPaper2P9In3C::full_update_() { + ESP_LOGI(TAG, "Performing full e-paper update."); + this->write_buffer_(0, this->get_height_internal()); + SEND(UPDATE_FULL); + this->command(ACTIVATE); // don't wait here + this->is_busy_ = false; +} +void WeActEPaper2P9In3C::display() { + if (this->is_busy_ || (this->busy_pin_ != nullptr && this->busy_pin_->digital_read())) + return; + this->is_busy_ = true; + this->full_update_(); +} } // namespace waveshare_epaper } // namespace esphome From 39158e7bce2ee294c9a38063c293efeca3d5b075 Mon Sep 17 00:00:00 2001 From: Jonas Bergler Date: Thu, 15 Feb 2024 12:46:52 +1300 Subject: [PATCH 4/5] review feedback --- esphome/components/waveshare_epaper/weact_2p9in3c.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp index 046c9d29e1..b6f10c5015 100644 --- a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp +++ b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp @@ -134,12 +134,12 @@ void HOT WeActEPaper2P9In3C::draw_absolute_pixel_internal(int x, int y, Color co 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; + const uint8_t subpos = 0x80 >> (x & 0x07); // flip logic if (color == display::COLOR_OFF) { - this->buffer_[pos] |= 0x80 >> subpos; + this->buffer_[pos] |= subpos; } else { - this->buffer_[pos] &= ~(0x80 >> subpos); + this->buffer_[pos] &= ~subpos; } // draw red pixels only, if the color contains red only From 63489831adc2b8de2addbd59dea565653dd5a166 Mon Sep 17 00:00:00 2001 From: Jonas Bergler Date: Mon, 19 Feb 2024 12:07:28 +1300 Subject: [PATCH 5/5] fix issues drawing red --- esphome/components/display/display_buffer.cpp | 2 ++ .../components/waveshare_epaper/weact_2p9in3c.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 3af1b63e01..15f0187296 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -12,11 +12,13 @@ static const char *const TAG = "display"; void DisplayBuffer::init_internal_(uint32_t buffer_length) { ExternalRAMAllocator allocator(ExternalRAMAllocator::ALLOW_FAILURE); + ESP_LOGD(TAG, "allocated %u bytes", buffer_length); this->buffer_ = allocator.allocate(buffer_length); if (this->buffer_ == nullptr) { ESP_LOGE(TAG, "Could not allocate buffer for display!"); return; } + memset(this->buffer_, 0, buffer_length); this->clear(); } diff --git a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp index b6f10c5015..d05048dcec 100644 --- a/esphome/components/waveshare_epaper/weact_2p9in3c.cpp +++ b/esphome/components/waveshare_epaper/weact_2p9in3c.cpp @@ -108,7 +108,7 @@ void WeActEPaper2P9In3C::set_window_(int t, int b) { // send the buffer starting on line `top`, up to line `bottom`. void WeActEPaper2P9In3C::write_buffer_(int top, int bottom) { - auto width_bytes = this->get_width_internal() / 8; + auto width_bytes = this->get_width_internal() / 8u; auto offset = top * width_bytes; auto length = (bottom - top) * width_bytes; @@ -120,7 +120,7 @@ void WeActEPaper2P9In3C::write_buffer_(int top, int bottom) { this->write_array(this->buffer_ + offset, length); this->end_data_(); - offset += this->get_buffer_length_() / 2; + offset += this->get_buffer_length_() / 2u; this->command(WRITE_COLOR); this->start_data_(); this->write_array(this->buffer_ + offset, length); @@ -131,10 +131,9 @@ void HOT WeActEPaper2P9In3C::draw_absolute_pixel_internal(int x, int y, Color co 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 = 0x80 >> (x & 0x07); + // flip logic if (color == display::COLOR_OFF) { this->buffer_[pos] |= subpos; @@ -142,11 +141,12 @@ void HOT WeActEPaper2P9In3C::draw_absolute_pixel_internal(int x, int y, Color co this->buffer_[pos] &= ~subpos; } - // draw red pixels only, if the color contains red only + // draw red pixels only if the color contains red only + const uint32_t buf_half_len = this->get_buffer_length_() / 2u; if (((color.red > 0) && (color.green == 0) && (color.blue == 0))) { - this->buffer_[pos + buf_half_len] |= 0x80 >> subpos; + this->buffer_[pos + buf_half_len] |= subpos; } else { - this->buffer_[pos + buf_half_len] &= ~(0x80 >> subpos); + this->buffer_[pos + buf_half_len] &= ~subpos; } }