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", WaveshareEPaperBase
)
WaveshareEPaperPolled = waveshare_epaper_ns.class_(
"WaveshareEPaperPolled", WaveshareEPaper
)
WaveshareEPaperTypeA = waveshare_epaper_ns.class_(
"WaveshareEPaperTypeA", WaveshareEPaper
)
@ -98,6 +101,9 @@ WaveshareEPaper13P3InK = waveshare_epaper_ns.class_(
"WaveshareEPaper13P3InK", WaveshareEPaper
)
GDEW0154M09 = waveshare_epaper_ns.class_("GDEW0154M09", WaveshareEPaper)
WaveshareEPaper7In5BV2 = waveshare_epaper_ns.class_(
"WaveshareEPaper7In5BV2", WaveshareEPaperPolled
)
WaveshareEPaperTypeAModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeAModel")
WaveshareEPaperTypeBModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeBModel")
@ -128,6 +134,7 @@ MODELS = {
"5.83inv2": ("b", WaveshareEPaper5P8InV2),
"7.50in": ("b", WaveshareEPaper7P5In),
"7.50in-bv2": ("b", WaveshareEPaper7P5InBV2),
"7.50in-bv2-rb": ("b", WaveshareEPaper7In5BV2),
"7.50in-bv3": ("b", WaveshareEPaper7P5InBV3),
"7.50in-bc": ("b", WaveshareEPaper7P5InBC),
"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
void WaveshareEPaperBase::setup_pins_() {
void WaveshareEPaper::setup_pins_() {
this->init_internal_(this->get_buffer_length_());
this->dc_pin_->setup(); // OUTPUT
this->dc_pin_->digital_write(false);
@ -125,13 +125,13 @@ void WaveshareEPaperBase::setup_pins_() {
this->reset_();
}
float WaveshareEPaperBase::get_setup_priority() const { return setup_priority::PROCESSOR; }
void WaveshareEPaperBase::command(uint8_t value) {
float WaveshareEPaper::get_setup_priority() const { return setup_priority::PROCESSOR; }
void WaveshareEPaper::command(uint8_t value) {
this->start_command_();
this->write_byte(value);
this->end_command_();
}
void WaveshareEPaperBase::data(uint8_t value) {
void WaveshareEPaper::data(uint8_t value) {
this->start_data_();
this->write_byte(value);
this->end_data_();
@ -139,7 +139,7 @@ void WaveshareEPaperBase::data(uint8_t value) {
// 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) {
void WaveshareEPaper::cmd_data(const uint8_t *c_data, size_t length) {
this->dc_pin_->digital_write(false);
this->enable();
this->write_byte(c_data[0]);
@ -148,7 +148,7 @@ void WaveshareEPaperBase::cmd_data(const uint8_t *c_data, size_t length) {
this->disable();
}
bool WaveshareEPaperBase::wait_until_idle_() {
bool WaveshareEPaper::wait_until_idle_() {
if (this->busy_pin_ == nullptr || !this->busy_pin_->digital_read()) {
return true;
}
@ -163,15 +163,23 @@ bool WaveshareEPaperBase::wait_until_idle_() {
}
return true;
}
void WaveshareEPaperBase::update() {
void WaveshareEPaper::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;
uint32_t offset = 0;
for (const auto& buf_color: this->get_supported_colors()) {
// A bit set to 1 means color is off
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) {
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 uint8_t subpos = x & 0x07;
// flip logic
if (!color.is_on()) {
this->buffer_[pos] |= 0x80 >> subpos;
} else {
this->buffer_[pos] &= ~(0x80 >> subpos);
uint32_t offset = 0;
for (const auto& buf_color: this->get_supported_colors()) {
// A bit set to 1 means color is off
this->buffer_[offset+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_() {
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
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);
}
return (this->get_width_controller() * this->get_height_internal() * this->get_supported_colors().size()) / 8u;
}
void WaveshareEPaperBase::start_command_() {
void WaveshareEPaper::start_command_() {
this->dc_pin_->digital_write(false);
this->enable();
}
void WaveshareEPaperBase::end_command_() { this->disable(); }
void WaveshareEPaperBase::start_data_() {
void WaveshareEPaper::end_command_() { this->disable(); }
void WaveshareEPaper::start_data_() {
this->dc_pin_->digital_write(true);
this->enable();
}
void WaveshareEPaperBase::end_data_() { this->disable(); }
void WaveshareEPaperBase::on_safe_shutdown() { this->deep_sleep(); }
void WaveshareEPaper::end_data_() { this->disable(); }
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
@ -602,7 +592,7 @@ uint32_t WaveshareEPaperTypeA::idle_timeout_() {
case TTGO_EPAPER_2_13_IN_B1:
return 2500;
default:
return WaveshareEPaperBase::idle_timeout_();
return WaveshareEPaper::idle_timeout_();
}
}
@ -3040,11 +3030,166 @@ uint32_t WaveshareEPaper13P3InK::idle_timeout_() { return 10000; }
void WaveshareEPaper13P3InK::dump_config() {
LOG_DISPLAY("", "Waveshare E-Paper", this);
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(" DC Pin: ", this->dc_pin_);
LOG_PIN(" Busy Pin: ", this->busy_pin_);
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 esphome

View file

@ -7,7 +7,7 @@
namespace esphome {
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,
spi::CLOCK_PHASE_LEADING, spi::DATA_RATE_2MHZ> {
public:
@ -34,6 +34,10 @@ class WaveshareEPaperBase : public display::DisplayBuffer,
void on_safe_shutdown() override;
display::DisplayType get_display_type() override;
void fill(Color color) override;
protected:
bool wait_until_idle_();
@ -50,9 +54,14 @@ class WaveshareEPaperBase : public display::DisplayBuffer,
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};
// 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 end_command_();
void start_data_();
@ -64,26 +73,9 @@ class WaveshareEPaperBase : public display::DisplayBuffer,
virtual uint32_t idle_timeout_() { return 1000u; } // NOLINT(readability-identifier-naming)
};
class WaveshareEPaper : public WaveshareEPaperBase {
class WaveshareEPaperBWR : public WaveshareEPaper {
public:
void fill(Color color) override;
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;
virtual std::vector<Color> get_supported_colors() override { return {display::COLOR_ON, Color(255, 0, 0, 0)}; }
};
enum WaveshareEPaperTypeAModel {
@ -791,6 +783,83 @@ class WaveshareEPaper13P3InK : public WaveshareEPaper {
int get_height_internal() 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