ESPHome 2026.8.0-dev
Loading...
Searching...
No Matches
cst328_touchscreen.cpp
Go to the documentation of this file.
2#include "esphome/core/log.h"
3
4namespace esphome::cst328 {
5
6static const char *const TAG = "cst328.touchscreen";
7
8static const uint32_t CST328_BEFORE_RESET_TIMEOUT = 50; // 50 ms from datasheet
9static const uint32_t CST328_TRANSITION_TIMEOUT = 300; // 200 ms from datasheet, but typically much less
10static const uint16_t CST328_FW_CRC = 0xCACA; // Expected firmware CRC value
11static const uint8_t CST328_SYNC_BYTE = 0xAB; // Sync byte used in communication
12
13static const uint8_t ZERO_BYTE = 0;
14
15#define I2C_WARN_ON_ERROR(x, log_tag, format, ...) \
16 do { \
17 i2c::ErrorCode err_rc_ = (x); \
18 if (err_rc_ != i2c::ERROR_OK) { \
19 ESP_LOGW(log_tag, "%s(%d): [error %d] " format, __FUNCTION__, __LINE__, err_rc_, ##__VA_ARGS__); \
20 this->status_set_warning(format); \
21 } \
22 } while (0)
23
24#define I2C_FAIL_ON_ERROR(x, log_tag, format, ...) \
25 do { \
26 i2c::ErrorCode err_rc_ = (x); \
27 if (err_rc_ != i2c::ERROR_OK) { \
28 ESP_LOGE(log_tag, "%s(%d): [error %d] " format, __FUNCTION__, __LINE__, err_rc_, ##__VA_ARGS__); \
29 this->mark_failed(); \
30 return; \
31 } \
32 } while (0)
33
35 ESP_LOGCONFIG(TAG, "Setting up CST328 Touchscreen...");
36 if (this->reset_pin_ != nullptr) {
37 this->reset_pin_->setup();
38 this->reset_pin_->digital_write(true);
39 this->set_timeout(CST328_BEFORE_RESET_TIMEOUT, [this] { this->reset_device_(); });
40 } else {
41 this->continue_setup_();
42 }
43}
44
46 this->reset_pin_->digital_write(false);
47 delay(5);
48 this->reset_pin_->digital_write(true);
49 this->set_timeout(CST328_TRANSITION_TIMEOUT, [this] { this->continue_setup_(); });
50}
51
53 ESP_LOGV(TAG, "Continuing CST328 setup...");
54
55 uint8_t data_byte{0};
56 uint8_t buf[24]{};
57
58 I2C_FAIL_ON_ERROR(this->write_register16(CST_WM_DEBUG_INFO, buf, 0), TAG, "Failed to enter debug/info mode");
59 I2C_FAIL_ON_ERROR(this->read_register16(CST_REG_FW_CRC_AND_BOOT_TIME, buf, 4), TAG,
60 "Failed to read FW CRC and boot time");
61
62 uint16_t fw_crc = buf[2] + (buf[3] << 8);
63 if (fw_crc != CST328_FW_CRC) {
64 ESP_LOGE(TAG, "Error: Firmware CRC mismatch, expected 0x%04X but got 0x%04X", CST328_FW_CRC, fw_crc);
65 this->mark_failed();
66 return;
67 }
68
69 I2C_FAIL_ON_ERROR(this->read_register16(CST_REG_CHIP_TYPE_AND_PROJECT_ID, buf, 4), TAG,
70 "Failed to read chip and project ID");
71
72 this->chip_id_ = buf[2] + (buf[3] << 8);
73 this->project_id_ = buf[0] + (buf[1] << 8);
74 ESP_LOGD(TAG, "Chip ID %X, project ID %X", this->chip_id_, this->project_id_);
75 I2C_FAIL_ON_ERROR(this->read_register16(CST_REG_FW_REVISION, buf, 4), TAG, "Failed to read FW version");
76
77 this->fw_ver_major_ = buf[3];
78 this->fw_ver_minor_ = buf[2];
79 this->fw_build_ = buf[0] + (buf[1] << 8);
80 ESP_LOGV(TAG, "FW version %d.%d.%d", this->fw_ver_major_, this->fw_ver_minor_, this->fw_build_);
81
82 if (i2c::ERROR_OK == this->read_register16(CST_REG_X_Y_RESOLUTION, buf, 4)) {
83 this->x_raw_max_ = buf[0] + (buf[1] << 8);
84 this->y_raw_max_ = buf[2] + (buf[3] << 8);
85 } else {
86 this->x_raw_max_ = this->display_->get_native_width();
87 this->y_raw_max_ = this->display_->get_native_height();
88 }
89
90 I2C_WARN_ON_ERROR(this->write_register16(CST_WM_NORMAL, buf, 0), TAG, "Failed to enter normal mode");
91 I2C_WARN_ON_ERROR(this->read_register16(CST_REG_TOUCH_INFORMATION, &data_byte, 1), TAG, "Failed to read sync");
92 I2C_WARN_ON_ERROR(this->write_register16(CST_REG_TOUCH_INFORMATION, &CST328_SYNC_BYTE, 1), TAG,
93 "Failed to write sync");
94
95 if (this->interrupt_pin_ != nullptr) {
96 this->interrupt_pin_->setup();
98 }
99
100 this->setup_complete_ = true;
101 ESP_LOGV(TAG, "CST328 setup complete");
102}
103
105 ESP_LOGCONFIG(TAG, "CST328 Touchscreen:");
106 LOG_I2C_DEVICE(this);
107 LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
108 LOG_PIN(" Reset Pin: ", this->reset_pin_);
109 ESP_LOGCONFIG(TAG, " Chip ID: 0x%04X, Project ID: 0x%04X", this->chip_id_, this->project_id_);
110 ESP_LOGCONFIG(TAG, " FW version: %d.%d.%d", this->fw_ver_major_, this->fw_ver_minor_, this->fw_build_);
111 ESP_LOGCONFIG(TAG, " X/Y resolution: %d/%d", this->x_raw_max_, this->y_raw_max_);
112}
113
115 if (this->button_touched_ == state) {
116 return;
117 }
118 this->button_touched_ = state;
119 for (auto *listener : this->button_listeners_) {
120 listener->update_button(state);
121 }
122}
123
125 if (!this->setup_complete_) {
126 this->skip_update_ = true;
127 return;
128 }
129
130 uint8_t touch_data[CST328_TOUCH_DATA_SIZE];
131
132 this->status_clear_warning();
133
134 if (i2c::ERROR_OK != this->read_register16(CST_REG_TOUCH_INFORMATION, touch_data, CST328_TOUCH_DATA_SIZE)) {
135 ESP_LOGW(TAG, "Failed to read touch data");
136 this->status_set_warning();
137 this->skip_update_ = true;
138 return;
139 }
140
141 uint8_t touch_cnt = touch_data[CST_REG_FINGER_COUNT_IDX] & 0x0F;
142 if (touch_cnt == 0 || touch_cnt > CST328_TOUCH_MAX_POINTS) {
143 this->update_button_state_(false);
144 } else {
145 this->update_button_state_(true);
146
147 uint8_t data_idx = 0;
148 for (uint8_t i = 0; i < touch_cnt; i++) {
149 uint8_t id = touch_data[data_idx] >> 4;
150 int16_t x = (touch_data[data_idx + 1] << 4) | ((touch_data[data_idx + 3] >> 4) & 0x0F);
151 int16_t y = (touch_data[data_idx + 2] << 4) | (touch_data[data_idx + 3] & 0x0F);
152 int16_t z = touch_data[data_idx + 4];
153
154 this->add_raw_touch_position_(id, x, y, z);
155 data_idx += (i == 0) ? 7 : 5;
156 }
157 }
158
159 bool cleanup_error = false;
160 cleanup_error |= (i2c::ERROR_OK != this->write_register16(CST_REG_TOUCH_FINGER_NUMBER, &ZERO_BYTE, 1));
161 cleanup_error |= (i2c::ERROR_OK != this->write_register16(CST_REG_TOUCH_INFORMATION, &CST328_SYNC_BYTE, 1));
162
163 if (cleanup_error) {
164 ESP_LOGW(TAG, "Failed to clean up touch registers");
165 }
166}
167
168} // namespace esphome::cst328
void mark_failed()
Mark this component as failed.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
Definition component.cpp:96
void status_clear_warning()
Definition component.h:289
virtual void setup()=0
virtual void digital_write(bool value)=0
std::vector< CST328ButtonListener * > button_listeners_
int get_native_width()
Get the native (original) width of the display in pixels.
Definition display.h:330
int get_native_height()
Get the native (original) height of the display in pixels.
Definition display.h:332
ErrorCode write_register16(uint16_t a_register, const uint8_t *data, size_t len) const
write an array of bytes to a specific register in the I²C device
Definition i2c.cpp:43
ErrorCode read_register16(uint16_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:29
void attach_interrupt_(InternalGPIOPin *irq_pin, esphome::gpio::InterruptType type)
Call this function to send touch points to the on_touch listener and the binary_sensors.
void add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_raw, int16_t z_raw=0)
bool state
Definition fan.h:2
bool z
Definition msa3xx.h:1
@ INTERRUPT_FALLING_EDGE
Definition gpio.h:49
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
void HOT delay(uint32_t ms)
Definition hal.cpp:85
static void uint32_t
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6