mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Support for ST7567 display 128x64 (I2C, SPI) (#5952)
This commit is contained in:
		
							
								
								
									
										55
									
								
								esphome/components/st7567_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								esphome/components/st7567_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import pins | ||||
| from esphome.components import display | ||||
| from esphome.const import ( | ||||
|     CONF_LAMBDA, | ||||
|     CONF_RESET_PIN, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@latonita"] | ||||
|  | ||||
| st7567_base_ns = cg.esphome_ns.namespace("st7567_base") | ||||
| ST7567 = st7567_base_ns.class_("ST7567", cg.PollingComponent, display.DisplayBuffer) | ||||
| ST7567Model = st7567_base_ns.enum("ST7567Model") | ||||
|  | ||||
| # todo in future: reuse following constants from const.py when they are released | ||||
| CONF_INVERT_COLORS = "invert_colors" | ||||
| CONF_TRANSFORM = "transform" | ||||
| CONF_MIRROR_X = "mirror_x" | ||||
| CONF_MIRROR_Y = "mirror_y" | ||||
|  | ||||
|  | ||||
| ST7567_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend( | ||||
|     { | ||||
|         cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||
|         cv.Optional(CONF_INVERT_COLORS, default=False): cv.boolean, | ||||
|         cv.Optional(CONF_TRANSFORM): cv.Schema( | ||||
|             { | ||||
|                 cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, | ||||
|                 cv.Optional(CONF_MIRROR_Y, default=False): cv.boolean, | ||||
|             } | ||||
|         ), | ||||
|     } | ||||
| ).extend(cv.polling_component_schema("1s")) | ||||
|  | ||||
|  | ||||
| async def setup_st7567(var, config): | ||||
|     await display.register_display(var, config) | ||||
|  | ||||
|     if CONF_RESET_PIN in config: | ||||
|         reset = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) | ||||
|         cg.add(var.set_reset_pin(reset)) | ||||
|  | ||||
|     cg.add(var.init_invert_colors(config[CONF_INVERT_COLORS])) | ||||
|  | ||||
|     if CONF_TRANSFORM in config: | ||||
|         transform = config[CONF_TRANSFORM] | ||||
|         cg.add(var.init_mirror_x(transform[CONF_MIRROR_X])) | ||||
|         cg.add(var.init_mirror_y(transform[CONF_MIRROR_Y])) | ||||
|  | ||||
|     if CONF_LAMBDA in config: | ||||
|         lambda_ = await cg.process_lambda( | ||||
|             config[CONF_LAMBDA], [(display.DisplayRef, "it")], return_type=cg.void | ||||
|         ) | ||||
|         cg.add(var.set_writer(lambda_)) | ||||
							
								
								
									
										152
									
								
								esphome/components/st7567_base/st7567_base.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								esphome/components/st7567_base/st7567_base.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,152 @@ | ||||
| #include "st7567_base.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/core/helpers.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace st7567_base { | ||||
|  | ||||
| static const char *const TAG = "st7567"; | ||||
|  | ||||
| void ST7567::setup() { | ||||
|   this->init_internal_(this->get_buffer_length_()); | ||||
|   this->display_init_(); | ||||
| } | ||||
|  | ||||
| void ST7567::display_init_() { | ||||
|   ESP_LOGD(TAG, "Initializing ST7567 display..."); | ||||
|   this->display_init_registers_(); | ||||
|   this->clear(); | ||||
|   this->write_display_data(); | ||||
|   this->command(ST7567_DISPLAY_ON); | ||||
| } | ||||
|  | ||||
| void ST7567::display_init_registers_() { | ||||
|   this->command(ST7567_BIAS_9); | ||||
|   this->command(this->mirror_x_ ? ST7567_SEG_REVERSE : ST7567_SEG_NORMAL); | ||||
|   this->command(this->mirror_y_ ? ST7567_COM_NORMAL : ST7567_COM_REMAP); | ||||
|   this->command(ST7567_POWER_CTL | 0x4); | ||||
|   this->command(ST7567_POWER_CTL | 0x6); | ||||
|   this->command(ST7567_POWER_CTL | 0x7); | ||||
|  | ||||
|   this->set_brightness(this->brightness_); | ||||
|   this->set_contrast(this->contrast_); | ||||
|  | ||||
|   this->command(ST7567_INVERT_OFF | this->invert_colors_); | ||||
|  | ||||
|   this->command(ST7567_BOOSTER_ON); | ||||
|   this->command(ST7567_REGULATOR_ON); | ||||
|   this->command(ST7567_POWER_ON); | ||||
|  | ||||
|   this->command(ST7567_SCAN_START_LINE); | ||||
|   this->command(ST7567_PIXELS_NORMAL | this->all_pixels_on_); | ||||
| } | ||||
|  | ||||
| void ST7567::display_sw_refresh_() { | ||||
|   ESP_LOGD(TAG, "Performing refresh sequence..."); | ||||
|   this->command(ST7567_SW_REFRESH); | ||||
|   this->display_init_registers_(); | ||||
| } | ||||
|  | ||||
| void ST7567::request_refresh() { | ||||
|   // as per datasheet: It is recommended to use the refresh sequence regularly in a specified interval. | ||||
|   this->refresh_requested_ = true; | ||||
| } | ||||
|  | ||||
| void ST7567::update() { | ||||
|   this->do_update_(); | ||||
|   if (this->refresh_requested_) { | ||||
|     this->refresh_requested_ = false; | ||||
|     this->display_sw_refresh_(); | ||||
|   } | ||||
|   this->write_display_data(); | ||||
| } | ||||
|  | ||||
| void ST7567::set_all_pixels_on(bool enable) { | ||||
|   this->all_pixels_on_ = enable; | ||||
|   this->command(ST7567_PIXELS_NORMAL | this->all_pixels_on_); | ||||
| } | ||||
|  | ||||
| void ST7567::set_invert_colors(bool invert_colors) { | ||||
|   this->invert_colors_ = invert_colors; | ||||
|   this->command(ST7567_INVERT_OFF | this->invert_colors_); | ||||
| } | ||||
|  | ||||
| void ST7567::set_contrast(uint8_t val) { | ||||
|   this->contrast_ = val & 0b111111; | ||||
|   // 0..63, 26 is normal | ||||
|  | ||||
|   // two byte command | ||||
|   // first byte 0x81 | ||||
|   // second byte 0-63 | ||||
|  | ||||
|   this->command(ST7567_SET_EV_CMD); | ||||
|   this->command(this->contrast_); | ||||
| } | ||||
|  | ||||
| void ST7567::set_brightness(uint8_t val) { | ||||
|   this->brightness_ = val & 0b111; | ||||
|   // 0..7, 5 normal | ||||
|  | ||||
|   //********Adjust display brightness******** | ||||
|   // 0x20-0x27 is the internal Rb/Ra resistance | ||||
|   // adjustment setting of V5 voltage RR=4.5V | ||||
|  | ||||
|   this->command(ST7567_RESISTOR_RATIO | this->brightness_); | ||||
| } | ||||
|  | ||||
| bool ST7567::is_on() { return this->is_on_; } | ||||
|  | ||||
| void ST7567::turn_on() { | ||||
|   this->command(ST7567_DISPLAY_ON); | ||||
|   this->is_on_ = true; | ||||
| } | ||||
|  | ||||
| void ST7567::turn_off() { | ||||
|   this->command(ST7567_DISPLAY_OFF); | ||||
|   this->is_on_ = false; | ||||
| } | ||||
|  | ||||
| void ST7567::set_scroll(uint8_t line) { this->start_line_ = line % this->get_height_internal(); } | ||||
|  | ||||
| int ST7567::get_width_internal() { return 128; } | ||||
|  | ||||
| int ST7567::get_height_internal() { return 64; } | ||||
|  | ||||
| // 128x64, but memory size 132x64, line starts from 0, but if mirrored then it starts from 131, not 127 | ||||
| size_t ST7567::get_buffer_length_() { | ||||
|   return size_t(this->get_width_internal() + 4) * size_t(this->get_height_internal()) / 8u; | ||||
| } | ||||
|  | ||||
| void HOT ST7567::draw_absolute_pixel_internal(int x, int y, Color color) { | ||||
|   if (x >= this->get_width_internal() || x < 0 || y >= this->get_height_internal() || y < 0) { | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   uint16_t pos = x + (y / 8) * this->get_width_internal(); | ||||
|   uint8_t subpos = y & 0x07; | ||||
|   if (color.is_on()) { | ||||
|     this->buffer_[pos] |= (1 << subpos); | ||||
|   } else { | ||||
|     this->buffer_[pos] &= ~(1 << subpos); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void ST7567::fill(Color color) { memset(buffer_, color.is_on() ? 0xFF : 0x00, this->get_buffer_length_()); } | ||||
|  | ||||
| void ST7567::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); | ||||
|   } | ||||
| } | ||||
|  | ||||
| const char *ST7567::model_str_() { return "ST7567 128x64"; } | ||||
|  | ||||
| }  // namespace st7567_base | ||||
| }  // namespace esphome | ||||
							
								
								
									
										100
									
								
								esphome/components/st7567_base/st7567_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								esphome/components/st7567_base/st7567_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/components/display/display_buffer.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace st7567_base { | ||||
|  | ||||
| static const uint8_t ST7567_BOOSTER_ON = 0x2C;    // internal power supply on | ||||
| static const uint8_t ST7567_REGULATOR_ON = 0x2E;  // internal power supply on | ||||
| static const uint8_t ST7567_POWER_ON = 0x2F;      // internal power supply on | ||||
|  | ||||
| static const uint8_t ST7567_DISPLAY_ON = 0xAF;   // Display ON. Normal Display Mode. | ||||
| static const uint8_t ST7567_DISPLAY_OFF = 0xAE;  // Display OFF. All SEGs/COMs output with VSS | ||||
| static const uint8_t ST7567_SET_START_LINE = 0x40; | ||||
| static const uint8_t ST7567_POWER_CTL = 0x28; | ||||
| static const uint8_t ST7567_SEG_NORMAL = 0xA0;       // | ||||
| static const uint8_t ST7567_SEG_REVERSE = 0xA1;      // mirror X axis (horizontal) | ||||
| static const uint8_t ST7567_COM_NORMAL = 0xC0;       // | ||||
| static const uint8_t ST7567_COM_REMAP = 0xC8;        // mirror Y axis (vertical) | ||||
| static const uint8_t ST7567_PIXELS_NORMAL = 0xA4;    // display ram content | ||||
| static const uint8_t ST7567_PIXELS_ALL_ON = 0xA5;    // all pixels on | ||||
| static const uint8_t ST7567_INVERT_OFF = 0xA6;       // normal pixels | ||||
| static const uint8_t ST7567_INVERT_ON = 0xA7;        // inverted pixels | ||||
| static const uint8_t ST7567_SCAN_START_LINE = 0x40;  // scrolling = 0x40 + (0..63) | ||||
| static const uint8_t ST7567_COL_ADDR_H = 0x10;       // x pos (0..95) 4 MSB | ||||
| static const uint8_t ST7567_COL_ADDR_L = 0x00;       // x pos (0..95) 4 LSB | ||||
| static const uint8_t ST7567_PAGE_ADDR = 0xB0;        // y pos, 8.5 rows (0..8) | ||||
| static const uint8_t ST7567_BIAS_9 = 0xA2; | ||||
| static const uint8_t ST7567_CONTRAST = 0x80;  // 0x80 + (0..31) | ||||
| static const uint8_t ST7567_SET_EV_CMD = 0x81; | ||||
| static const uint8_t ST7567_SET_EV_PARAM = 0x00; | ||||
| static const uint8_t ST7567_RESISTOR_RATIO = 0x20; | ||||
| static const uint8_t ST7567_SW_REFRESH = 0xE2; | ||||
|  | ||||
| class ST7567 : public display::DisplayBuffer { | ||||
|  public: | ||||
|   void setup() override; | ||||
|  | ||||
|   void update() override; | ||||
|  | ||||
|   void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; } | ||||
|   void init_mirror_x(bool mirror_x) { this->mirror_x_ = mirror_x; } | ||||
|   void init_mirror_y(bool mirror_y) { this->mirror_y_ = mirror_y; } | ||||
|   void init_invert_colors(bool invert_colors) { this->invert_colors_ = invert_colors; } | ||||
|  | ||||
|   void set_invert_colors(bool invert_colors);  // inversion of screen colors | ||||
|   void set_contrast(uint8_t val);              // 0..63, 27-30 normal | ||||
|   void set_brightness(uint8_t val);            // 0..7, 5 normal | ||||
|   void set_all_pixels_on(bool enable);         // turn on all pixels, this doesn't affect RAM | ||||
|   void set_scroll(uint8_t line);               // set display start line: for screen scrolling w/o affecting RAM | ||||
|  | ||||
|   bool is_on(); | ||||
|   void turn_on(); | ||||
|   void turn_off(); | ||||
|  | ||||
|   void request_refresh();  // from datasheet: It is recommended to use the refresh sequence regularly in a specified | ||||
|                            // interval. | ||||
|  | ||||
|   float get_setup_priority() const override { return setup_priority::PROCESSOR; } | ||||
|   void fill(Color color) override; | ||||
|  | ||||
|   display::DisplayType get_display_type() override { return display::DisplayType::DISPLAY_TYPE_BINARY; } | ||||
|  | ||||
|  protected: | ||||
|   virtual void command(uint8_t value) = 0; | ||||
|   virtual void write_display_data() = 0; | ||||
|  | ||||
|   void init_reset_(); | ||||
|   void display_init_(); | ||||
|   void display_init_registers_(); | ||||
|   void display_sw_refresh_(); | ||||
|  | ||||
|   void draw_absolute_pixel_internal(int x, int y, Color color) override; | ||||
|  | ||||
|   int get_height_internal() override; | ||||
|   int get_width_internal() override; | ||||
|   size_t get_buffer_length_(); | ||||
|  | ||||
|   int get_offset_x_() { return mirror_x_ ? 4 : 0; }; | ||||
|  | ||||
|   const char *model_str_(); | ||||
|  | ||||
|   GPIOPin *reset_pin_{nullptr}; | ||||
|   bool is_on_{false}; | ||||
|   // float contrast_{1.0}; | ||||
|   // float brightness_{1.0}; | ||||
|   uint8_t contrast_{27}; | ||||
|   uint8_t brightness_{5}; | ||||
|   bool mirror_x_{true}; | ||||
|   bool mirror_y_{true}; | ||||
|   bool invert_colors_{false}; | ||||
|   bool all_pixels_on_{false}; | ||||
|   uint8_t start_line_{0}; | ||||
|   bool refresh_requested_{false}; | ||||
| }; | ||||
|  | ||||
| }  // namespace st7567_base | ||||
| }  // namespace esphome | ||||
							
								
								
									
										1
									
								
								esphome/components/st7567_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/st7567_i2c/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| CODEOWNERS = ["@latonita"] | ||||
							
								
								
									
										29
									
								
								esphome/components/st7567_i2c/display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								esphome/components/st7567_i2c/display.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import st7567_base, i2c | ||||
