Files
homeassistant_espscreen/components/smart_display/elecrow_touch_reset.h
T
Xandrossian 6910f30d4c
CI / checks (push) Has been cancelled
CI / firmware (add-on) (push) Has been cancelled
CI / firmware (min_version) (push) Has been cancelled
Add touch_probe and touch_reset actions to the Elecrow for a diagnosis over the API (0.2.97, firmware 0.2.83)
2026-09-21 14:04:25 -07:00

78 lines
4.2 KiB
C++

#pragma once
// The GT911 of the Elecrow CrowPanel 7.0" V3.0 hangs on a PCA9557 I/O expander (I2C 0x18): IO0 is its reset, IO1 its
// interrupt line, and it stays in reset until something drives them (firmware 0.2.82). This is Elecrow's own sequence
// from their V3.0 ESPHome example, byte for byte: every expander pin an output and low (the reset held, the interrupt
// line low so the chip takes address 0x5D), 20 ms, the reset released, 100 ms for the chip to come up, then the
// interrupt line back to an input. It runs after the I2C bus is up and before the GT911 driver looks for the chip
// (setup priority 700, between the bus's 1000 and the driver's 600), so the driver finds it at 0x5D. A V2.0 board
// has no expander: the writes fail, the log says so, and the GT911 boots by its pull-up as before.
//
// probe() and reset() are the touch_probe and touch_reset actions of the board file (firmware 0.2.83): the expander's
// registers and whether a GT911 answers at 0x5D or 0x14 (its product id, "911"), and the same sequence with values of
// one's own, for a diagnosis over the API without a new build.
//
// Only the Elecrow's board file builds this (`smart_display: elecrow_touch_reset:`, which sets the flag), so the
// header adds nothing to a CYD, which has no I2C at all.
#if defined(ESP_SCREENS_ELECROW_TOUCH_RESET) && ESP_SCREENS_ELECROW_TOUCH_RESET
#include "esphome/components/i2c/i2c.h"
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
namespace elecrow {
class TouchReset : public esphome::Component, public esphome::i2c::I2CDevice {
public:
float get_setup_priority() const override { return 700.0f; }
void setup() override { this->reset(0x00, 0x00, 0x01, 20, 100, 0x02); }
// Elecrow's sequence with its values: `config` the expander's configuration register during the reset (0 = every
// pin an output), `low` its output register while the reset is held, `high` after the release, `final_config`
// afterwards; then the probe.
void reset(int config, int low, int high, int hold_ms, int wait_ms, int final_config) {
bool ok = this->write_reg_(0x03, config);
ok = this->write_reg_(0x01, low) && ok;
esphome::delay(hold_ms);
ok = this->write_reg_(0x01, high) && ok;
esphome::delay(wait_ms);
ok = this->write_reg_(0x03, final_config) && ok;
if (ok) {
ESP_LOGI("touch", "GT911 reset through the PCA9557 at 0x%02X: config 0x%02X, out 0x%02X -> 0x%02X, %d + %d ms, config 0x%02X",
this->address_, config, low, high, hold_ms, wait_ms, final_config);
} else {
ESP_LOGW("touch", "No PCA9557 at 0x%02X: the GT911 was not reset (a V2.0 board boots it by its pull-up)", this->address_);
}
this->probe();
}
// The expander's four registers and the GT911's answer at both addresses.
void probe() {
uint8_t regs[4] = {0, 0, 0, 0};
bool ok = true;
for (uint8_t reg = 0; reg < 4; ++reg) {
ok = this->write(&reg, 1) == esphome::i2c::ERROR_OK && this->read(&regs[reg], 1) == esphome::i2c::ERROR_OK && ok;
}
ESP_LOGI("touch", "PCA9557 at 0x%02X: %s input 0x%02X output 0x%02X polarity 0x%02X config 0x%02X", this->address_,
ok ? "answers," : "no answer;", regs[0], regs[1], regs[2], regs[3]);
for (uint8_t address : {0x5D, 0x14}) {
esphome::i2c::I2CDevice chip;
chip.set_i2c_bus(this->bus_);
chip.set_i2c_address(address);
const uint8_t product_id[2] = {0x81, 0x40};
uint8_t id[4] = {0, 0, 0, 0};
const bool written = chip.write(product_id, sizeof(product_id)) == esphome::i2c::ERROR_OK;
const bool read = written && chip.read(id, sizeof(id)) == esphome::i2c::ERROR_OK;
ESP_LOGI("touch", "GT911 at 0x%02X: %s%s product id %02X %02X %02X %02X (\"%c%c%c\")", address,
written ? "write ok, " : "no write ack, ", read ? "read ok," : "no read,", id[0], id[1], id[2], id[3],
id[0] >= 32 && id[0] < 127 ? id[0] : '.', id[1] >= 32 && id[1] < 127 ? id[1] : '.', id[2] >= 32 && id[2] < 127 ? id[2] : '.');
}
}
protected:
bool write_reg_(uint8_t reg, int value) {
const uint8_t data[2] = {reg, static_cast<uint8_t>(value)};
return this->write(data, sizeof(data)) == esphome::i2c::ERROR_OK;
}
};
} // namespace elecrow
#endif