Waveshare: support red and black on EDP_7in5b_V2

This commit is contained in:
Tristan Groléat 2023-12-03 19:42:45 +01:00
parent 75899162b3
commit 481e7ee74b
3 changed files with 294 additions and 73 deletions

View file

@ -24,6 +24,9 @@ WaveshareEPaper = waveshare_epaper_ns.class_("WaveshareEPaper", WaveshareEPaperB
WaveshareEPaperBWR = waveshare_epaper_ns.class_( WaveshareEPaperBWR = waveshare_epaper_ns.class_(
"WaveshareEPaperBWR", WaveshareEPaperBase "WaveshareEPaperBWR", WaveshareEPaperBase
) )
WaveshareEPaperPolled = waveshare_epaper_ns.class_(
"WaveshareEPaperPolled", WaveshareEPaper
)
WaveshareEPaperTypeA = waveshare_epaper_ns.class_( WaveshareEPaperTypeA = waveshare_epaper_ns.class_(
"WaveshareEPaperTypeA", WaveshareEPaper "WaveshareEPaperTypeA", WaveshareEPaper
) )
@ -98,6 +101,9 @@ WaveshareEPaper13P3InK = waveshare_epaper_ns.class_(
"WaveshareEPaper13P3InK", WaveshareEPaper "WaveshareEPaper13P3InK", WaveshareEPaper
) )
GDEW0154M09 = waveshare_epaper_ns.class_("GDEW0154M09", WaveshareEPaper) GDEW0154M09 = waveshare_epaper_ns.class_("GDEW0154M09", WaveshareEPaper)
WaveshareEPaper7In5BV2 = waveshare_epaper_ns.class_(
"WaveshareEPaper7In5BV2", WaveshareEPaperPolled
)
WaveshareEPaperTypeAModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeAModel") WaveshareEPaperTypeAModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeAModel")
WaveshareEPaperTypeBModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeBModel") WaveshareEPaperTypeBModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeBModel")
@ -128,6 +134,7 @@ MODELS = {
"5.83inv2": ("b", WaveshareEPaper5P8InV2), "5.83inv2": ("b", WaveshareEPaper5P8InV2),
"7.50in": ("b", WaveshareEPaper7P5In), "7.50in": ("b", WaveshareEPaper7P5In),
"7.50in-bv2": ("b", WaveshareEPaper7P5InBV2), "7.50in-bv2": ("b", WaveshareEPaper7P5InBV2),
"7.50in-bv2-rb": ("b", WaveshareEPaper7In5BV2),
"7.50in-bv3": ("b", WaveshareEPaper7P5InBV3), "7.50in-bv3": ("b", WaveshareEPaper7P5InBV3),
"7.50in-bc": ("b", WaveshareEPaper7P5InBC), "7.50in-bc": ("b", WaveshareEPaper7P5InBC),
"7.50inv2": ("b", WaveshareEPaper7P5InV2), "7.50inv2": ("b", WaveshareEPaper7P5InV2),

View file

@ -110,7 +110,7 @@ static const uint8_t PARTIAL_UPD_2IN9_LUT[PARTIAL_UPD_2IN9_LUT_SIZE] =
}; };
// clang-format on // clang-format on
void WaveshareEPaperBase::setup_pins_() { void WaveshareEPaper::setup_pins_() {
this->init_internal_(this->get_buffer_length_()); this->init_internal_(this->get_buffer_length_());
this->dc_pin_->setup(); // OUTPUT this->dc_pin_->setup(); // OUTPUT
this->dc_pin_->digital_write(false); this->dc_pin_->digital_write(false);
@ -125,13 +125,13 @@ void WaveshareEPaperBase::setup_pins_() {
this->reset_(); this->reset_();
} }
float WaveshareEPaperBase::get_setup_priority() const { return setup_priority::PROCESSOR; } float WaveshareEPaper::get_setup_priority() const { return setup_priority::PROCESSOR; }
void WaveshareEPaperBase::command(uint8_t value) { void WaveshareEPaper::command(uint8_t value) {
this->start_command_(); this->start_command_();
this->write_byte(value); this->write_byte(value);
this->end_command_(); this->end_command_();
} }
void WaveshareEPaperBase::data(uint8_t value) { void WaveshareEPaper::data(uint8_t value) {
this->start_data_(); this->start_data_();
this->write_byte(value); this->write_byte(value);
this->end_data_(); this->end_data_();
@ -139,7 +139,7 @@ void WaveshareEPaperBase::data(uint8_t value) {
// write a command followed by one or more bytes of data. // write a command followed by one or more bytes of data.
// The command is the first byte, length is the total including cmd. // The command is the first byte, length is the total including cmd.
void WaveshareEPaperBase::cmd_data(const uint8_t *c_data, size_t length) { void WaveshareEPaper::cmd_data(const uint8_t *c_data, size_t length) {
this->dc_pin_->digital_write(false); this->dc_pin_->digital_write(false);
this->enable(); this->enable();
this->write_byte(c_data[0]); this->write_byte(c_data[0]);
@ -148,7 +148,7 @@ void WaveshareEPaperBase::cmd_data(const uint8_t *c_data, size_t length) {
this->disable(); this->disable();
} }
bool WaveshareEPaperBase::wait_until_idle_() { bool WaveshareEPaper::wait_until_idle_() {
if (this->busy_pin_ == nullptr || !this->busy_pin_->digital_read()) { if (this->busy_pin_ == nullptr || !this->busy_pin_->digital_read()) {
return true; return true;
} }
@ -163,15 +163,23 @@ bool WaveshareEPaperBase::wait_until_idle_() {
} }
return true; return true;
} }
void WaveshareEPaperBase::update() { void WaveshareEPaper::update() {
this->do_update_(); this->do_update_();
this->display(); this->display();
} }
void WaveshareEPaper::fill(Color color) { void WaveshareEPaper::fill(Color color) {
// flip logic uint32_t offset = 0;
const uint8_t fill = color.is_on() ? 0x00 : 0xFF; for (const auto& buf_color: this->get_supported_colors()) {
for (uint32_t i = 0; i < this->get_buffer_length_(); i++) // A bit set to 1 means color is off
this->buffer_[i] = fill; uint8_t value = 0x00;
if (color != buf_color) {
value = 0xFF;
}
for (uint32_t i = 0; i < (this->get_width_internal() * this->get_height_internal()) / 8u; i++) {
this->buffer_[offset+i] = value;
}
offset+= (this->get_width_internal() * this->get_height_internal()) / 8u;
}
} }
void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, Color color) { 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) if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0)
@ -179,58 +187,40 @@ void HOT WaveshareEPaper::draw_absolute_pixel_internal(int x, int y, Color color
const uint32_t pos = (x + y * this->get_width_controller()) / 8u; const uint32_t pos = (x + y * this->get_width_controller()) / 8u;
const uint8_t subpos = x & 0x07; const uint8_t subpos = x & 0x07;
// flip logic uint32_t offset = 0;
if (!color.is_on()) { for (const auto& buf_color: this->get_supported_colors()) {
this->buffer_[pos] |= 0x80 >> subpos; // A bit set to 1 means color is off
} else { this->buffer_[offset+pos] &= ~(0x80 >> subpos);
this->buffer_[pos] &= ~(0x80 >> subpos); if (color != buf_color) {
this->buffer_[offset+pos] |= 0x80 >> subpos;
}
offset+= (this->get_width_internal() * this->get_height_internal()) / 8u;
} }
} }
uint32_t WaveshareEPaper::get_buffer_length_() { uint32_t WaveshareEPaper::get_buffer_length_() {
return this->get_width_controller() * this->get_height_internal() / 8u; return (this->get_width_controller() * this->get_height_internal() * this->get_supported_colors().size()) / 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
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 WaveshareEPaperBase::start_command_() { void WaveshareEPaper::start_command_() {
this->dc_pin_->digital_write(false); this->dc_pin_->digital_write(false);
this->enable(); this->enable();
} }
void WaveshareEPaperBase::end_command_() { this->disable(); } void WaveshareEPaper::end_command_() { this->disable(); }
void WaveshareEPaperBase::start_data_() { void WaveshareEPaper::start_data_() {
this->dc_pin_->digital_write(true); this->dc_pin_->digital_write(true);
this->enable(); this->enable();
} }
void WaveshareEPaperBase::end_data_() { this->disable(); } void WaveshareEPaper::end_data_() { this->disable(); }
void WaveshareEPaperBase::on_safe_shutdown() { this->deep_sleep(); } void WaveshareEPaper::on_safe_shutdown() { this->deep_sleep(); }
display::DisplayType WaveshareEPaper::get_display_type() {
if (this->get_supported_colors().size() == 1) {
return display::DisplayType::DISPLAY_TYPE_BINARY;
} else {
return display::DisplayType::DISPLAY_TYPE_COLOR;
}
}
// ======================================================== // ========================================================
// Type A // Type A
@ -602,7 +592,7 @@ uint32_t WaveshareEPaperTypeA::idle_timeout_() {
case TTGO_EPAPER_2_13_IN_B1: case TTGO_EPAPER_2_13_IN_B1:
return 2500; return 2500;
default: default:
return WaveshareEPaperBase::idle_timeout_(); return WaveshareEPaper::idle_timeout_();
} }
} }
@ -3040,11 +3030,166 @@ uint32_t WaveshareEPaper13P3InK::idle_timeout_() { return 10000; }
void WaveshareEPaper13P3InK::dump_config() { void WaveshareEPaper13P3InK::dump_config() {
LOG_DISPLAY("", "Waveshare E-Paper", this); LOG_DISPLAY("", "Waveshare E-Paper", this);
ESP_LOGCONFIG(TAG, " Model: 13.3inK"); ESP_LOGCONFIG(TAG, " Model: 13.3inK");
}
void WaveshareEPaperPolled::update() {
this->do_update_();
if (this->state_ == State::sleeping) {
this->set_state_(State::update_requested);
}
}
void WaveshareEPaperPolled::loop() {
switch (this->state_) {
case State::sleeping:
break;
case State::update_requested:
this->reset_pin_->digital_write(false);
this->set_state_(State::resetting);
break;
case State::resetting:
if (millis() - this->last_state_change_ >= this->reset_duration_) {
this->reset_pin_->digital_write(true);
this->set_state_(State::initializing);
}
break;
case State::initializing:
if (millis() - this->last_state_change_ >= 200) {
this->power_on();
this->set_state_(State::powering_on);
}
break;
case State::powering_on:
if (millis() - this->last_state_change_ >= 100 && (!this->busy_pin_ || !this->busy_pin_->digital_read())) {
this->configure();
this->set_state_(State::configuring);
}
break;
case State::configuring:
this->display();
this->set_state_(State::displaying);
break;
case State::displaying:
if (millis() - this->last_state_change_ >= 200 && (!this->busy_pin_ || !this->busy_pin_->digital_read())) {
this->power_off();
this->set_state_(State::powering_off);
}
break;
case State::powering_off:
if (!this->busy_pin_ || !this->busy_pin_->digital_read()) {
this->deep_sleep();
this->set_state_(State::sleeping);
}
break;
}
}
void WaveshareEPaperPolled::set_state_(State state) {
this->state_ = state;
this->last_state_change_ = millis();
switch (this->state_) {
case State::sleeping:
ESP_LOGD(TAG, "sleeping");
break;
case State::update_requested:
ESP_LOGD(TAG, "update_requested");
break;
case State::resetting:
ESP_LOGD(TAG, "resetting");
break;
case State::initializing:
ESP_LOGD(TAG, "initializing");
break;
case State::powering_on:
ESP_LOGD(TAG, "powering_on");
break;
case State::configuring:
ESP_LOGD(TAG, "configuring");
break;
case State::displaying:
ESP_LOGD(TAG, "displaying");
break;
case State::powering_off:
ESP_LOGD(TAG, "powering_off");
break;
}
}
void WaveshareEPaper7In5BV2::dump_config() {
LOG_DISPLAY("", "Waveshare E-Paper", this);
ESP_LOGCONFIG(TAG, " Model: 7.5in V3 Black/Red");
LOG_PIN(" Reset Pin: ", this->reset_pin_); LOG_PIN(" Reset Pin: ", this->reset_pin_);
LOG_PIN(" DC Pin: ", this->dc_pin_); LOG_PIN(" DC Pin: ", this->dc_pin_);
LOG_PIN(" Busy Pin: ", this->busy_pin_); LOG_PIN(" Busy Pin: ", this->busy_pin_);
LOG_UPDATE_INTERVAL(this); LOG_UPDATE_INTERVAL(this);
} }
void WaveshareEPaper7In5BV2::power_on() {
// COMMAND POWER SETTING
this->command(0x01);
this->data(0x07);
this->data(0x17);
this->data(0x3F);
this->data(0x3F);
// POWER ON
this->command(0x04);
}
void WaveshareEPaper7In5BV2::configure() {
// 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);
this->data(0x20);
this->data(0x01);
this->data(0xE0);
// COMMAND DUAL SPI MODE
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);
// COMMAND RESOLUTION GATE SETTING
this->command(0x65);
this->data(0x00);
this->data(0x00);
this->data(0x00);
this->data(0x00);
}
void HOT WaveshareEPaper7In5BV2::display() {
uint32_t buf_len = this->get_buffer_length_();
// COMMAND DATA START TRANSMISSION NEW DATA
this->command(0x10);
for (uint32_t i = 0; i < buf_len/2; i++) {
this->data(this->buffer_[i]);
}
this->command(0x92);
// COMMAND DATA START TRANSMISSION NEW DATA
this->command(0x13);
for (uint32_t i = buf_len/2; i < buf_len; i++) {
this->data(~this->buffer_[i]);
}
// COMMAND DISPLAY REFRESH
this->command(0x12);
}
void WaveshareEPaper7In5BV2::power_off() {
this->command(0x02); // POWER OFF
}
void WaveshareEPaper7In5BV2::deep_sleep() {
this->command(0x07); // SLEEP
this->data(0xA5);
}
} // namespace waveshare_epaper } // namespace waveshare_epaper
} // namespace esphome } // namespace esphome

