ESPHome 2026.6.0-dev
Loading...
Searching...
No Matches
xpt2046.cpp
Go to the documentation of this file.
1#include "xpt2046.h"
3#include "esphome/core/log.h"
4
5#include <algorithm>
6
7namespace esphome::xpt2046 {
8
9static const char *const TAG = "xpt2046";
10
12 if (this->irq_pin_ != nullptr) {
13 // The pin reports a touch with a falling edge. Unfortunately the pin goes also changes state
14 // while the channels are read and wiring it as an interrupt is not straightforward and would
15 // need careful masking. A GPIO poll is cheap so we'll just use that.
16
17 this->irq_pin_->setup(); // INPUT
19 this->irq_pin_->setup();
21 }
22 this->spi_setup();
23 this->read_adc_(0xD0); // ADC powerdown, enable PENIRQ pin
24}
25
27 int16_t data[6], x_raw, y_raw, z_raw;
28 bool touch = false;
29
30 enable();
31
32 int16_t touch_pressure_1 = this->read_adc_(0xB1 /* touch_pressure_1 */);
33 int16_t touch_pressure_2 = this->read_adc_(0xC1 /* touch_pressure_2 */);
34 z_raw = touch_pressure_1 + 0xfff - touch_pressure_2;
35 ESP_LOGVV(TAG, "Touchscreen Update z = %d", z_raw);
36 touch = (z_raw >= this->threshold_);
37 if (touch) {
38 read_adc_(0xD1 /* X */); // dummy Y measure, 1st is always noisy
39 data[0] = this->read_adc_(0x91 /* Y */);
40 data[1] = this->read_adc_(0xD1 /* X */); // make 3 x-y measurements
41 data[2] = this->read_adc_(0x91 /* Y */);
42 data[3] = this->read_adc_(0xD1 /* X */);
43 data[4] = this->read_adc_(0x91 /* Y */);
44 }
45
46 data[5] = this->read_adc_(0xD0 /* X */); // Last X touch power down
47
48 disable();
49
50 if (touch) {
51 x_raw = best_two_avg(data[1], data[3], data[5]);
52 y_raw = best_two_avg(data[0], data[2], data[4]);
53
54 ESP_LOGD(TAG, "Touchscreen Update [%d, %d], z = %d", x_raw, y_raw, z_raw);
55
56 this->add_raw_touch_position_(0, x_raw, y_raw, z_raw);
57 }
58}
59
61 ESP_LOGCONFIG(TAG,
62 "XPT2046:\n"
63 " X min: %d\n"
64 " X max: %d\n"
65 " Y min: %d\n"
66 " Y max: %d\n"
67 " Swap X/Y: %s\n"
68 " Invert X: %s\n"
69 " Invert Y: %s\n"
70 " threshold: %d",
71 this->x_raw_min_, this->x_raw_max_, this->y_raw_min_, this->y_raw_max_, YESNO(this->swap_x_y_),
72 YESNO(this->invert_x_), YESNO(this->invert_y_), this->threshold_);
73 LOG_PIN(" IRQ Pin: ", this->irq_pin_);
74 LOG_UPDATE_INTERVAL(this);
75}
76
77// float XPT2046Component::get_setup_priority() const { return setup_priority::DATA; }
78
79int16_t XPT2046Component::best_two_avg(int16_t value1, int16_t value2, int16_t value3) {
80 int16_t delta_a, delta_b, delta_c;
81 int16_t reta = 0;
82
83 delta_a = (value1 > value2) ? value1 - value2 : value2 - value1;
84 delta_b = (value1 > value3) ? value1 - value3 : value3 - value1;
85 delta_c = (value3 > value2) ? value3 - value2 : value2 - value3;
86
87 if (delta_a <= delta_b && delta_a <= delta_c) {
88 reta = (value1 + value2) >> 1;
89 } else if (delta_b <= delta_a && delta_b <= delta_c) {
90 reta = (value1 + value3) >> 1;
91 } else {
92 reta = (value2 + value3) >> 1;
93 }
94
95 return reta;
96}
97
98int16_t XPT2046Component::read_adc_(uint8_t ctrl) { // NOLINT
99 uint8_t data[2];
100
101 this->write_byte(ctrl);
102 delay(1);
103 data[0] = this->read_byte();
104 data[1] = this->read_byte();
105
106 return ((data[0] << 8) | data[1]) >> 3;
107}
108
109} // namespace esphome::xpt2046
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
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)
int16_t read_adc_(uint8_t ctrl)
Definition xpt2046.cpp:98
static int16_t best_two_avg(int16_t value1, int16_t value2, int16_t value3)
Definition xpt2046.cpp:79
@ INTERRUPT_FALLING_EDGE
Definition gpio.h:51
@ FLAG_PULLUP
Definition gpio.h:30
@ FLAG_INPUT
Definition gpio.h:27
void HOT delay(uint32_t ms)
Definition hal.cpp:85