From 4620ad612432a45d01a1cee7dffb249a3ef3f32b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Biernacki?= Date: Sat, 4 Apr 2020 23:23:23 +0200 Subject: [PATCH] Support for pcd8544 (nokia 5110 and 3310) screen (#973) * First version of working compontent for pc8544 screen * Fixed lint errors * Fixed lint errors #2 --- esphome/components/pcd8544/__init__.py | 0 esphome/components/pcd8544/display.py | 39 ++++++++ esphome/components/pcd8544/pcd_8544.cpp | 127 ++++++++++++++++++++++++ esphome/components/pcd8544/pcd_8544.h | 75 ++++++++++++++ tests/test1.yaml | 6 ++ 5 files changed, 247 insertions(+) create mode 100644 esphome/components/pcd8544/__init__.py create mode 100644 esphome/components/pcd8544/display.py create mode 100644 esphome/components/pcd8544/pcd_8544.cpp create mode 100644 esphome/components/pcd8544/pcd_8544.h diff --git a/esphome/components/pcd8544/__init__.py b/esphome/components/pcd8544/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/esphome/components/pcd8544/display.py b/esphome/components/pcd8544/display.py new file mode 100644 index 0000000000..e47937e46a --- /dev/null +++ b/esphome/components/pcd8544/display.py @@ -0,0 +1,39 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome import pins +from esphome.components import display, spi +from esphome.const import ( + CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES, CONF_RESET_PIN, CONF_CS_PIN, +) + +DEPENDENCIES = ['spi'] + +pcd8544_ns = cg.esphome_ns.namespace('pcd8544') +PCD8544 = pcd8544_ns.class_('PCD8544', cg.PollingComponent, display.DisplayBuffer, spi.SPIDevice) + + +CONFIG_SCHEMA = cv.All(display.FULL_DISPLAY_SCHEMA.extend({ + cv.GenerateID(): cv.declare_id(PCD8544), + cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_RESET_PIN): pins.gpio_output_pin_schema, + cv.Required(CONF_CS_PIN): pins.gpio_output_pin_schema, # CE +}).extend(cv.polling_component_schema('1s')).extend(spi.SPI_DEVICE_SCHEMA), + cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA)) + + +def to_code(config): + var = cg.new_Pvariable(config[CONF_ID]) + + yield cg.register_component(var, config) + yield display.register_display(var, config) + yield spi.register_spi_device(var, config) + + dc = yield cg.gpio_pin_expression(config[CONF_DC_PIN]) + cg.add(var.set_dc_pin(dc)) + reset = yield cg.gpio_pin_expression(config[CONF_RESET_PIN]) + cg.add(var.set_reset_pin(reset)) + + if CONF_LAMBDA in config: + lambda_ = yield cg.process_lambda(config[CONF_LAMBDA], [(display.DisplayBufferRef, 'it')], + return_type=cg.void) + cg.add(var.set_writer(lambda_)) diff --git a/esphome/components/pcd8544/pcd_8544.cpp b/esphome/components/pcd8544/pcd_8544.cpp new file mode 100644 index 0000000000..ed9d1bbd43 --- /dev/null +++ b/esphome/components/pcd8544/pcd_8544.cpp @@ -0,0 +1,127 @@ +#include "pcd_8544.h" +#include "esphome/core/log.h" +#include "esphome/core/application.h" +#include "esphome/core/helpers.h" + +namespace esphome { +namespace pcd8544 { + +static const char *TAG = "pcd_8544"; + +void PCD8544::setup_pins_() { + this->spi_setup(); + this->init_reset_(); + this->dc_pin_->setup(); +} + +void PCD8544::init_reset_() { + if (this->reset_pin_ != nullptr) { + this->reset_pin_->setup(); + this->reset_pin_->digital_write(true); + delay(1); + // Trigger Reset + this->reset_pin_->digital_write(false); + delay(10); + // Wake up + this->reset_pin_->digital_write(true); + } +} + +void PCD8544::initialize() { + this->init_internal_(this->get_buffer_length_()); + + this->command(this->PCD8544_FUNCTIONSET | this->PCD8544_EXTENDEDINSTRUCTION); + // LCD bias select (4 is optimal?) + this->command(this->PCD8544_SETBIAS | 0x04); + + // contrast + // TODO: in future version we may add a user a control over contrast + this->command(this->PCD8544_SETVOP | 0x7f); // Experimentally determined + + // normal mode + this->command(this->PCD8544_FUNCTIONSET); + + // Set display to Normal + this->command(this->PCD8544_DISPLAYCONTROL | this->PCD8544_DISPLAYNORMAL); +} + +void PCD8544::start_command_() { + this->dc_pin_->digital_write(false); + this->enable(); +} +void PCD8544::end_command_() { this->disable(); } +void PCD8544::start_data_() { + this->dc_pin_->digital_write(true); + this->enable(); +} +void PCD8544::end_data_() { this->disable(); } + +int PCD8544::get_width_internal() { return 84; } +int PCD8544::get_height_internal() { return 48; } + +size_t PCD8544::get_buffer_length_() { + return size_t(this->get_width_internal()) * size_t(this->get_height_internal()) / 8u; +} + +void HOT PCD8544::display() { + uint8_t col, maxcol, p; + + for (p = 0; p < 6; p++) { + this->command(this->PCD8544_SETYADDR | p); + + // start at the beginning of the row + col = 0; + maxcol = this->get_width_internal() - 1; + + this->command(this->PCD8544_SETXADDR | col); + + this->start_data_(); + for (; col <= maxcol; col++) { + this->write_byte(this->buffer_[(this->get_width_internal() * p) + col]); + } + this->end_data_(); + } + + this->command(this->PCD8544_SETYADDR); +} + +void HOT PCD8544::draw_absolute_pixel_internal(int x, int y, int color) { + if (x >= this->get_width_internal() || y >= this->get_height_internal() || x < 0 || y < 0) { + return; + } + + uint16_t pos = x + (y / 8) * this->get_width_internal(); + uint8_t subpos = y % 8; + if (color) { + this->buffer_[pos] |= (1 << subpos); + } else { + this->buffer_[pos] &= ~(1 << subpos); + } +} + +void PCD8544::dump_config() { + LOG_DISPLAY("", "PCD8544", this); + LOG_PIN(" DC Pin: ", this->dc_pin_); + LOG_PIN(" Reset Pin: ", this->reset_pin_); + LOG_UPDATE_INTERVAL(this); +} + +void PCD8544::command(uint8_t value) { + this->start_command_(); + this->write_byte(value); + this->end_command_(); +} + +void PCD8544::update() { + this->do_update_(); + this->display(); +} + +void PCD8544::fill(int color) { + uint8_t fill = color ? 0xFF : 0x00; + for (uint32_t i = 0; i < this->get_buffer_length_(); i++) + this->buffer_[i] = fill; +} + +} // namespace pcd8544 +} // namespace esphome diff --git a/esphome/components/pcd8544/pcd_8544.h b/esphome/components/pcd8544/pcd_8544.h new file mode 100644 index 0000000000..a1c247bf7b --- /dev/null +++ b/esphome/components/pcd8544/pcd_8544.h @@ -0,0 +1,75 @@ +#pragma once + +#include "esphome/core/component.h" +#include "esphome/components/spi/spi.h" +#include "esphome/components/display/display_buffer.h" + +namespace esphome { +namespace pcd8544 { + +class PCD8544 : public PollingComponent, + public display::DisplayBuffer, + public spi::SPIDevice { + public: + const uint8_t PCD8544_POWERDOWN = 0x04; + const uint8_t PCD8544_ENTRYMODE = 0x02; + const uint8_t PCD8544_EXTENDEDINSTRUCTION = 0x01; + + const uint8_t PCD8544_DISPLAYBLANK = 0x0; + const uint8_t PCD8544_DISPLAYNORMAL = 0x4; + const uint8_t PCD8544_DISPLAYALLON = 0x1; + const uint8_t PCD8544_DISPLAYINVERTED = 0x5; + + const uint8_t PCD8544_FUNCTIONSET = 0x20; + const uint8_t PCD8544_DISPLAYCONTROL = 0x08; + const uint8_t PCD8544_SETYADDR = 0x40; + const uint8_t PCD8544_SETXADDR = 0x80; + + const uint8_t PCD8544_SETTEMP = 0x04; + const uint8_t PCD8544_SETBIAS = 0x10; + const uint8_t PCD8544_SETVOP = 0x80; + + void set_dc_pin(GPIOPin *dc_pin) { this->dc_pin_ = dc_pin; } + void set_reset_pin(GPIOPin *reset) { this->reset_pin_ = reset; } + float get_setup_priority() const override { return setup_priority::PROCESSOR; } + + void command(uint8_t value); + void data(uint8_t value); + + void initialize(); + void dump_config() override; + void HOT display(); + + void update() override; + + void fill(int color) override; + + void setup() override { + this->setup_pins_(); + this->initialize(); + } + + protected: + void draw_absolute_pixel_internal(int x, int y, int color) override; + + void setup_pins_(); + + void init_reset_(); + + size_t get_buffer_length_(); + + void start_command_(); + void end_command_(); + void start_data_(); + void end_data_(); + + int get_width_internal() override; + int get_height_internal() override; + + GPIOPin *reset_pin_; + GPIOPin *dc_pin_; +}; + +} // namespace pcd8544 +} // namespace esphome diff --git a/tests/test1.yaml b/tests/test1.yaml index 9102873fb6..1fc6b650c4 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -1444,6 +1444,12 @@ display: lambda: |- it.set_component_value("gauge", 50); it.set_component_text("textview", "Hello World!"); +- platform: pcd8544 + cs_pin: GPIO23 + dc_pin: GPIO23 + reset_pin: GPIO23 + lambda: |- + it.rectangle(0, 0, it.get_width(), it.get_height()); - platform: ssd1306_i2c model: "SSD1306_128X64" reset_pin: GPIO23