View file

@ -7,7 +7,7 @@
namespace esphome { namespace esphome {
namespace waveshare_epaper { namespace waveshare_epaper {
class WaveshareEPaperBase : public display::DisplayBuffer, class WaveshareEPaper : public display::DisplayBuffer,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW,
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_2MHZ> { spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_2MHZ> {
public: public:
@ -34,6 +34,10 @@ class WaveshareEPaperBase : public display::DisplayBuffer,
void on_safe_shutdown() override; void on_safe_shutdown() override;
display::DisplayType get_display_type() override;
void fill(Color color) override;
protected: protected:
bool wait_until_idle_(); bool wait_until_idle_();
@ -50,9 +54,14 @@ class WaveshareEPaperBase : public display::DisplayBuffer,
virtual int get_width_controller() { return this->get_width_internal(); }; virtual int get_width_controller() { return this->get_width_internal(); };
virtual uint32_t get_buffer_length_() = 0; // NOLINT(readability-identifier-naming) virtual uint32_t get_buffer_length_();
uint32_t reset_duration_{200}; uint32_t reset_duration_{200};
// Return the list of colors supported by the device
virtual std::vector<Color> get_supported_colors() { return {display::COLOR_ON}; }
void draw_absolute_pixel_internal(int x, int y, Color color) override;
void start_command_(); void start_command_();
void end_command_(); void end_command_();
void start_data_(); void start_data_();
@ -64,26 +73,9 @@ class WaveshareEPaperBase : public display::DisplayBuffer,
virtual uint32_t idle_timeout_() { return 1000u; } // NOLINT(readability-identifier-naming) virtual uint32_t idle_timeout_() { return 1000u; } // NOLINT(readability-identifier-naming)
}; };
class WaveshareEPaper : public WaveshareEPaperBase { class WaveshareEPaperBWR : public WaveshareEPaper {
public: public:
void fill(Color color) override; virtual std::vector<Color> get_supported_colors() override { return {display::COLOR_ON, Color(255, 0, 0, 0)}; }
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; }
protected:
void draw_absolute_pixel_internal(int x, int y, Color color) override;
uint32_t get_buffer_length_() override;
};
class WaveshareEPaperBWR : public WaveshareEPaperBase {
public:
void fill(Color color) override;
display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; }
protected:
void draw_absolute_pixel_internal(int x, int y, Color color) override;
uint32_t get_buffer_length_() override;
}; };
enum WaveshareEPaperTypeAModel { enum WaveshareEPaperTypeAModel {
@ -791,6 +783,83 @@ class WaveshareEPaper13P3InK : public WaveshareEPaper {
int get_height_internal() override; int get_height_internal() override;
uint32_t idle_timeout_() override; uint32_t idle_timeout_() override;
};
// Generic Waveshare e-paper component that
// avoids using any blocking wait to be able to support
// big screens that are slow to update
class WaveshareEPaperPolled : public WaveshareEPaper {
// Will request a display refresh
void update() override;
// Will move the state machine one state at a time
// to refresh the display when requested by display()
void loop() override;
// Unused method from parent
void initialize() override {}
protected:
// Below are display steps, called one after the other by loop()
// Just implement these to support a new device.
// Never sleep or wait in a step, the state machine will
// handle it.
// Just after reset, set the power mode and power the driver on
virtual void power_on() = 0;
// Send all the configuration required to display
virtual void configure() = 0;
// Send image data and refresh the display
virtual void display() = 0;
// Power off the driver
virtual void power_off() = 0;
// Set the screen to deep sleep
void deep_sleep() override = 0;
private:
enum class State: uint8_t {
sleeping,
update_requested,
resetting,
initializing,
powering_on,
configuring,
displaying,
powering_off,
};
// Set the current state of the display
void set_state_(State state);
// Current state of the display
State state_{State::sleeping};
// Timestamp of last state changed, used to wait between states
uint32_t last_state_change_{0};
};
// 7.5 inches screen supporting black and red color with
// a v3 label on the back. Called EDP_7in5b_V2 in WaveShare examples.
class WaveshareEPaper7In5BV2 : public WaveshareEPaperPolled {
public:
void dump_config() override;
void power_on() override;
void configure() override;
void display() override;
void power_off() override;
void deep_sleep() override;
virtual std::vector<Color> get_supported_colors() override { return {display::COLOR_ON, Color(255, 0, 0, 0)}; }
protected:
int get_width_internal() override { return 800; }
int get_height_internal() override { return 480; }
}; };
} // namespace waveshare_epaper } // namespace waveshare_epaper