| from esphome.const import CONF_ID, CONF_LAMBDA, CONF_PAGES | ||||
|  | ||||
| CODEOWNERS = ["@latonita"] | ||||
|  | ||||
| AUTO_LOAD = ["st7567_base"] | ||||
| DEPENDENCIES = ["i2c"] | ||||
|  | ||||
| st7567_i2c = cg.esphome_ns.namespace("st7567_i2c") | ||||
| I2CST7567 = st7567_i2c.class_("I2CST7567", st7567_base.ST7567, i2c.I2CDevice) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     st7567_base.ST7567_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(I2CST7567), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
|     .extend(i2c.i2c_device_schema(0x3F)), | ||||
|     cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await st7567_base.setup_st7567(var, config) | ||||
|     await i2c.register_i2c_device(var, config) | ||||
							
								
								
									
										60
									
								
								esphome/components/st7567_i2c/st7567_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								esphome/components/st7567_i2c/st7567_i2c.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| #include "st7567_i2c.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace st7567_i2c { | ||||
|  | ||||
| static const char *const TAG = "st7567_i2c"; | ||||
|  | ||||
| void I2CST7567::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up I2C ST7567 display..."); | ||||
|   this->init_reset_(); | ||||
|  | ||||
|   auto err = this->write(nullptr, 0); | ||||
|   if (err != i2c::ERROR_OK) { | ||||
|     this->error_code_ = COMMUNICATION_FAILED; | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   ST7567::setup(); | ||||
| } | ||||
|  | ||||
| void I2CST7567::dump_config() { | ||||
|   LOG_DISPLAY("", "I2CST7567", this); | ||||
|   LOG_I2C_DEVICE(this); | ||||
|   ESP_LOGCONFIG(TAG, "  Model: %s", this->model_str_()); | ||||
|   LOG_PIN("  Reset Pin: ", this->reset_pin_); | ||||
|   ESP_LOGCONFIG(TAG, "  Mirror X: %s", YESNO(this->mirror_x_)); | ||||
|   ESP_LOGCONFIG(TAG, "  Mirror Y: %s", YESNO(this->mirror_y_)); | ||||
|   ESP_LOGCONFIG(TAG, "  Invert Colors: %s", YESNO(this->invert_colors_)); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
|  | ||||
|   if (this->error_code_ == COMMUNICATION_FAILED) { | ||||
|     ESP_LOGE(TAG, "Communication with I2C ST7567 failed!"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void I2CST7567::command(uint8_t value) { this->write_byte(0x00, value); } | ||||
|  | ||||
| void HOT I2CST7567::write_display_data() { | ||||
|   // ST7567A has built-in RAM with 132x65 bit capacity which stores the display data. | ||||
|   // but only first 128 pixels from each line are shown on screen | ||||
|   // if screen got flipped horizontally then it shows last 128 pixels, | ||||
|   // so we need to write x coordinate starting from column 4, not column 0 | ||||
|   this->command(esphome::st7567_base::ST7567_SET_START_LINE + this->start_line_); | ||||
|   for (uint8_t y = 0; y < (uint8_t) this->get_height_internal() / 8; y++) { | ||||
|     this->command(esphome::st7567_base::ST7567_PAGE_ADDR + y);                       // Set Page | ||||
|     this->command(esphome::st7567_base::ST7567_COL_ADDR_H);                          // Set MSB Column address | ||||
|     this->command(esphome::st7567_base::ST7567_COL_ADDR_L + this->get_offset_x_());  // Set LSB Column address | ||||
|  | ||||
|     static const size_t BLOCK_SIZE = 64; | ||||
|     for (uint8_t x = 0; x < (uint8_t) this->get_width_internal(); x += BLOCK_SIZE) { | ||||
|       this->write_register(esphome::st7567_base::ST7567_SET_START_LINE, &buffer_[y * this->get_width_internal() + x], | ||||
|                            this->get_width_internal() - x > BLOCK_SIZE ? BLOCK_SIZE : this->get_width_internal() - x, | ||||
|                            true); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace st7567_i2c | ||||
| }  // namespace esphome | ||||
							
								
								
									
										23
									
								
								esphome/components/st7567_i2c/st7567_i2c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/st7567_i2c/st7567_i2c.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/st7567_base/st7567_base.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace st7567_i2c { | ||||
|  | ||||
| class I2CST7567 : public st7567_base::ST7567, public i2c::I2CDevice { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|  | ||||
|  protected: | ||||
|   void command(uint8_t value) override; | ||||
|   void write_display_data() override; | ||||
|  | ||||
|   enum ErrorCode { NONE = 0, COMMUNICATION_FAILED } error_code_{NONE}; | ||||
| }; | ||||
|  | ||||
| }  // namespace st7567_i2c | ||||
| }  // namespace esphome | ||||
							
								
								
									
										1
									
								
								esphome/components/st7567_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/st7567_spi/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| CODEOWNERS = ["@latonita"] | ||||
							
								
								
									
										34
									
								
								esphome/components/st7567_spi/display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								esphome/components/st7567_spi/display.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome import pins | ||||
| from esphome.components import spi, st7567_base | ||||
| from esphome.const import CONF_DC_PIN, CONF_ID, CONF_LAMBDA, CONF_PAGES | ||||
|  | ||||
| CODEOWNERS = ["@latonita"] | ||||
|  | ||||
| AUTO_LOAD = ["st7567_base"] | ||||
| DEPENDENCIES = ["spi"] | ||||
|  | ||||
| st7567_spi = cg.esphome_ns.namespace("st7567_spi") | ||||
| SPIST7567 = st7567_spi.class_("SPIST7567", st7567_base.ST7567, spi.SPIDevice) | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     st7567_base.ST7567_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(SPIST7567), | ||||
|             cv.Required(CONF_DC_PIN): pins.gpio_output_pin_schema, | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.COMPONENT_SCHEMA) | ||||
|     .extend(spi.spi_device_schema()), | ||||
|     cv.has_at_most_one_key(CONF_PAGES, CONF_LAMBDA), | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await st7567_base.setup_st7567(var, config) | ||||
|     await spi.register_spi_device(var, config) | ||||
|  | ||||
|     dc = await cg.gpio_pin_expression(config[CONF_DC_PIN]) | ||||
|     cg.add(var.set_dc_pin(dc)) | ||||
							
								
								
									
										66
									
								
								esphome/components/st7567_spi/st7567_spi.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								esphome/components/st7567_spi/st7567_spi.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| #include "st7567_spi.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace st7567_spi { | ||||
|  | ||||
| static const char *const TAG = "st7567_spi"; | ||||
|  | ||||
| void SPIST7567::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up SPI ST7567 display..."); | ||||
|   this->spi_setup(); | ||||
|   this->dc_pin_->setup(); | ||||
|   if (this->cs_) | ||||
|     this->cs_->setup(); | ||||
|  | ||||
|   this->init_reset_(); | ||||
|   ST7567::setup(); | ||||
| } | ||||
|  | ||||
| void SPIST7567::dump_config() { | ||||
|   LOG_DISPLAY("", "SPI ST7567", this); | ||||
|   ESP_LOGCONFIG(TAG, "  Model: %s", this->model_str_()); | ||||
|   LOG_PIN("  CS Pin: ", this->cs_); | ||||
|   LOG_PIN("  DC Pin: ", this->dc_pin_); | ||||
|   LOG_PIN("  Reset Pin: ", this->reset_pin_); | ||||
|   ESP_LOGCONFIG(TAG, "  Mirror X: %s", YESNO(this->mirror_x_)); | ||||
|   ESP_LOGCONFIG(TAG, "  Mirror Y: %s", YESNO(this->mirror_y_)); | ||||
|   ESP_LOGCONFIG(TAG, "  Invert Colors: %s", YESNO(this->invert_colors_)); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
| } | ||||
|  | ||||
| void SPIST7567::command(uint8_t value) { | ||||
|   if (this->cs_) | ||||
|     this->cs_->digital_write(true); | ||||
|   this->dc_pin_->digital_write(false); | ||||
|   delay(1); | ||||
|   this->enable(); | ||||
|   if (this->cs_) | ||||
|     this->cs_->digital_write(false); | ||||
|   this->write_byte(value); | ||||
|   if (this->cs_) | ||||
|     this->cs_->digital_write(true); | ||||
|   this->disable(); | ||||
| } | ||||
|  | ||||
| void HOT SPIST7567::write_display_data() { | ||||
|   // ST7567A has built-in RAM with 132x65 bit capacity which stores the display data. | ||||
|   // but only first 128 pixels from each line are shown on screen | ||||
|   // if screen got flipped horizontally then it shows last 128 pixels, | ||||
|   // so we need to write x coordinate starting from column 4, not column 0 | ||||
|   this->command(esphome::st7567_base::ST7567_SET_START_LINE + this->start_line_); | ||||
|   for (uint8_t y = 0; y < (uint8_t) this->get_height_internal() / 8; y++) { | ||||
|     this->dc_pin_->digital_write(false); | ||||
|     this->command(esphome::st7567_base::ST7567_PAGE_ADDR + y);                       // Set Page | ||||
|     this->command(esphome::st7567_base::ST7567_COL_ADDR_H);                          // Set MSB Column address | ||||
|     this->command(esphome::st7567_base::ST7567_COL_ADDR_L + this->get_offset_x_());  // Set LSB Column address | ||||
|     this->dc_pin_->digital_write(true); | ||||
|  | ||||
|     this->enable(); | ||||
|     this->write_array(&this->buffer_[y * this->get_width_internal()], this->get_width_internal()); | ||||
|     this->disable(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace st7567_spi | ||||
| }  // namespace esphome | ||||
							
								
								
									
										29
									
								
								esphome/components/st7567_spi/st7567_spi.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								esphome/components/st7567_spi/st7567_spi.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/st7567_base/st7567_base.h" | ||||
| #include "esphome/components/spi/spi.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace st7567_spi { | ||||
|  | ||||
| class SPIST7567 : public st7567_base::ST7567, | ||||
|                   public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_HIGH, spi::CLOCK_PHASE_TRAILING, | ||||
|                                         spi::DATA_RATE_8MHZ> { | ||||
|  public: | ||||
|   void set_dc_pin(GPIOPin *dc_pin) { dc_pin_ = dc_pin; } | ||||
|  | ||||
|   void setup() override; | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
|  protected: | ||||
|   void command(uint8_t value) override; | ||||
|  | ||||
|   void write_display_data() override; | ||||
|  | ||||
|   GPIOPin *dc_pin_; | ||||
| }; | ||||
|  | ||||
| }  // namespace st7567_spi | ||||
| }  // namespace esphome | ||||
		Reference in New Issue
	
	Block a user