mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-20 18:53:47 +01:00 
			
		
		
		
	Touchscreen: add support for CST226 controller chip (#6151)
--------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -81,6 +81,7 @@ esphome/components/copy/* @OttoWinter | ||||
| esphome/components/cover/* @esphome/core | ||||
| esphome/components/cs5460a/* @balrog-kun | ||||
| esphome/components/cse7761/* @berfenger | ||||
| esphome/components/cst226/* @clydebarrow | ||||
| esphome/components/cst816/* @clydebarrow | ||||
| esphome/components/ct_clamp/* @jesserockz | ||||
| esphome/components/current_based/* @djwmarcx | ||||
|   | ||||
							
								
								
									
										6
									
								
								esphome/components/cst226/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								esphome/components/cst226/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| import esphome.codegen as cg | ||||
|  | ||||
| CODEOWNERS = ["@clydebarrow"] | ||||
| DEPENDENCIES = ["i2c"] | ||||
|  | ||||
| cst226_ns = cg.esphome_ns.namespace("cst226") | ||||
							
								
								
									
										38
									
								
								esphome/components/cst226/touchscreen/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								esphome/components/cst226/touchscreen/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
|  | ||||
| from esphome import pins | ||||
| from esphome.components import i2c, touchscreen | ||||
| from esphome.const import CONF_INTERRUPT_PIN, CONF_ID, CONF_RESET_PIN | ||||
| from .. import cst226_ns | ||||
|  | ||||
|  | ||||
| CST226Touchscreen = cst226_ns.class_( | ||||
|     "CST226Touchscreen", | ||||
|     touchscreen.Touchscreen, | ||||
|     i2c.I2CDevice, | ||||
| ) | ||||
|  | ||||
| CST226ButtonListener = cst226_ns.class_("CST226ButtonListener") | ||||
| CONFIG_SCHEMA = ( | ||||
|     touchscreen.touchscreen_schema("100ms") | ||||
|     .extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(CST226Touchscreen), | ||||
|             cv.Optional(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, | ||||
|             cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||||
|         } | ||||
|     ) | ||||
|     .extend(i2c.i2c_device_schema(0x5A)) | ||||
| ) | ||||
|  | ||||
|  | ||||
| async def to_code(config): | ||||
|     var = cg.new_Pvariable(config[CONF_ID]) | ||||
|     await touchscreen.register_touchscreen(var, config) | ||||
|     await i2c.register_i2c_device(var, config) | ||||
|  | ||||
|     if interrupt_pin := config.get(CONF_INTERRUPT_PIN): | ||||
|         cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) | ||||
|     if reset_pin := config.get(CONF_RESET_PIN): | ||||
|         cg.add(var.set_reset_pin(await cg.gpio_pin_expression(reset_pin))) | ||||
							
								
								
									
										92
									
								
								esphome/components/cst226/touchscreen/cst226_touchscreen.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								esphome/components/cst226/touchscreen/cst226_touchscreen.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| #include "cst226_touchscreen.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace cst226 { | ||||
|  | ||||
| void CST226Touchscreen::setup() { | ||||
|   esph_log_config(TAG, "Setting up CST226 Touchscreen..."); | ||||
|   if (this->reset_pin_ != nullptr) { | ||||
|     this->reset_pin_->setup(); | ||||
|     this->reset_pin_->digital_write(true); | ||||
|     delay(5); | ||||
|     this->reset_pin_->digital_write(false); | ||||
|     delay(5); | ||||
|     this->reset_pin_->digital_write(true); | ||||
|     this->set_timeout(30, [this] { this->continue_setup_(); }); | ||||
|   } else { | ||||
|     this->continue_setup_(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void CST226Touchscreen::update_touches() { | ||||
|   uint8_t data[28]; | ||||
|   if (!this->read_bytes(CST226_REG_STATUS, data, sizeof data)) { | ||||
|     this->status_set_warning(); | ||||
|     this->skip_update_ = true; | ||||
|     return; | ||||
|   } | ||||
|   this->status_clear_warning(); | ||||
|   if (data[6] != 0xAB || data[0] == 0xAB || data[5] == 0x80) { | ||||
|     this->skip_update_ = true; | ||||
|     return; | ||||
|   } | ||||
|   uint8_t num_of_touches = data[5] & 0x7F; | ||||
|   if (num_of_touches == 0 || num_of_touches > 5) { | ||||
|     this->write_byte(0, 0xAB); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   size_t index = 0; | ||||
|   for (uint8_t i = 0; i != num_of_touches; i++) { | ||||
|     uint8_t id = data[index] >> 4; | ||||
|     int16_t x = (data[index + 1] << 4) | ((data[index + 3] >> 4) & 0x0F); | ||||
|     int16_t y = (data[index + 2] << 4) | (data[index + 3] & 0x0F); | ||||
|     int16_t z = data[index + 4]; | ||||
|     this->add_raw_touch_position_(id, x, y, z); | ||||
|     esph_log_v(TAG, "Read touch %d: %d/%d", id, x, y); | ||||
|     index += 5; | ||||
|     if (i == 0) | ||||
|       index += 2; | ||||
|   } | ||||
| } | ||||
|  | ||||
| void CST226Touchscreen::continue_setup_() { | ||||
|   uint8_t buffer[8]; | ||||
|   if (this->interrupt_pin_ != nullptr) { | ||||
|     this->interrupt_pin_->setup(); | ||||
|     this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE); | ||||
|   } | ||||
|   buffer[0] = 0xD1; | ||||
|   if (this->write_register16(0xD1, buffer, 1) != i2c::ERROR_OK) { | ||||
|     esph_log_e(TAG, "Write byte to 0xD1 failed"); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   delay(10); | ||||
|   if (this->read16_(0xD204, buffer, 4)) { | ||||
|     uint16_t chip_id = buffer[2] + (buffer[3] << 8); | ||||
|     uint16_t project_id = buffer[0] + (buffer[1] << 8); | ||||
|     esph_log_config(TAG, "Chip ID %X, project ID %x", chip_id, project_id); | ||||
|   } | ||||
|   if (this->x_raw_max_ == 0 || this->y_raw_max_ == 0) { | ||||
|     if (this->read16_(0xD1F8, buffer, 4)) { | ||||
|       this->x_raw_max_ = buffer[0] + (buffer[1] << 8); | ||||
|       this->y_raw_max_ = buffer[2] + (buffer[3] << 8); | ||||
|     } else { | ||||
|       this->x_raw_max_ = this->display_->get_native_width(); | ||||
|       this->y_raw_max_ = this->display_->get_native_height(); | ||||
|     } | ||||
|   } | ||||
|   this->setup_complete_ = true; | ||||
|   esph_log_config(TAG, "CST226 Touchscreen setup complete"); | ||||
| } | ||||
|  | ||||
| void CST226Touchscreen::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "CST226 Touchscreen:"); | ||||
|   LOG_I2C_DEVICE(this); | ||||
|   LOG_PIN("  Interrupt Pin: ", this->interrupt_pin_); | ||||
|   LOG_PIN("  Reset Pin: ", this->reset_pin_); | ||||
| } | ||||
|  | ||||
| }  // namespace cst226 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										44
									
								
								esphome/components/cst226/touchscreen/cst226_touchscreen.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								esphome/components/cst226/touchscreen/cst226_touchscreen.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
| #include "esphome/components/touchscreen/touchscreen.h" | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace cst226 { | ||||
|  | ||||
| static const char *const TAG = "cst226.touchscreen"; | ||||
|  | ||||
| static const uint8_t CST226_REG_STATUS = 0x00; | ||||
|  | ||||
| class CST226Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice { | ||||
|  public: | ||||
|   void setup() override; | ||||
|   void update_touches() override; | ||||
|   void dump_config() override; | ||||
|  | ||||
|   void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } | ||||
|   void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } | ||||
|   bool can_proceed() override { return this->setup_complete_ || this->is_failed(); } | ||||
|  | ||||
|  protected: | ||||
|   bool read16_(uint16_t addr, uint8_t *data, size_t len) { | ||||
|     if (this->read_register16(addr, data, len) != i2c::ERROR_OK) { | ||||
|       esph_log_e(TAG, "Read data from 0x%04X failed", addr); | ||||
|       this->mark_failed(); | ||||
|       return false; | ||||
|     } | ||||
|     return true; | ||||
|   } | ||||
|   void continue_setup_(); | ||||
|  | ||||
|   InternalGPIOPin *interrupt_pin_{}; | ||||
|   GPIOPin *reset_pin_{}; | ||||
|   uint8_t chip_id_{}; | ||||
|   bool setup_complete_{}; | ||||
| }; | ||||
|  | ||||
| }  // namespace cst226 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										24
									
								
								tests/components/cst226/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								tests/components/cst226/test.esp32-c3.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| spi: | ||||
|   - id: spi_id_1 | ||||
|     clk_pin: GPIO7 | ||||
|     mosi_pin: GPIO6 | ||||
|     interface: any | ||||
|  | ||||
| display: | ||||
|   - platform: ili9xxx | ||||
|     id: displ8 | ||||
|     model: ili9342 | ||||
|     cs_pin: GPIO5 | ||||
|     dc_pin: GPIO4 | ||||
|     reset_pin: | ||||
|       number: GPIO21 | ||||
|  | ||||
| i2c: | ||||
|   scl: GPIO18 | ||||
|   sda: GPIO8 | ||||
|  | ||||
| touchscreen: | ||||
|   - platform: cst226 | ||||
|     interrupt_pin: GPIO3 | ||||
|     reset_pin: GPIO20 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user