mirror of
https://github.com/esphome/esphome.git
synced 2024-12-21 21:14:52 +01:00
Add support for Waveshare EPD 2.13" V3 (#5363)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
6561746f97
commit
ed771abc8a
7 changed files with 264 additions and 8 deletions
|
@ -367,6 +367,7 @@ esphome/components/veml3235/* @kbx81
|
|||
esphome/components/version/* @esphome/core
|
||||
esphome/components/voice_assistant/* @jesserockz
|
||||
esphome/components/wake_on_lan/* @willwill2will54
|
||||
esphome/components/waveshare_epaper/* @clydebarrow
|
||||
esphome/components/web_server_base/* @OttoWinter
|
||||
esphome/components/web_server_idf/* @dentra
|
||||
esphome/components/whirlpool/* @glmnet
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
CODEOWNERS = ["@clydebarrow"]
|
|
@ -72,6 +72,9 @@ WaveshareEPaper7P5InHDB = waveshare_epaper_ns.class_(
|
|||
WaveshareEPaper2P13InDKE = waveshare_epaper_ns.class_(
|
||||
"WaveshareEPaper2P13InDKE", WaveshareEPaper
|
||||
)
|
||||
WaveshareEPaper2P13InV3 = waveshare_epaper_ns.class_(
|
||||
"WaveshareEPaper2P13InV3", WaveshareEPaper
|
||||
)
|
||||
GDEW0154M09 = waveshare_epaper_ns.class_("GDEW0154M09", WaveshareEPaper)
|
||||
|
||||
WaveshareEPaperTypeAModel = waveshare_epaper_ns.enum("WaveshareEPaperTypeAModel")
|
||||
|
@ -104,6 +107,7 @@ MODELS = {
|
|||
"7.50inv2alt": ("b", WaveshareEPaper7P5InV2alt),
|
||||
"7.50in-hd-b": ("b", WaveshareEPaper7P5InHDB),
|
||||
"2.13in-ttgo-dke": ("c", WaveshareEPaper2P13InDKE),
|
||||
"2.13inv3": ("c", WaveshareEPaper2P13InV3),
|
||||
"1.54in-m5coreink-m09": ("c", GDEW0154M09),
|
||||
}
|
||||
|
||||
|
|
186
esphome/components/waveshare_epaper/waveshare_213v3.cpp
Normal file
186
esphome/components/waveshare_epaper/waveshare_213v3.cpp
Normal file
|
@ -0,0 +1,186 @@
|
|||
#include "waveshare_epaper.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/application.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace waveshare_epaper {
|
||||
|
||||
static const char *const TAG = "waveshare_2.13v3";
|
||||
|
||||
static const uint8_t PARTIAL_LUT[] = {
|
||||
0x32, // cmd
|
||||
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,
|
||||
};
|
||||
|
||||
static const uint8_t FULL_LUT[] = {
|
||||
0x32, // CMD
|
||||
0x80, 0x4A, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x4A, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x80, 0x4A, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x4A, 0x80, 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, 0xF, 0x0, 0x0, 0xF, 0x0, 0x0, 0x2, 0xF, 0x0, 0x0, 0x0, 0x0, 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, 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, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0, 0x0, 0x0,
|
||||
};
|
||||
|
||||
static const uint8_t SW_RESET = 0x12;
|
||||
static const uint8_t ACTIVATE = 0x20;
|
||||
static const uint8_t WRITE_BUFFER = 0x24;
|
||||
static const uint8_t WRITE_BASE = 0x26;
|
||||
|
||||
static const uint8_t DRV_OUT_CTL[] = {0x01, 0x27, 0x01, 0x00}; // driver output control
|
||||
static const uint8_t GATEV[] = {0x03, 0x17};
|
||||
static const uint8_t SRCV[] = {0x04, 0x41, 0x0C, 0x32};
|
||||
static const uint8_t SLEEP[] = {0x10, 0x01};
|
||||
static const uint8_t DATA_ENTRY[] = {0x11, 0x03}; // data entry mode
|
||||
static const uint8_t TEMP_SENS[] = {0x18, 0x80}; // Temp sensor
|
||||
static const uint8_t DISPLAY_UPDATE[] = {0x21, 0x00, 0x80}; // Display update control
|
||||
static const uint8_t UPSEQ[] = {0x22, 0xC0};
|
||||
static const uint8_t ON_FULL[] = {0x22, 0xC7};
|
||||
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 BORDER_FULL[] = {0x3C, 0x05}; // border waveform
|
||||
static const uint8_t CMD1[] = {0x3F, 0x22};
|
||||
static const uint8_t RAM_X_START[] = {0x44, 0x00, 121 / 8}; // set ram_x_address_start_end
|
||||
static const uint8_t RAM_Y_START[] = {0x45, 0x00, 0x00, 250 - 1, 0}; // set ram_y_address_start_end
|
||||
static const uint8_t RAM_X_POS[] = {0x4E, 0x00}; // set ram_x_address_counter
|
||||
// static const uint8_t RAM_Y_POS[] = {0x4F, 0x00, 0x00}; // set ram_y_address_counter
|
||||
#define SEND(x) this->cmd_data(x, sizeof(x))
|
||||
|
||||
void WaveshareEPaper2P13InV3::write_lut_(const uint8_t *lut) {
|
||||
this->wait_until_idle_();
|
||||
this->cmd_data(lut, sizeof(PARTIAL_LUT));
|
||||
SEND(CMD1);
|
||||
SEND(GATEV);
|
||||
SEND(SRCV);
|
||||
SEND(VCOM);
|
||||
}
|
||||
|
||||
// write the buffer starting on line top, up to line bottom.
|
||||
void WaveshareEPaper2P13InV3::write_buffer_(uint8_t cmd, int top, int bottom) {
|
||||
this->wait_until_idle_();
|
||||
this->set_window_(top, bottom);
|
||||
this->command(cmd);
|
||||
this->start_data_();
|
||||
auto width_bytes = this->get_width_internal() / 8;
|
||||
this->write_array(this->buffer_ + top * width_bytes, (bottom - top) * width_bytes);
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
void WaveshareEPaper2P13InV3::send_reset_() {
|
||||
if (this->reset_pin_ != nullptr) {
|
||||
this->reset_pin_->digital_write(false);
|
||||
delay(2);
|
||||
this->reset_pin_->digital_write(true);
|
||||
}
|
||||
}
|
||||
|
||||
void WaveshareEPaper2P13InV3::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(CMD5);
|
||||
this->set_window_(0, this->get_height_internal());
|
||||
SEND(BORDER_FULL);
|
||||
SEND(DISPLAY_UPDATE);
|
||||
SEND(TEMP_SENS);
|
||||
this->wait_until_idle_();
|
||||
this->write_lut_(FULL_LUT);
|
||||
}
|
||||
|
||||
// t and b are y positions, i.e. line numbers.
|
||||
void WaveshareEPaper2P13InV3::set_window_(int t, int b) {
|
||||
uint8_t buffer[3];
|
||||
|
||||
SEND(RAM_X_START);
|
||||
SEND(RAM_Y_START);
|
||||
SEND(RAM_X_POS);
|
||||
buffer[0] = 0x4F;
|
||||
buffer[1] = (uint8_t) t;
|
||||
buffer[2] = (uint8_t) (t >> 8);
|
||||
SEND(buffer);
|
||||
}
|
||||
|
||||
// must implement, but we override setup to have more control
|
||||
void WaveshareEPaper2P13InV3::initialize() {}
|
||||
|
||||
void WaveshareEPaper2P13InV3::partial_update_() {
|
||||
this->send_reset_();
|
||||
this->set_timeout(100, [this] {
|
||||
this->write_lut_(PARTIAL_LUT);
|
||||
SEND(BORDER_PART);
|
||||
SEND(UPSEQ);
|
||||
this->command(ACTIVATE);
|
||||
this->set_timeout(100, [this] {
|
||||
this->wait_until_idle_();
|
||||
this->write_buffer_(WRITE_BUFFER, 0, this->get_height_internal());
|
||||
SEND(ON_PARTIAL);
|
||||
this->command(ACTIVATE); // Activate Display Update Sequence
|
||||
this->is_busy_ = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void WaveshareEPaper2P13InV3::full_update_() {
|
||||
ESP_LOGI(TAG, "Performing full e-paper update.");
|
||||
this->write_lut_(FULL_LUT);
|
||||
this->write_buffer_(WRITE_BUFFER, 0, this->get_height_internal());
|
||||
this->write_buffer_(WRITE_BASE, 0, this->get_height_internal());
|
||||
SEND(ON_FULL);
|
||||
this->command(ACTIVATE); // don't wait here
|
||||
this->is_busy_ = false;
|
||||
}
|
||||
|
||||
void WaveshareEPaper2P13InV3::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 WaveshareEPaper2P13InV3::get_width_internal() { return 128; }
|
||||
|
||||
int WaveshareEPaper2P13InV3::get_height_internal() { return 250; }
|
||||
|
||||
uint32_t WaveshareEPaper2P13InV3::idle_timeout_() { return 5000; }
|
||||
|
||||
void WaveshareEPaper2P13InV3::dump_config() {
|
||||
LOG_DISPLAY("", "Waveshare E-Paper", this)
|
||||
ESP_LOGCONFIG(TAG, " Model: 2.13inV3");
|
||||
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 WaveshareEPaper2P13InV3::set_full_update_every(uint32_t full_update_every) {
|
||||
this->full_update_every_ = full_update_every;
|
||||
}
|
||||
|
||||
} // namespace waveshare_epaper
|
||||
} // namespace esphome
|
|
@ -109,8 +109,20 @@ void WaveshareEPaper::data(uint8_t value) {
|
|||
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 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]);
|
||||
this->dc_pin_->digital_write(true);
|
||||
this->write_array(c_data + 1, length - 1);
|
||||
this->disable();
|
||||
}
|
||||
|
||||
bool WaveshareEPaper::wait_until_idle_() {
|
||||
if (this->busy_pin_ == nullptr) {
|
||||
if (this->busy_pin_ == nullptr || !this->busy_pin_->digital_read()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -120,7 +132,7 @@ bool WaveshareEPaper::wait_until_idle_() {
|
|||
ESP_LOGE(TAG, "Timeout while displaying image!");
|
||||
return false;
|
||||
}
|
||||
delay(10);
|
||||
delay(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -2218,8 +2230,9 @@ void HOT WaveshareEPaper2P13InDKE::display() {
|
|||
} else {
|
||||
// set up partial update
|
||||
this->command(0x32);
|
||||
for (uint8_t v : PART_UPDATE_LUT_TTGO_DKE)
|
||||
this->data(v);
|
||||
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);
|
||||
|
||||
|
@ -2264,12 +2277,10 @@ void HOT WaveshareEPaper2P13InDKE::display() {
|
|||
this->wait_until_idle_();
|
||||
|
||||
// data must be sent again on partial update
|
||||
delay(300); // NOLINT
|
||||
this->command(0x24);
|
||||
this->start_data_();
|
||||
this->write_array(this->buffer_, this->get_buffer_length_());
|
||||
this->end_data_();
|
||||
delay(300); // NOLINT
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Completed e-paper update.");
|
||||
|
@ -2281,6 +2292,7 @@ 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_);
|
||||
|
|
|
@ -19,6 +19,7 @@ class WaveshareEPaper : public display::DisplayBuffer,
|
|||
|
||||
void command(uint8_t value);
|
||||
void data(uint8_t value);
|
||||
void cmd_data(const uint8_t *data, size_t length);
|
||||
|
||||
virtual void display() = 0;
|
||||
virtual void initialize() = 0;
|
||||
|
@ -49,7 +50,7 @@ class WaveshareEPaper : public display::DisplayBuffer,
|
|||
this->reset_pin_->digital_write(false);
|
||||
delay(reset_duration_); // NOLINT
|
||||
this->reset_pin_->digital_write(true);
|
||||
delay(200); // NOLINT
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,5 +615,39 @@ class WaveshareEPaper2P13InDKE : public WaveshareEPaper {
|
|||
uint32_t at_update_{0};
|
||||
};
|
||||
|
||||
class WaveshareEPaper2P13InV3 : public WaveshareEPaper {
|
||||
public:
|
||||
void display() override;
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
void deep_sleep() override {
|
||||
// COMMAND POWER DOWN
|
||||
this->command(0x10);
|
||||
this->data(0x01);
|
||||
// cannot wait until idle here, the device no longer responds
|
||||
}
|
||||
|
||||
void set_full_update_every(uint32_t full_update_every);
|
||||
|
||||
void setup() override;
|
||||
void initialize() override;
|
||||
|
||||
protected:
|
||||
int get_width_internal() override;
|
||||
int get_height_internal() override;
|
||||
uint32_t idle_timeout_() override;
|
||||
|
||||
void write_buffer_(uint8_t cmd, 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_{30};
|
||||
uint32_t at_update_{0};
|
||||
bool is_busy_{false};
|
||||
void write_lut_(const uint8_t *lut);
|
||||
};
|
||||
} // namespace waveshare_epaper
|
||||
} // namespace esphome
|
||||
|
|
|
@ -693,7 +693,6 @@ display:
|
|||
greyscale: false
|
||||
partial_updating: false
|
||||
update_interval: 60s
|
||||
|
||||
display_data_1_pin:
|
||||
number: GPIO5
|
||||
allow_other_uses: true
|
||||
|
@ -742,6 +741,24 @@ display:
|
|||
vcom_pin:
|
||||
number: GPIO1
|
||||
allow_other_uses: true
|
||||
- platform: waveshare_epaper
|
||||
spi_id: spi_id_1
|
||||
cs_pin:
|
||||
number: GPIO23
|
||||
allow_other_uses: true
|
||||
dc_pin:
|
||||
number: GPIO23
|
||||
allow_other_uses: true
|
||||
busy_pin:
|
||||
number: GPIO23
|
||||
allow_other_uses: true
|
||||
reset_pin:
|
||||
number: GPIO23
|
||||
allow_other_uses: true
|
||||
model: 2.13inv3
|
||||
full_update_every: 30
|
||||
lambda: |-
|
||||
it.rectangle(0, 0, it.get_width(), it.get_height());
|
||||
|
||||
number:
|
||||
- platform: tuya
|
||||
|
|
Loading…
Reference in a new issue