diff --git a/esphome/components/epaper_spi/epaper_spi.cpp b/esphome/components/epaper_spi/epaper_spi.cpp index 9d8005560d..6ac4ac0975 100644 --- a/esphome/components/epaper_spi/epaper_spi.cpp +++ b/esphome/components/epaper_spi/epaper_spi.cpp @@ -1,5 +1,4 @@ #include "epaper_spi.h" -#include #include #include "esphome/core/application.h" #include "esphome/core/helpers.h" @@ -9,21 +8,32 @@ namespace esphome::epaper_spi { static const char *const TAG = "epaper_spi"; -static const uint8_t MAX_TRANSFER_TIME = 10; // Transfer in 10ms blocks to allow the loop to run - void EPaperBase::setup() { - this->init_internal_(this->get_buffer_length()); + if (!this->init_buffer_(this->get_buffer_length())) { + this->mark_failed("Failed to initialize buffer"); + return; + } this->setup_pins_(); this->spi_setup(); } +bool EPaperBase::init_buffer_(size_t buffer_length) { + if (!this->buffer_.init(buffer_length)) { + return false; + } + this->clear(); + return true; +} + void EPaperBase::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 } @@ -44,13 +54,23 @@ void EPaperBase::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 EPaperBase::cmd_data(const uint8_t *c_data, size_t length) { +// The command is the first byte, length is the length of data only in the second byte, followed by the data. +// [COMMAND, LENGTH, DATA...] +void EPaperBase::cmd_data(const uint8_t *data) { + const uint8_t command = data[0]; + const uint8_t length = data[1]; + const uint8_t *ptr = data + 2; + + ESP_LOGVV(TAG, "Command: 0x%02X, Length: %d, Data: %s", command, length, + format_hex_pretty(ptr, length, '.', false).c_str()); + 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->write_byte(command); + if (length > 0) { + this->dc_pin_->digital_write(true); + this->write_array(ptr, length); + } this->disable(); } @@ -61,179 +81,79 @@ bool EPaperBase::is_idle_() { return !this->busy_pin_->digital_read(); } -void EPaperBase::reset_() { +void EPaperBase::reset() { if (this->reset_pin_ != nullptr) { this->reset_pin_->digital_write(false); this->disable_loop(); this->set_timeout(this->reset_duration_, [this] { this->reset_pin_->digital_write(true); - this->set_timeout(20, [this] { - this->state_ = RESET_DONE; - this->enable_loop(); - }); + this->set_timeout(20, [this] { this->enable_loop(); }); }); } } void EPaperBase::update() { - if (this->state_ != IDLE) { + if (!this->state_queue_.empty()) { ESP_LOGE(TAG, "Display update already in progress"); return; } - this->do_update_(); // Calls ESPHome (current page) lambda - this->state_ = UPDATING; + + this->state_queue_.push(EPaperState::UPDATE); + this->state_queue_.push(EPaperState::RESET); + this->state_queue_.push(EPaperState::INITIALISE); + this->state_queue_.push(EPaperState::TRANSFER_DATA); + this->state_queue_.push(EPaperState::POWER_ON); + this->state_queue_.push(EPaperState::REFRESH_SCREEN); + this->state_queue_.push(EPaperState::POWER_OFF); + this->state_queue_.push(EPaperState::DEEP_SLEEP); + this->state_queue_.push(EPaperState::IDLE); + this->enable_loop(); } void EPaperBase::loop() { - switch (this->state_) { - case IDLE: + if (this->waiting_for_idle_) { + if (this->is_idle_()) { + this->waiting_for_idle_ = false; + } else { + return; + } + } + + auto state = this->state_queue_.front(); + + switch (state) { + case EPaperState::IDLE: this->disable_loop(); break; - case UPDATING: - this->reset_(); - this->state_ = RESETTING; + case EPaperState::UPDATE: + this->do_update_(); // Calls ESPHome (current page) lambda break; - case RESETTING: - // Nothing to do here, next state change is handled by timeouts + case EPaperState::RESET: + this->reset(); break; - case RESET_DONE: - if (this->is_idle_()) { - this->initialize(); - this->state_ = INITIALIZING; + case EPaperState::INITIALISE: + this->initialize_(); + break; + case EPaperState::TRANSFER_DATA: + if (!this->transfer_data()) { + return; // Not done yet, come back next loop } break; - case INITIALIZING: - if (this->is_idle_()) { - ESP_LOGI(TAG, "Display initialized successfully"); - this->state_ = TRANSFERING_DATA; - } - break; - case TRANSFERING_DATA: - this->transfer_data(); - break; - case TRANSFER_DONE: + case EPaperState::POWER_ON: this->power_on(); - this->state_ = POWERING_ON; break; - case POWERING_ON: - if (this->is_idle_()) { - this->refresh_screen(); - this->state_ = REFRESHING_SCREEN; - } + case EPaperState::REFRESH_SCREEN: + this->refresh_screen(); break; - case REFRESHING_SCREEN: - if (this->is_idle_()) { - this->power_off(); - this->state_ = POWERING_OFF; - } + case EPaperState::POWER_OFF: + this->power_off(); break; - case POWERING_OFF: - if (this->is_idle_()) { - this->deep_sleep(); - } - this->state_ = IDLE; - this->disable_loop(); + case EPaperState::DEEP_SLEEP: + this->deep_sleep(); break; } -} - -void EPaper6Color::setup() { - if (!this->init_internal_6c_(this->get_buffer_length())) { - this->mark_failed("Failed to initialize buffer"); - return; - } - this->setup_pins_(); - this->spi_setup(); -} - -bool EPaper6Color::init_internal_6c_(uint32_t buffer_length) { - if (!this->buffer_.init(buffer_length)) { - return false; - } - this->clear(); - return true; -} - -uint8_t EPaper6Color::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 = 0x2; // Yellow - } - } else { - hex_code = 0x3; // Red (or Magenta) - } - } else { - if (color.green > 127) { - if (color.blue > 127) { - hex_code = 0x5; // Cyan -> Blue - } else { - hex_code = 0x6; // Green - } - } else { - if (color.blue > 127) { - hex_code = 0x5; // Blue - } else { - hex_code = 0x0; // Black - } - } - } - - return hex_code; -} -void EPaper6Color::fill(Color color) { - uint8_t pixel_color; - if (color.is_on()) { - pixel_color = this->color_to_hex(color); - } else { - pixel_color = 0x1; - } - - // We store 8 bitset<3> in 3 bytes - // | byte 1 | byte 2 | byte 3 | - // |aaabbbaa|abbbaaab|bbaaabbb| - uint8_t byte_1 = pixel_color << 5 | pixel_color << 2 | pixel_color >> 1; - uint8_t byte_2 = pixel_color << 7 | pixel_color << 4 | pixel_color << 1 | pixel_color >> 2; - uint8_t byte_3 = pixel_color << 6 | pixel_color << 3 | pixel_color << 0; - - const size_t buffer_length = this->get_buffer_length(); - for (size_t i = 0; i < buffer_length; i += 3) { - this->buffer_[i + 0] = byte_1; - this->buffer_[i + 1] = byte_2; - this->buffer_[i + 2] = byte_3; - } -} - -uint32_t EPaper6Color::get_buffer_length() { - // 6 colors buffer, 1 pixel = 3 bits, we will store 8 pixels in 24 bits = 3 bytes - return this->get_width_controller() * this->get_height_internal() / 8u * 3u; -} - -void HOT EPaper6Color::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 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; - - if (byte_subposition <= 5) { - this->buffer_[byte_position] = (this->buffer_[byte_position] & (0xFF ^ (0b111 << (5 - byte_subposition)))) | - (pixel_bits << (5 - byte_subposition)); - } else { - this->buffer_[byte_position] = (this->buffer_[byte_position] & (0xFF ^ (0b111 >> (byte_subposition - 5)))) | - (pixel_bits >> (byte_subposition - 5)); - - this->buffer_[byte_position + 1] = - (this->buffer_[byte_position + 1] & (0xFF ^ (0xFF & (0b111 << (13 - byte_subposition))))) | - (pixel_bits << (13 - byte_subposition)); - } + this->state_queue_.pop(); } void EPaperBase::start_command_() { @@ -251,112 +171,27 @@ void EPaperBase::end_data_() { this->disable(); } void EPaperBase::on_safe_shutdown() { this->deep_sleep(); } -void EPaper7p3InE::initialize() { - static const uint8_t cmdh_data[] = {0xAA, 0x49, 0x55, 0x20, 0x08, 0x09, 0x18}; - this->cmd_data(cmdh_data, sizeof(cmdh_data)); +void EPaperBase::initialize_() { + size_t index = 0; + const auto &sequence = this->init_sequence_; + const size_t sequence_size = this->init_sequence_length_; + while (index != sequence_size) { + if (sequence_size - index < 2) { + this->mark_failed("Malformed init sequence"); + return; + } + const auto *ptr = sequence + index; + const uint8_t length = ptr[1]; + if (sequence_size - index < length) { + this->mark_failed("Malformed init sequence"); + return; + } - static const uint8_t data_01[] = {0x01, 0x3F}; - this->cmd_data(data_01, sizeof(data_01)); - - static const uint8_t data_02[] = {0x00, 0x5F, 0x69}; - this->cmd_data(data_02, sizeof(data_02)); - - static const uint8_t data_03[] = {0x03, 0x00, 0x54, 0x00, 0x44}; - this->cmd_data(data_03, sizeof(data_03)); - - static const uint8_t data_04[] = {0x05, 0x40, 0x1F, 0x1F, 0x2C}; - this->cmd_data(data_04, sizeof(data_04)); - - static const uint8_t data_05[] = {0x06, 0x6F, 0x1F, 0x17, 0x49}; - this->cmd_data(data_05, sizeof(data_05)); - - static const uint8_t data_06[] = {0x08, 0x6F, 0x1F, 0x1F, 0x22}; - this->cmd_data(data_06, sizeof(data_06)); - - static const uint8_t data_07[] = {0x30, 0x03}; - this->cmd_data(data_07, sizeof(data_07)); - - static const uint8_t data_08[] = {0x50, 0x3F}; - this->cmd_data(data_08, sizeof(data_08)); - - static const uint8_t data_09[] = {0x60, 0x02, 0x00}; - this->cmd_data(data_09, sizeof(data_09)); - - static const uint8_t data_10[] = {0x61, 0x03, 0x20, 0x01, 0xE0}; - this->cmd_data(data_10, sizeof(data_10)); - - static const uint8_t data_11[] = {0x84, 0x01}; - this->cmd_data(data_11, sizeof(data_11)); - - static const uint8_t data_12[] = {0xE3, 0x2F}; - this->cmd_data(data_12, sizeof(data_12)); + this->cmd_data(ptr); + index += length + 2; + } this->power_on(); } -void HOT EPaper7p3InE::transfer_data() { - const uint32_t start_time = App.get_loop_component_start_time(); - if (this->current_data_index_ == 0) { - ESP_LOGI(TAG, "Sending data to the display"); - this->command(0x10); - } - - uint8_t bytes_to_send[4]{0}; - const size_t buffer_length = this->get_buffer_length(); - for (size_t i = this->current_data_index_; i < buffer_length; i += 3) { - std::bitset<24> triplet = encode_uint24(this->buffer_[i + 0], this->buffer_[i + 1], this->buffer_[i + 2]); - // 8 bitset<3> are stored in 3 bytes - // |aaabbbaa|abbbaaab|bbaaabbb| - // | byte 1 | byte 2 | byte 3 | - bytes_to_send[0] = ((triplet >> 17).to_ulong() & 0b01110000) | ((triplet >> 18).to_ulong() & 0b00000111); - bytes_to_send[1] = ((triplet >> 11).to_ulong() & 0b01110000) | ((triplet >> 12).to_ulong() & 0b00000111); - bytes_to_send[2] = ((triplet >> 5).to_ulong() & 0b01110000) | ((triplet >> 6).to_ulong() & 0b00000111); - bytes_to_send[3] = ((triplet << 1).to_ulong() & 0b01110000) | ((triplet << 0).to_ulong() & 0b00000111); - - this->start_data_(); - this->write_array(bytes_to_send, sizeof(bytes_to_send)); - this->end_data_(); - - if (millis() - start_time > MAX_TRANSFER_TIME) { - // Let the main loop run and come back next loop - this->current_data_index_ = i + 3; - return; - } - } - // Finished the entire dataset - this->current_data_index_ = 0; - this->state_ = TRANSFER_DONE; -} - -void EPaper7p3InE::power_on() { - ESP_LOGI(TAG, "Power on the display"); - this->command(0x04); -} - -void EPaper7p3InE::power_off() { - ESP_LOGI(TAG, "Power off the display"); - this->command(0x02); - this->data(0x00); -} - -void EPaper7p3InE::refresh_screen() { - this->command(0x12); - this->data(0x00); -} - -void EPaper7p3InE::deep_sleep() { - ESP_LOGI(TAG, "Set the display to deep sleep"); - this->command(0x07); - this->data(0xA5); -} - -void EPaper7p3InE::dump_config() { - LOG_DISPLAY("", "E-Paper SPI", this); - ESP_LOGCONFIG(TAG, " Model: 7.3in-E"); - 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 esphome::epaper_spi diff --git a/esphome/components/epaper_spi/epaper_spi.h b/esphome/components/epaper_spi/epaper_spi.h index 92b310f39e..11418e0b64 100644 --- a/esphome/components/epaper_spi/epaper_spi.h +++ b/esphome/components/epaper_spi/epaper_spi.h @@ -5,25 +5,30 @@ #include "esphome/components/split_buffer/split_buffer.h" #include "esphome/core/component.h" +#include + namespace esphome::epaper_spi { -enum EPaperState : uint8_t { +enum class EPaperState : uint8_t { IDLE, - UPDATING, - RESETTING, - RESET_DONE, - INITIALIZING, - TRANSFERING_DATA, - TRANSFER_DONE, - POWERING_ON, - REFRESHING_SCREEN, - POWERING_OFF, + UPDATE, + RESET, + INITIALISE, + TRANSFER_DATA, + POWER_ON, + REFRESH_SCREEN, + POWER_OFF, + DEEP_SLEEP, }; +static const uint8_t MAX_TRANSFER_TIME = 10; // Transfer in 10ms blocks to allow the loop to run + class EPaperBase : public display::DisplayBuffer, public spi::SPIDevice { public: + EPaperBase(const uint8_t *init_sequence, const size_t init_sequence_length) + : init_sequence_(init_sequence), init_sequence_length_(init_sequence_length) {} void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } float get_setup_priority() const override; void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } @@ -32,7 +37,7 @@ class EPaperBase : public display::DisplayBuffer, void command(uint8_t value); void data(uint8_t value); - void cmd_data(const uint8_t *data, size_t length); + void cmd_data(const uint8_t *data); void update() override; void loop() override; @@ -44,12 +49,17 @@ class EPaperBase : public display::DisplayBuffer, protected: bool is_idle_(); void setup_pins_(); - void reset_(); + virtual void reset(); + void initialize_(); + bool init_buffer_(size_t buffer_length); virtual int get_width_controller() { return this->get_width_internal(); }; - virtual void initialize() = 0; virtual void deep_sleep() = 0; - virtual void transfer_data() = 0; + /** + * Send data to the device via SPI + * @return true if done, false if should be called next loop + */ + virtual bool transfer_data() = 0; virtual void refresh_screen() = 0; virtual void power_on() = 0; @@ -65,45 +75,17 @@ class EPaperBase : public display::DisplayBuffer, GPIOPin *busy_pin_{nullptr}; GPIOPin *reset_pin_{nullptr}; + const uint8_t *init_sequence_{nullptr}; + const size_t init_sequence_length_{0}; + uint32_t reset_duration_{200}; - EPaperState state_{IDLE}; - split_buffer::SplitBuffer buffer_; -}; - -class EPaper6Color : public EPaperBase { - public: - uint8_t color_to_hex(Color color); - 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; - void setup() override; - bool init_internal_6c_(uint32_t buffer_length); -}; - -class EPaper7p3InE : public EPaper6Color { - public: - void initialize() override; - - void dump_config() override; - - protected: - int get_width_internal() override { return 800; }; - int get_height_internal() override { return 480; }; - void transfer_data() override; - void refresh_screen() override; - - void power_on() override; - void power_off() override; - - void deep_sleep() override; - size_t current_data_index_{0}; + + std::queue state_queue_{{EPaperState::IDLE}}; + + bool waiting_for_idle_{false}; }; } // namespace esphome::epaper_spi diff --git a/esphome/components/epaper_spi/epaper_spi_base_6_color.cpp b/esphome/components/epaper_spi/epaper_spi_base_6_color.cpp new file mode 100644 index 0000000000..36d286669a --- /dev/null +++ b/esphome/components/epaper_spi/epaper_spi_base_6_color.cpp @@ -0,0 +1,135 @@ +#include "epaper_spi_base_6_color.h" + +#include "esphome/core/log.h" + +namespace esphome::epaper_spi { + +static constexpr const char *const TAG = "epaper_spi.6c"; + +static inline uint8_t color_to_hex(Color color) { + if (color.red > 127) { + if (color.green > 170) { + if (color.blue > 127) { + return 0x1; // White + } else { + return 0x2; // Yellow + } + } else { + return 0x3; // Red (or Magenta) + } + } else { + if (color.green > 127) { + if (color.blue > 127) { + return 0x5; // Cyan -> Blue + } else { + return 0x6; // Green + } + } else { + if (color.blue > 127) { + return 0x5; // Blue + } else { + return 0x0; // Black + } + } + } +} + +void EPaper6Color::fill(Color color) { + uint8_t pixel_color; + if (color.is_on()) { + pixel_color = color_to_hex(color); + } else { + pixel_color = 0x1; + } + + // We store 8 bitset<3> in 3 bytes + // | byte 1 | byte 2 | byte 3 | + // |aaabbbaa|abbbaaab|bbaaabbb| + uint8_t byte_1 = pixel_color << 5 | pixel_color << 2 | pixel_color >> 1; + uint8_t byte_2 = pixel_color << 7 | pixel_color << 4 | pixel_color << 1 | pixel_color >> 2; + uint8_t byte_3 = pixel_color << 6 | pixel_color << 3 | pixel_color << 0; + + const size_t buffer_length = this->get_buffer_length(); + for (size_t i = 0; i < buffer_length; i += 3) { + this->buffer_[i + 0] = byte_1; + this->buffer_[i + 1] = byte_2; + this->buffer_[i + 2] = byte_3; + } +} + +uint32_t EPaper6Color::get_buffer_length() { + // 6 colors buffer, 1 pixel = 3 bits, we will store 8 pixels in 24 bits = 3 bytes + return this->get_width_controller() * this->get_height_internal() / 8u * 3u; +} + +void HOT EPaper6Color::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 = color_to_hex(color); + 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; + + if (byte_subposition <= 5) { + this->buffer_[byte_position] = (this->buffer_[byte_position] & (0xFF ^ (0b111 << (5 - byte_subposition)))) | + (pixel_bits << (5 - byte_subposition)); + } else { + this->buffer_[byte_position] = (this->buffer_[byte_position] & (0xFF ^ (0b111 >> (byte_subposition - 5)))) | + (pixel_bits >> (byte_subposition - 5)); + + this->buffer_[byte_position + 1] = + (this->buffer_[byte_position + 1] & (0xFF ^ (0xFF & (0b111 << (13 - byte_subposition))))) | + (pixel_bits << (13 - byte_subposition)); + } +} + +bool HOT EPaper6Color::transfer_data() { + const uint32_t start_time = App.get_loop_component_start_time(); + if (this->current_data_index_ == 0) { + ESP_LOGI(TAG, "Sending data to the display"); + this->command(0x10); + } + + uint8_t bytes_to_send[4]{0}; + const size_t buffer_length = this->get_buffer_length(); + for (size_t i = this->current_data_index_; i < buffer_length; i += 3) { + const uint32_t triplet = encode_uint24(this->buffer_[i + 0], this->buffer_[i + 1], this->buffer_[i + 2]); + // 8 pixels are stored in 3 bytes + // |aaabbbaa|abbbaaab|bbaaabbb| + // | byte 1 | byte 2 | byte 3 | + bytes_to_send[0] = ((triplet >> 17) & 0b01110000) | ((triplet >> 18) & 0b00000111); + bytes_to_send[1] = ((triplet >> 11) & 0b01110000) | ((triplet >> 12) & 0b00000111); + bytes_to_send[2] = ((triplet >> 5) & 0b01110000) | ((triplet >> 6) & 0b00000111); + bytes_to_send[3] = ((triplet << 1) & 0b01110000) | ((triplet << 0) & 0b00000111); + + this->start_data_(); + this->write_array(bytes_to_send, sizeof(bytes_to_send)); + this->end_data_(); + + if (millis() - start_time > MAX_TRANSFER_TIME) { + // Let the main loop run and come back next loop + this->current_data_index_ = i + 3; + return false; + } + } + // Finished the entire dataset + this->current_data_index_ = 0; + return true; +} + +void EPaper6Color::reset() { + if (this->reset_pin_ != nullptr) { + this->disable_loop(); + this->reset_pin_->digital_write(true); + this->set_timeout(20, [this] { + this->reset_pin_->digital_write(false); + delay(2); + this->reset_pin_->digital_write(true); + this->set_timeout(20, [this] { this->enable_loop(); }); + }); + } +} + +} // namespace esphome::epaper_spi diff --git a/esphome/components/epaper_spi/epaper_spi_base_6_color.h b/esphome/components/epaper_spi/epaper_spi_base_6_color.h new file mode 100644 index 0000000000..b15a2abf68 --- /dev/null +++ b/esphome/components/epaper_spi/epaper_spi_base_6_color.h @@ -0,0 +1,23 @@ +#pragma once + +#include "epaper_spi.h" + +namespace esphome::epaper_spi { + +class EPaper6Color : public EPaperBase { + public: + EPaper6Color(const uint8_t *init_sequence, const size_t init_sequence_length) + : EPaperBase(init_sequence, init_sequence_length) {} + + display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_COLOR; } + void fill(Color color) override; + + protected: + void draw_absolute_pixel_internal(int x, int y, Color color) override; + uint32_t get_buffer_length() override; + + bool transfer_data() override; + void reset() override; +}; + +} // namespace esphome::epaper_spi diff --git a/esphome/components/epaper_spi/epaper_spi_model_7p3in_e.cpp b/esphome/components/epaper_spi/epaper_spi_model_7p3in_e.cpp new file mode 100644 index 0000000000..b78819e1ed --- /dev/null +++ b/esphome/components/epaper_spi/epaper_spi_model_7p3in_e.cpp @@ -0,0 +1,41 @@ +#include "epaper_spi_model_7p3in_e.h" + +namespace esphome::epaper_spi { + +static constexpr const char *const TAG = "epaper_spi.7.3in-e"; + +void EPaper7p3InE::power_on() { + ESP_LOGI(TAG, "Power on the display"); + this->command(0x04); + this->waiting_for_idle_ = true; +} + +void EPaper7p3InE::power_off() { + ESP_LOGI(TAG, "Power off the display"); + this->command(0x02); + this->data(0x00); + this->waiting_for_idle_ = true; +} + +void EPaper7p3InE::refresh_screen() { + this->command(0x12); + this->data(0x00); + this->waiting_for_idle_ = true; +} + +void EPaper7p3InE::deep_sleep() { + ESP_LOGI(TAG, "Set the display to deep sleep"); + this->command(0x07); + this->data(0xA5); +} + +void EPaper7p3InE::dump_config() { + LOG_DISPLAY("", "E-Paper SPI", this); + ESP_LOGCONFIG(TAG, " Model: 7.3in-E"); + 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 esphome::epaper_spi diff --git a/esphome/components/epaper_spi/epaper_spi_model_7p3in_e.h b/esphome/components/epaper_spi/epaper_spi_model_7p3in_e.h new file mode 100644 index 0000000000..4365dce1b3 --- /dev/null +++ b/esphome/components/epaper_spi/epaper_spi_model_7p3in_e.h @@ -0,0 +1,45 @@ +#pragma once + +#include "epaper_spi_base_6_color.h" + +namespace esphome::epaper_spi { + +class EPaper7p3InE : public EPaper6Color { + static constexpr const uint16_t WIDTH = 800; + static constexpr const uint16_t HEIGHT = 480; + // clang-format off + + // Command, data length, data + static constexpr uint8_t INIT_SEQUENCE[] = { + 0xAA, 6, 0x49, 0x55, 0x20, 0x08, 0x09, 0x18, + 0x01, 1, 0x3F, + 0x00, 2, 0x5F, 0x69, + 0x03, 4, 0x00, 0x54, 0x00, 0x44, + 0x05, 4, 0x40, 0x1F, 0x1F, 0x2C, + 0x06, 4, 0x6F, 0x1F, 0x17, 0x49, + 0x08, 4, 0x6F, 0x1F, 0x1F, 0x22, + 0x30, 1, 0x03, + 0x50, 1, 0x3F, + 0x60, 2, 0x02, 0x00, + 0x61, 4, WIDTH / 256, WIDTH % 256, HEIGHT / 256, HEIGHT % 256, + 0x84, 1, 0x01, + 0xE3, 1, 0x2F, + }; + // clang-format on + + public: + EPaper7p3InE() : EPaper6Color(INIT_SEQUENCE, sizeof(INIT_SEQUENCE)) {} + + void dump_config() override; + + protected: + int get_width_internal() override { return WIDTH; }; + int get_height_internal() override { return HEIGHT; }; + + void refresh_screen() override; + void power_on() override; + void power_off() override; + void deep_sleep() override; +}; + +} // namespace esphome::epaper_spi