ESPHome 2026.3.0-dev
Loading...
Searching...
No Matches
gt911_touchscreen.cpp
Go to the documentation of this file.
1#include "gt911_touchscreen.h"
2
4#include "esphome/core/log.h"
5#include "esphome/core/gpio.h"
6
7namespace esphome {
8namespace gt911 {
9
10static const char *const TAG = "gt911.touchscreen";
11
12static const uint8_t PRIMARY_ADDRESS = 0x5D; // default I2C address for GT911
13static const uint8_t SECONDARY_ADDRESS = 0x14; // secondary I2C address for GT911
14static const uint8_t GET_TOUCH_STATE[2] = {0x81, 0x4E};
15static const uint8_t CLEAR_TOUCH_STATE[3] = {0x81, 0x4E, 0x00};
16static const uint8_t GET_TOUCHES[2] = {0x81, 0x4F};
17static const uint8_t GET_SWITCHES[2] = {0x80, 0x4D};
18static const uint8_t GET_MAX_VALUES[2] = {0x80, 0x48};
19static const size_t MAX_TOUCHES = 5; // max number of possible touches reported
20static const size_t MAX_BUTTONS = 4; // max number of buttons scanned
21
22#define ERROR_CHECK(err) \
23 if ((err) != i2c::ERROR_OK) { \
24 this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL)); \
25 return; \
26 }
27
29 if (this->reset_pin_ != nullptr) {
30 // temporarily set the interrupt pin to output to control address selection
31 this->reset_pin_->setup();
32 this->reset_pin_->digital_write(false);
33 if (this->interrupt_pin_ != nullptr) {
34 this->interrupt_pin_->setup();
36 this->interrupt_pin_->digital_write(false);
37 }
38 delay(2);
39 this->reset_pin_->digital_write(true);
40 // wait at least T3+T4 ms as per the datasheet
41 this->set_timeout(5 + 50 + 1, [this] { this->setup_internal_(); });
42 return;
43 }
44 this->setup_internal_();
45}
46
48 if (this->interrupt_pin_ != nullptr) {
49 if (this->interrupt_pin_->is_internal())
51 }
52
53 uint8_t data[4];
54 i2c::ErrorCode err = this->write(GET_SWITCHES, sizeof(GET_SWITCHES));
55 if (err != i2c::ERROR_OK && this->address_ == PRIMARY_ADDRESS) {
56 this->address_ = SECONDARY_ADDRESS;
57 err = this->write(GET_SWITCHES, sizeof(GET_SWITCHES));
58 }
59 if (err == i2c::ERROR_OK) {
60 err = this->read(data, 1);
61 if (err == i2c::ERROR_OK) {
62 ESP_LOGD(TAG, "Switches ADDR: 0x%02X DATA: 0x%02X", this->address_, data[0]);
63
64 // data[0] & 1 == 1 => controller uses falling edge => active-low
65 // data[0] & 1 == 0 => controller uses rising edge => active-high
66 bool active_high = !(data[0] & 1);
67
68 if (this->interrupt_pin_ != nullptr) {
69 if (this->interrupt_pin_->is_internal()) {
70 // Direct MCU pin: attach a hardware interrupt, no polling needed.
71 this->attach_interrupt_(static_cast<InternalGPIOPin *>(this->interrupt_pin_),
73 ESP_LOGD(TAG, "Interrupt pin: hardware interrupt, active %s", active_high ? "HIGH" : "LOW");
74 } else {
75 // IO expander pin: leave as output for configuration only.
76 ESP_LOGD(TAG, "Interrupt pin: IO expander polling mode, active %s", active_high ? "HIGH" : "LOW");
77 }
78 }
79 }
80 }
81
82 if (this->x_raw_max_ == 0 || this->y_raw_max_ == 0) {
83 // no calibration? Attempt to read the max values from the touchscreen.
84 if (err == i2c::ERROR_OK) {
85 err = this->write(GET_MAX_VALUES, sizeof(GET_MAX_VALUES));
86 if (err == i2c::ERROR_OK) {
87 err = this->read(data, sizeof(data));
88 if (err == i2c::ERROR_OK) {
89 this->x_raw_max_ = encode_uint16(data[1], data[0]);
90 this->y_raw_max_ = encode_uint16(data[3], data[2]);
91 if (this->swap_x_y_)
92 std::swap(this->x_raw_max_, this->y_raw_max_);
93 }
94 }
95 }
96 if (err != i2c::ERROR_OK) {
97 this->mark_failed(LOG_STR("Calibration error"));
98 return;
99 }
100 }
101
102 if (err != i2c::ERROR_OK) {
103 this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
104 return;
105 }
106 this->setup_done_ = true;
107}
108
110 this->skip_update_ = true; // skip send touch events by default, set to false after successful error checks
111 if (!this->setup_done_) {
112 return;
113 }
114
115 i2c::ErrorCode err;
116 uint8_t touch_state = 0;
117 uint8_t data[MAX_TOUCHES + 1][8]; // 8 bytes each for each point, plus extra space for the key byte
118
119 err = this->write(GET_TOUCH_STATE, sizeof(GET_TOUCH_STATE));
120 ERROR_CHECK(err);
121 err = this->read(&touch_state, 1);
122 ERROR_CHECK(err);
123 this->write(CLEAR_TOUCH_STATE, sizeof(CLEAR_TOUCH_STATE));
124 uint8_t num_of_touches = touch_state & 0x07;
125
126 if ((touch_state & 0x80) == 0 || num_of_touches > MAX_TOUCHES) {
127 return;
128 }
129
130 err = this->write(GET_TOUCHES, sizeof(GET_TOUCHES));
131 ERROR_CHECK(err);
132 // num_of_touches is guaranteed to be 0..5. Also read the key data
133 err = this->read(data[0], sizeof(data[0]) * num_of_touches + 1);
134 ERROR_CHECK(err);
135
136 this->skip_update_ = false; // All error checks passed, send touch events
137 for (uint8_t i = 0; i != num_of_touches; i++) {
138 uint16_t id = data[i][0];
139 uint16_t x = encode_uint16(data[i][2], data[i][1]);
140 uint16_t y = encode_uint16(data[i][4], data[i][3]);
141 this->add_raw_touch_position_(id, x, y);
142 }
143 auto keys = data[num_of_touches][0] & ((1 << MAX_BUTTONS) - 1);
144 if (keys != this->button_state_) {
145 this->button_state_ = keys;
146 for (size_t i = 0; i != MAX_BUTTONS; i++) {
147 for (auto *listener : this->button_listeners_)
148 listener->update_button(i, (keys & (1 << i)) != 0);
149 }
150 }
151}
152
154 ESP_LOGCONFIG(TAG, "GT911 Touchscreen:");
155 LOG_I2C_DEVICE(this);
156 LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
157 LOG_PIN(" Reset Pin: ", this->reset_pin_);
158}
159
160} // namespace gt911
161} // namespace esphome
void mark_failed()
Mark this component as failed.
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:443
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
virtual void digital_write(bool value)=0
virtual ESPDEPRECATED("Override dump_summary(char*, size_t) instead. Will be removed in 2026.7.0.", "2026.1.0") virtual std boo is_internal)()
Get a summary of this pin as a string.
Definition gpio.h:88
void setup_internal_()
Perform the internal setup routine for the GT911 touchscreen.
void setup() override
Initialize the GT911 touchscreen.
std::vector< GT911ButtonListener * > button_listeners_
bool setup_done_
True if the touchscreen setup has completed successfully.
ErrorCode write(const uint8_t *data, size_t len) const
writes an array of bytes to a device using an I2CBus
Definition i2c.h:183
ErrorCode read(uint8_t *data, size_t len) const
reads an array of bytes from the device using an I2CBus
Definition i2c.h:163
uint8_t address_
store the address of the device on the bus
Definition i2c.h:270
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)
@ INTERRUPT_FALLING_EDGE
Definition gpio.h:51
@ INTERRUPT_RISING_EDGE
Definition gpio.h:50
@ FLAG_OUTPUT
Definition gpio.h:28
@ FLAG_INPUT
Definition gpio.h:27
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
Definition i2c_bus.h:12
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:14
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition helpers.h:653
void HOT delay(uint32_t ms)
Definition core.cpp:27
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6