initial cst328

This commit is contained in:
Anton Viktorov 2024-12-25 19:40:36 +01:00
parent 45beea68eb
commit 1805000e9a
4 changed files with 261 additions and 0 deletions

View File

@ -0,0 +1,6 @@
import esphome.codegen as cg
CODEOWNERS = ["@latonita"]
DEPENDENCIES = ["i2c"]
cst328_ns = cg.esphome_ns.namespace("cst328")

View File

@ -0,0 +1,36 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components import i2c, touchscreen
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN
from .. import cst328_ns
CST328Touchscreen = cst328_ns.class_(
"CST328Touchscreen",
touchscreen.Touchscreen,
i2c.I2CDevice,
)
CONFIG_SCHEMA = (
touchscreen.touchscreen_schema("100ms")
.extend(
{
cv.GenerateID(): cv.declare_id(CST328Touchscreen),
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(0x1A))
)
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)))

View File

@ -0,0 +1,143 @@
#include "cst328_touchscreen.h"
namespace esphome {
namespace cst328 {
void CST328Touchscreen::setup() {
ESP_LOGCONFIG(TAG, "Setting up CST328 Touchscreen...");
if (this->reset_pin_ != nullptr) {
this->reset_pin_->setup();
this->reset_pin_->digital_write(true);
delay(50);
this->reset_pin_->digital_write(false);
delay(5);
this->reset_pin_->digital_write(true);
this->set_timeout(50, [this] { this->continue_setup_(); });
} else {
this->continue_setup_();
}
}
void CST328Touchscreen::continue_setup_() {
uint8_t buffer[4];
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) {
// ESP_LOGE(TAG, "Write byte to 0xD1 failed");
// this->mark_failed();
// return;
// }
// delay(10);
// Enter debug/info mode
if (this->write_register16(static_cast<uint16_t>(Cst328WorkModes::DEBUG_INFO_MODE), buffer, 0) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "Failed to enter debug/info mode");
this->mark_failed();
return;
}
// Read chip and project ID
if (this->read16_(static_cast<u_int16_t>(Cst328Registers::CHIP_TYPE_AND_PROJECT_ID), buffer, 4)) {
this->chip_id_ = buffer[2] + (buffer[3] << 8);
this->project_id_ = buffer[0] + (buffer[1] << 8);
ESP_LOGV(TAG, "Chip ID %X, project ID %X", this->chip_id_, this->project_id_);
}
// Read FW checksum
if (this->read16_(static_cast<uint16_t>(Cst328Registers::FW_CRC_AND_BOOT_TIME), buffer, 4)) {
uint16_t fw_crc = buffer[2] + (buffer[3] << 8);
if (0xCACA != fw_crc) {
ESP_LOGE(TAG, "Invalid FW checksum: %X", fw_crc);
this->mark_failed();
return;
}
}
// Read FW version
if (this->read16_(static_cast<u_int16_t>(Cst328Registers::FW_REVISION), buffer, 4)) {
this->fw_ver_major_ = buffer[3];
this->fw_ver_minor_ = buffer[2];
this->fw_build_ = buffer[0] + (buffer[1] << 8);
ESP_LOGV(TAG, "FW version %d.%d.%d", this->fw_ver_major_, this->fw_ver_minor_, this->fw_build_);
}
// Read X/Y resolution
if (this->read16_(static_cast<u_int16_t>(Cst328Registers::X_Y_RESOLUTION), 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();
}
// Enter normal mode
this->write_register16(static_cast<uint16_t>(Cst328WorkModes::NORMAL_MODE), buffer, 0);
this->setup_complete_ = true;
ESP_LOGV(TAG, "CST328 Touchscreen setup complete");
}
void CST328Touchscreen::dump_config() {
ESP_LOGCONFIG(TAG, "CST328 Touchscreen:");
LOG_I2C_DEVICE(this);
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
LOG_PIN(" Reset Pin: ", this->reset_pin_);
ESP_LOGCONFIG(TAG, " Chip ID: 0x%04X, Project ID: 0x%04X", this->chip_id_, this->project_id_);
ESP_LOGCONFIG(TAG, " FW version: %d.%d.%d", this->fw_ver_major_, this->fw_ver_minor_, this->fw_build_);
ESP_LOGCONFIG(TAG, " X/Y resolution: %d/%d", this->x_raw_max_, this->y_raw_max_);
}
void CST328Touchscreen::update_touches() {
uint8_t data[CST328_TOUCH_DATA_SIZE];
uint8_t clear{0};
uint8_t touch_cnt = 0;
this->skip_update_ = true;
if (!this->read_register16(static_cast<u_int16_t>(Cst328Registers::TOUCH_FINGER_NUMBER), data, 1)) {
this->status_set_warning();
return;
}
this->status_clear_warning();
// number of fingers
touch_cnt = data[0] & 0x0F;
// no touch or error
if (touch_cnt == 0 || touch_cnt > CST328_TOUCH_MAX_POINTS) {
// clear touch
this->write_register16(static_cast<u_int16_t>(Cst328Registers::TOUCH_FINGER_NUMBER), &clear, 1);
return;
}
// read all points
if (!this->read_register16(static_cast<u_int16_t>(Cst328Registers::TOUCH_INFORMATION), data, sizeof(data))) {
ESP_LOGV(TAG, "Failed to read touch data");
this->status_set_warning();
return;
}
// clear touch
this->write_register16(static_cast<u_int16_t>(Cst328Registers::TOUCH_FINGER_NUMBER), &clear, 1);
this->skip_update_ = false;
size_t index = 0;
for (uint8_t i = 0; i != touch_cnt; 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);
ESP_LOGV(TAG, "Read touch %d: %d/%d", id, x, y);
index += 5;
if (i == 0) {
index += 2;
}
}
}
} // namespace cst328
} // namespace esphome

View File

@ -0,0 +1,76 @@
#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 cst328 {
static const char *const TAG = "cst328.touchscreen";
static const uint8_t CST328_REG_STATUS = 0x00;
static const uint8_t CST328_TOUCH_MAX_POINTS = 5;
static const uint8_t CST328_TOUCH_DATA_SIZE = 27;
enum class Cst328Registers : uint16_t {
TOUCH_INFORMATION = 0xD000,
TOUCH_FINGER_NUMBER = 0xD005,
KEY_TX_RX_NUMBERS = 0xD1F4,
X_Y_RESOLUTION = 0xD1F8,
FW_CRC_AND_BOOT_TIME = 0xD1FC,
CHIP_TYPE_AND_PROJECT_ID = 0xD204,
FW_REVISION = 0xD208,
};
enum class Cst328WorkModes : uint16_t {
DEBUG_INFO_MODE = 0xD101,
RESET_MODE = 0xD102,
RECALIBRATION_MODE = 0xD104,
DEEP_SLEEP_MODE = 0xD105,
DEBUG_POINT_MODE = 0xD108,
NORMAL_MODE = 0xD109,
DEBUG_RAWDATA_MODE = 0xD10A,
DEBUG_DIFF_MODE = 0xD10D,
DEBUG_FACTORY_MODE = 0xD119,
DEBUG_FACTORY_MODE_2 = 0xD120,
};
class CST328Touchscreen : 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_{};
uint16_t chip_id_{};
uint16_t project_id_{};
uint8_t fw_ver_major_{};
uint8_t fw_ver_minor_{};
uint16_t fw_build_{};
bool setup_complete_{};
};
} // namespace cst328
} // namespace esphome