initial commit

This commit is contained in:
Simon Helson
2025-07-13 14:47:19 +12:00
parent 71b978fe12
commit 1e95711b1d
7 changed files with 447 additions and 37 deletions

View File

View File

@@ -0,0 +1,124 @@
#include "cst9217_touchscreen.h"
#include "esphome/core/log.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace cst9217 {
void CST9217Touchscreen::setup() {
ESP_LOGCONFIG(TAG, "Setting up CST9217 Touchscreen...");
// Register operations taken from
// https://github.com/waveshareteam/Waveshare-ESP32-components/blob/master/display/touch/esp_lcd_touch_cst9217/esp_lcd_touch_cst9217.c
// and adapted for ESPHome.
// holder for data returned
uint8_t data[4] = {0};
// Reset the device before setup. This checks if the reset pin is set.
this->reset_device_();
// Enter command mode
uint8_t cmd_mode[2] = { 0xD1, 0x01 };
this->write_register16(ESP_LCD_TOUCH_CST9217_CMD_MODE_REG, cmd_mode, sizeof(cmd_mode)); // Set to cmd mode
vTaskDelay(pdMS_TO_TICKS(10));
// Read the checkcodes
this->read_register16(ESP_LCD_TOUCH_CST9217_CHECKCODE_REG, data, sizeof(data));
ESP_LOGV(TAG, "Checkcode: 0x%02X%02X%02X%02X",
data[0], data[1], data[2], data[3]);
// Get the touchscreen resolution
this->read_register16(ESP_LCD_TOUCH_CST9217_RESOLUTION_REG, data, sizeof(data));
this->touch_res_x_ = (data[1] << 8) | data[0];
this->touch_res_y_ = (data[3] << 8) | data[2];
this->x_raw_min_ = 0;
this->y_raw_min_ = 0;
this->x_raw_max_ = this->touch_res_x_;
this->y_raw_max_ = this->touch_res_y_;
ESP_LOGV(TAG, "Resolution X: %d, Y: %d", this->touch_res_x_, this->touch_res_y_);
// Get the chip ID and project ID and verify chip ID
this->read_register16(ESP_LCD_TOUCH_CST9217_PROJECT_ID_REG, data, sizeof(data));
this->chip_id_ = (data[3] << 8) | data[2];
this->touch_project_id_ = (data[1] << 8) | data[0];
if (this->chip_id_ != CST9217_CHIP_ID) {
this->mark_failed();
this->status_set_error(str_sprintf("CST9217 Chip ID mismatch, expected 0x%04X, got 0x%04X", CST9217_CHIP_ID, this->chip_id_).c_str());
return;
}
ESP_LOGV(TAG, "Chip Type: 0x%04X, ProjectID: 0x%04X", this->chip_id_, this->touch_project_id_);
// Attach an interrupt pin if provided
if (this->interrupt_pin_ != nullptr) {
this->interrupt_pin_->setup();
this->attach_interrupt_(this->interrupt_pin_, gpio::INTERRUPT_FALLING_EDGE);
ESP_LOGV(TAG, "Attached Interrupt Pin: %d", this->interrupt_pin_);
}
// At this point we're all good.
ESP_LOGV(TAG, "CST9217 Touchscreen initialized successfully");
}
void CST9217Touchscreen::dump_config() {
ESP_LOGCONFIG(TAG, "CST9217 Touchscreen:");
LOG_I2C_DEVICE(this);
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
LOG_PIN(" Reset Pin: ", this->reset_pin_);
ESP_LOGCONFIG(TAG, " Resolution X: %d, Y: %d", this->touch_res_x_, this->touch_res_y_);
ESP_LOGCONFIG(TAG, " Chip Type: 0x%04X, ProjectID: 0x%04X", this->chip_id_, this->touch_project_id_);
ESP_LOGCONFIG(TAG, " CST9217 Touchscreen config dump complete");
}
void CST9217Touchscreen::update_touches() {
// ESP_LOGI(TAG, "CST9217 Touchscreen: running update_touches");
uint8_t data[CST9217_DATA_LENGTH] = {0};
i2c::ErrorCode ret;
if(!this->read_register16(ESP_LCD_TOUCH_CST9217_DATA_REG, data, sizeof(data)) == i2c::ErrorCode::NO_ERROR) {
this->status_set_warning("CST9217 Touchscreen: Failed to read touch data");
return;
}
ESP_LOGV(TAG, "Touch data dump: %02X %02X %02X %02X %02X %02X %02X %02X",
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
if (data[6] != CST9217_ACK_VALUE) {
this->status_set_warning(str_sprintf("Invalid ACK: 0x%02X vs 0x%02X", data[6], CST9217_ACK_VALUE).c_str());
return;
}
this->status_clear_warning();
uint8_t points = data[5] & 0x7F;
points = (points > CST9217_MAX_TOUCH_POINTS) ? CST9217_MAX_TOUCH_POINTS : points;
for (int i = 0; i < points; i++) {
uint8_t *p = &data[i * 5 + (i ? 2 : 0)];
uint8_t status = p[0] & 0x0F;
if (status == 0x06) {
int16_t x = ((p[1] << 4) | (p[3] >> 4));
int16_t y = ((p[2] << 4) | (p[3] & 0x0F));
this->add_raw_touch_position_(i, x, y);
ESP_LOGV(TAG, "Point %d: X=%d, Y=%d",
i, x, y);
}
}
}
void CST9217Touchscreen::reset_device_() {
if (this->reset_pin_ != nullptr) {
ESP_LOGD(TAG, "Resetting CST9217 Touchscreen...");
this->reset_pin_->digital_write(false);
vTaskDelay(pdMS_TO_TICKS(10));
this->reset_pin_->digital_write(true);
vTaskDelay(pdMS_TO_TICKS(50));
ESP_LOGD(TAG, "CST9217 Touchscreen reset complete");
} else {
ESP_LOGD(TAG, "No reset pin configured, skipping reset");
}
}
} // namespace cst9217
} // namespace esphome

