mirror of
https://github.com/esphome/esphome.git
synced 2024-11-23 15:38:11 +01:00
Commit of Grayscale support as provided by niceboygithub. See: https://github.com/esphome/esphome/pull/6209#issuecomment-2388682338
This commit is contained in:
parent
89c972c85a
commit
f516a441fd
3 changed files with 311 additions and 39 deletions
|
@ -7,6 +7,7 @@ from esphome.const import (
|
|||
CONF_DC_PIN,
|
||||
CONF_FULL_UPDATE_EVERY,
|
||||
CONF_ID,
|
||||
CONF_INITIAL_MODE,
|
||||
CONF_LAMBDA,
|
||||
CONF_MODEL,
|
||||
CONF_PAGES,
|
||||
|
@ -168,6 +169,16 @@ def validate_reset_pin_required(config):
|
|||
)
|
||||
return config
|
||||
|
||||
def validate_grayscale4_supported(config):
|
||||
print(config[CONF_MODEL])
|
||||
if CONF_INITIAL_MODE in config:
|
||||
if config[CONF_MODEL] in ['4.20in-v2']:
|
||||
return config
|
||||
raise cv.Invalid(
|
||||
f"'{CONF_INITIAL_MODE}' is supported for model {config[CONF_MODEL]}"
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
display.FULL_DISPLAY_SCHEMA.extend(
|
||||
|
@ -182,12 +193,14 @@ CONFIG_SCHEMA = cv.All(
|
|||
cv.positive_time_period_milliseconds,
|
||||
cv.Range(max=core.TimePeriod(milliseconds=500)),
|
||||
),
|
||||
cv.Optional(CONF_INITIAL_MODE): cv.int_range(min=1, max=3),
|
||||
}
|
||||
)
|
||||
.extend(cv.polling_component_schema("1s"))
|
||||
.extend(spi.spi_device_schema()),
|
||||
validate_full_update_every_only_types_ac,
|
||||
validate_reset_pin_required,
|
||||
validate_grayscale4_supported,
|
||||
cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA),
|
||||
)
|
||||
|
||||
|
@ -224,3 +237,5 @@ async def to_code(config):
|
|||
cg.add(var.set_full_update_every(config[CONF_FULL_UPDATE_EVERY]))
|
||||
if CONF_RESET_DURATION in config:
|
||||
cg.add(var.set_reset_duration(config[CONF_RESET_DURATION]))
|
||||
if CONF_INITIAL_MODE in config:
|
||||
cg.add(var.set_initial_mode(config[CONF_INITIAL_MODE]))
|
||||
|
|
|
@ -7,35 +7,151 @@ namespace waveshare_epaper {
|
|||
|
||||
static const char *const TAG = "waveshare_4.2v2";
|
||||
|
||||
void WaveshareEPaper4P2InV2::display() {
|
||||
ESP_LOGD(TAG, "Performing full update");
|
||||
this->full_update_();
|
||||
static const uint8_t LUT_ALL[233]={
|
||||
0x01, 0x0A, 0x1B, 0x0F, 0x03, 0x01, 0x01,
|
||||
0x05, 0x0A, 0x01, 0x0A, 0x01, 0x01, 0x01,
|
||||
0x05, 0x08, 0x03, 0x02, 0x04, 0x01, 0x01,
|
||||
0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x0A, 0x1B, 0x0F, 0x03, 0x01, 0x01,
|
||||
0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01,
|
||||
0x05, 0x48, 0x03, 0x82, 0x84, 0x01, 0x01,
|
||||
0x01, 0x84, 0x84, 0x82, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x0A, 0x1B, 0x8F, 0x03, 0x01, 0x01,
|
||||
0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01,
|
||||
0x05, 0x48, 0x83, 0x82, 0x04, 0x01, 0x01,
|
||||
0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x8A, 0x1B, 0x8F, 0x03, 0x01, 0x01,
|
||||
0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01,
|
||||
0x05, 0x48, 0x83, 0x02, 0x04, 0x01, 0x01,
|
||||
0x01, 0x04, 0x04, 0x02, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x8A, 0x9B, 0x8F, 0x03, 0x01, 0x01,
|
||||
0x05, 0x4A, 0x01, 0x8A, 0x01, 0x01, 0x01,
|
||||
0x05, 0x48, 0x03, 0x42, 0x04, 0x01, 0x01,
|
||||
0x01, 0x04, 0x04, 0x42, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x07, 0x17, 0x41, 0xA8,
|
||||
0x32, 0x30,
|
||||
};
|
||||
|
||||
uint32_t WaveshareEPaper4P2InV2::get_buffer_length_() {
|
||||
if (this->initial_mode_ == MODE_GRAYSCALE4) {
|
||||
// black and gray buffer
|
||||
return this->get_width_controller() * this->get_height_internal() / 4u;
|
||||
} else {
|
||||
// just a black buffer
|
||||
return this->get_width_controller() * this->get_height_internal() / 8u;
|
||||
}
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::full_update_() {
|
||||
void WaveshareEPaper4P2InV2::display() {
|
||||
if (this->is_busy_ || (this->busy_pin_ != nullptr && this->busy_pin_->digital_read()))
|
||||
return;
|
||||
this->is_busy_ = true;
|
||||
if (this->initial_mode_ == MODE_GRAYSCALE4) {
|
||||
ESP_LOGD(TAG, "Performing grayscale4 update");
|
||||
this->update_(MODE_GRAYSCALE4);
|
||||
} else if (this->initial_mode_ == MODE_FAST) {
|
||||
ESP_LOGD(TAG, "Performing fast update");
|
||||
this->update_(MODE_FAST);
|
||||
} else {
|
||||
const bool partial = this->at_update_ != 0;
|
||||
this->at_update_ = (this->at_update_ + 1) % this->full_update_every_;
|
||||
if (partial) {
|
||||
ESP_LOGD(TAG, "Performing partial update");
|
||||
this->update_(MODE_PARTIAL);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Performing full update");
|
||||
//this->init_();
|
||||
this->update_(MODE_FULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::update_(TurnOnMode mode) {
|
||||
const uint32_t buf_half_len = this->get_buffer_length_() / 2u;
|
||||
|
||||
this->reset_();
|
||||
this->wait_until_idle_();
|
||||
if (!this->wait_until_idle_()) {
|
||||
ESP_LOGW(TAG, "wait_until_idle_ returned FALSE. Is your busy pin set?");
|
||||
}
|
||||
|
||||
if (mode == MODE_PARTIAL) {
|
||||
this->command(0x21);
|
||||
this->data(0x00);
|
||||
this->data(0x00);
|
||||
|
||||
this->command(0x3C);
|
||||
this->data(0x80);
|
||||
|
||||
// this->set_window_(0, 0, this->get_width_internal() - 1, this->get_height_internal() - 1);
|
||||
// this->set_cursor_(0, 0);
|
||||
} else if (mode == MODE_FULL) {
|
||||
this->command(0x21);
|
||||
this->data(0x40);
|
||||
this->data(0x00);
|
||||
|
||||
this->command(0x3C);
|
||||
this->data(0x05);
|
||||
}
|
||||
|
||||
this->command(0x24);
|
||||
this->start_data_();
|
||||
if (mode == MODE_GRAYSCALE4)
|
||||
this->write_array(this->buffer_, buf_half_len);
|
||||
else
|
||||
this->write_array(this->buffer_, this->get_buffer_length_());
|
||||
this->end_data_();
|
||||
|
||||
// new data
|
||||
if ((mode == MODE_FULL) || (mode == MODE_FAST)) {
|
||||
this->command(0x26);
|
||||
this->start_data_();
|
||||
this->write_array(this->buffer_, this->get_buffer_length_());
|
||||
this->end_data_();
|
||||
|
||||
this->turn_on_display_full_();
|
||||
|
||||
this->deep_sleep();
|
||||
} else if (mode == MODE_GRAYSCALE4) {
|
||||
this->command(0x26);
|
||||
this->start_data_();
|
||||
this->write_array(this->buffer_ + buf_half_len, buf_half_len);
|
||||
this->end_data_();
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::turn_on_display_full_() {
|
||||
this->turn_on_display_(mode);
|
||||
|
||||
this->deep_sleep();
|
||||
this->is_busy_ = false;
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::turn_on_display_(TurnOnMode mode) {
|
||||
this->command(0x22);
|
||||
switch (mode) {
|
||||
case MODE_GRAYSCALE4:
|
||||
this->data(0xcf);
|
||||
break;
|
||||
case MODE_PARTIAL:
|
||||
this->data(0xff);
|
||||
break;
|
||||
case MODE_FAST:
|
||||
this->data(0xc7);
|
||||
break;
|
||||
case MODE_FULL:
|
||||
default:
|
||||
this->data(0xf7);
|
||||
break;
|
||||
}
|
||||
this->command(0x20);
|
||||
|
||||
// possible timeout.
|
||||
this->wait_until_idle_();
|
||||
}
|
||||
|
||||
|
@ -52,17 +168,23 @@ void WaveshareEPaper4P2InV2::set_window_(uint16_t x, uint16_t y, uint16_t x2, ui
|
|||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::clear_() {
|
||||
uint8_t *buffer = (uint8_t *) calloc(this->get_buffer_length_(), sizeof(uint8_t));
|
||||
memset(buffer, 0xff, this->get_buffer_length_());
|
||||
uint32_t bufflen;
|
||||
if (this->initial_mode_ == MODE_GRAYSCALE4) {
|
||||
bufflen = this->get_buffer_length_() / 2u;
|
||||
} else {
|
||||
bufflen = this->get_buffer_length_();
|
||||
}
|
||||
uint8_t *buffer = (uint8_t *) calloc(bufflen, sizeof(uint8_t));
|
||||
memset(buffer, 0xff, bufflen);
|
||||
|
||||
this->command(0x24);
|
||||
this->start_data_();
|
||||
this->write_array(buffer, this->get_buffer_length_());
|
||||
this->write_array(buffer, bufflen);
|
||||
this->end_data_();
|
||||
|
||||
this->command(0x26);
|
||||
this->start_data_();
|
||||
this->write_array(buffer, this->get_buffer_length_());
|
||||
this->write_array(buffer, bufflen);
|
||||
this->end_data_();
|
||||
|
||||
free(buffer);
|
||||
|
@ -77,7 +199,28 @@ void WaveshareEPaper4P2InV2::set_cursor_(uint16_t x, uint16_t y) {
|
|||
this->data((y >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::fast_initialize_() {
|
||||
void WaveshareEPaper4P2InV2::write_lut_() {
|
||||
this->command(0x32);
|
||||
this->start_data_();
|
||||
this->write_array(LUT_ALL, 227);
|
||||
this->end_data_();
|
||||
|
||||
this->command(0x3F);
|
||||
this->data(LUT_ALL[227]);
|
||||
|
||||
this->command(0x03);
|
||||
this->data(LUT_ALL[228]);
|
||||
|
||||
this->command(0x04);
|
||||
this->data(LUT_ALL[229]);
|
||||
this->data(LUT_ALL[230]);
|
||||
this->data(LUT_ALL[231]);
|
||||
|
||||
this->command(0x2c);
|
||||
this->data(LUT_ALL[232]);
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::initialize_internal_(TurnOnMode mode) {
|
||||
#define MODE_1_SECOND 1
|
||||
#define MODE_1_5_SECOND 0
|
||||
|
||||
|
@ -89,13 +232,22 @@ void WaveshareEPaper4P2InV2::fast_initialize_() {
|
|||
if (!this->wait_until_idle_()) {
|
||||
ESP_LOGW(TAG, "wait_until_idle_ returned FALSE. Is your busy pin set?");
|
||||
}
|
||||
|
||||
this->command(0x21);
|
||||
if (mode == MODE_GRAYSCALE4)
|
||||
this->data(0x00);
|
||||
else
|
||||
this->data(0x40);
|
||||
this->data(0x00);
|
||||
|
||||
|
||||
this->command(0x3C);
|
||||
if (mode == MODE_GRAYSCALE4)
|
||||
this->data(0x03);
|
||||
else
|
||||
this->data(0x05);
|
||||
|
||||
if (mode == MODE_FAST) {
|
||||
#if MODE_1_5_SECOND
|
||||
// 1.5s
|
||||
this->command(0x1A); // Write to temperature register
|
||||
|
@ -113,6 +265,16 @@ void WaveshareEPaper4P2InV2::fast_initialize_() {
|
|||
if (!this->wait_until_idle_()) {
|
||||
ESP_LOGW(TAG, "wait_until_idle_ returned FALSE. Is your busy pin set?");
|
||||
}
|
||||
} else if (mode == MODE_GRAYSCALE4) {
|
||||
this->command(0x0C);
|
||||
this->data(0x8B);
|
||||
this->data(0x9C);
|
||||
this->data(0xA4);
|
||||
this->data(0x0F);
|
||||
|
||||
this->write_lut_();
|
||||
}
|
||||
|
||||
this->command(0x11); // data entry mode
|
||||
this->data(0x03); // X-mode
|
||||
|
||||
|
@ -124,11 +286,22 @@ void WaveshareEPaper4P2InV2::fast_initialize_() {
|
|||
}
|
||||
|
||||
this->clear_();
|
||||
this->turn_on_display_full_();
|
||||
this->turn_on_display_(mode);
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::initialize() {
|
||||
this->fast_initialize_();
|
||||
if (this->initial_mode_ == MODE_PARTIAL)
|
||||
this->initialize_internal_(MODE_FULL);
|
||||
else
|
||||
this->initialize_internal_(this->initial_mode_);
|
||||
}
|
||||
|
||||
uint32_t WaveshareEPaper4P2InV2::idle_timeout_() {
|
||||
if (this->initial_mode_ == MODE_GRAYSCALE4) {
|
||||
return 1000;
|
||||
} else {
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::deep_sleep() {
|
||||
|
@ -154,5 +327,73 @@ void WaveshareEPaper4P2InV2::reset_() {
|
|||
delay(100);
|
||||
}
|
||||
|
||||
void HOT WaveshareEPaper4P2InV2::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 pos = (x + y * this->get_width_controller()) / 8u;
|
||||
const uint8_t subpos = x & 0x07;
|
||||
const uint32_t buf_half_len = this->get_buffer_length_() / 2u;
|
||||
|
||||
if (!color.is_on()) {
|
||||
if (this->initial_mode_ == MODE_GRAYSCALE4) {
|
||||
// flip logic
|
||||
this->buffer_[pos] &= ~(0x80 >> subpos);
|
||||
this->buffer_[pos + buf_half_len] &= ~(0x80 >> subpos);
|
||||
} else {
|
||||
this->buffer_[pos] &= ~(0x80 >> subpos);
|
||||
}
|
||||
} else {
|
||||
if (this->initial_mode_ == MODE_GRAYSCALE4) {
|
||||
|
||||
/****Color display description****
|
||||
white gray1 gray2 black
|
||||
0x10| 01 01 00 00
|
||||
0x13| 01 00 01 00
|
||||
*********************************/
|
||||
|
||||
if (((color.red > 0) || (color.green > 0) || (color.blue > 0))) {
|
||||
// draw gray pixels
|
||||
if ((color.red >= 0xc0) || (color.green >= 0xc0) || (color.blue >= 0xc0)) {
|
||||
// white
|
||||
this->buffer_[pos] |= 0x80 >> subpos;
|
||||
this->buffer_[pos + buf_half_len] |= 0x80 >> subpos;
|
||||
} else if ((color.red >= 0x80) || (color.green >= 0x80) || (color.blue >= 0x80)) {
|
||||
// gray 1
|
||||
this->buffer_[pos] &= ~(0x80 >> subpos);
|
||||
this->buffer_[pos + buf_half_len] |= 0x80 >> subpos;
|
||||
} else {
|
||||
// gray 2
|
||||
this->buffer_[pos] |= 0x80 >> subpos;
|
||||
this->buffer_[pos + buf_half_len] &= ~(0x80 >> subpos);
|
||||
}
|
||||
} else {
|
||||
// black
|
||||
this->buffer_[pos] &= ~(0x80 >> subpos);
|
||||
this->buffer_[pos + buf_half_len] &= ~(0x80 >> subpos);
|
||||
}
|
||||
} else {
|
||||
// flip logic
|
||||
if ((color.r > 0) || (color.g > 0) || (color.b > 0))
|
||||
this->buffer_[pos] &= ~(0x80 >> subpos);
|
||||
else
|
||||
this->buffer_[pos] |= (0x80 >> subpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WaveshareEPaper4P2InV2::dump_config() {
|
||||
LOG_DISPLAY("", "Waveshare E-Paper", this)
|
||||
ESP_LOGCONFIG(TAG, " Model: 4.20inV2");
|
||||
if (this->initial_mode_ == MODE_GRAYSCALE4)
|
||||
ESP_LOGCONFIG(TAG, " Initial Mode: 4 Grayscale");
|
||||
else if (this->initial_mode_ == MODE_FAST)
|
||||
ESP_LOGCONFIG(TAG, " Initial Mode: Fast");
|
||||
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)
|
||||
}
|
||||
|
||||
} // namespace waveshare_epaper
|
||||
} // namespace esphome
|
|
@ -3,29 +3,45 @@
|
|||
namespace esphome {
|
||||
namespace waveshare_epaper {
|
||||
|
||||
enum TurnOnMode {
|
||||
MODE_PARTIAL = 0,
|
||||
MODE_FULL,
|
||||
MODE_FAST,
|
||||
MODE_GRAYSCALE4
|
||||
};
|
||||
|
||||
class WaveshareEPaper4P2InV2 : public WaveshareEPaper {
|
||||
public:
|
||||
void dump_config() override;
|
||||
void display() override;
|
||||
void initialize() override;
|
||||
void deep_sleep() override;
|
||||
|
||||
void set_full_update_every(uint32_t full_update_every);
|
||||
void set_initial_mode(uint8_t mode) { this->initial_mode_ = (TurnOnMode)mode; }
|
||||
|
||||
protected:
|
||||
void fast_initialize_();
|
||||
void full_update_();
|
||||
void initialize_internal_(TurnOnMode mode);
|
||||
void update_(TurnOnMode mode);
|
||||
void turn_on_display_(TurnOnMode mode);
|
||||
|
||||
void write_lut_();
|
||||
|
||||
void reset_();
|
||||
void set_window_(uint16_t x, uint16_t y, uint16_t x1, uint16_t y2);
|
||||
void set_cursor_(uint16_t x, uint16_t y);
|
||||
void turn_on_display_full_();
|
||||
void clear_();
|
||||
|
||||
int get_width_internal() override;
|
||||
int get_height_internal() override;
|
||||
uint32_t get_buffer_length_() override;
|
||||
void draw_absolute_pixel_internal(int x, int y, Color color) override;
|
||||
uint32_t idle_timeout_() override;
|
||||
|
||||
uint32_t full_update_every_{30};
|
||||
uint32_t at_update_{0};
|
||||
bool is_busy_{false};
|
||||
TurnOnMode initial_mode_{MODE_FAST};
|
||||
};
|
||||
|
||||
} // namespace waveshare_epaper
|
||||
|
|
Loading…
Reference in a new issue