View File

@@ -0,0 +1,49 @@
// cst9217.h
#include "esphome/core/component.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/touchscreen/touchscreen.h"
/* CST9217 registers */
#define ESP_LCD_TOUCH_CST9217_DATA_REG 0xD000
#define ESP_LCD_TOUCH_CST9217_PROJECT_ID_REG 0xD204
#define ESP_LCD_TOUCH_CST9217_CMD_MODE_REG 0xD101
#define ESP_LCD_TOUCH_CST9217_CHECKCODE_REG 0xD1FC
#define ESP_LCD_TOUCH_CST9217_RESOLUTION_REG 0xD1F8
/* CST9217 parameters */
#define CST9217_CHIP_ID 0x9217
#define CST9217_ACK_VALUE 0xAB
#define CST9217_MAX_TOUCH_POINTS 1
#define CST9217_DATA_LENGTH (CST9217_MAX_TOUCH_POINTS * 5 + 5)
namespace esphome {
namespace cst9217 {
static const char *const TAG = "cst9217.touchscreen";
class CST9217Touchscreen : public touchscreen::Touchscreen, public i2c::I2CDevice {
public:
void setup() override;
void dump_config() override;
void update_touches() override;
void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; }
void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; }
protected:
void CST9217Touchscreen::reset_device_();
// Internal buffer to read touch data
uint8_t touch_data_[CST9217_DATA_LENGTH]; // Sufficient for 2 touch points (8 bytes each) + header
InternalGPIOPin *interrupt_pin_{};
GPIOPin *reset_pin_{};
uint16_t chip_id_;
uint16_t touch_res_x_;
uint16_t touch_res_y_;
uint16_t touch_project_id_;
};
} // namespace cst9217
} // namespace esphome

View File

@@ -0,0 +1,34 @@
# Touchscreen component for CST9217
from esphome import pins
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import i2c, touchscreen
from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN
DEPENDENCIES = ["i2c"]
# Define the namespace for your component
cst9217_ns = cg.esphome_ns.namespace("cst9217")
CST9217Touchscreen = cst9217_ns.class_(
"CST9217Touchscreen",
touchscreen.Touchscreen,
i2c.I2CDevice,
)
CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(CST9217Touchscreen),
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)))