I know there have been mixed results with getting the touchscreen (gt911
) working, and with some hints from another post (can’t find it at the moment) that did some research in the datasheet, where the default address is 0x5D
, but it’s actually selectable at init-time utilizing both the reset_pin
and interrupt_pin
to tell the chip which address it should use. The problem is that the reset_pin
(LCD_RST, GPIO48+inverted) is shared between both the LCD panel and the CTP. I’ve tried various combinations of setting reset_pin in the ili9xxx driver, setting it in the gt911 driver, setting it in both using allow_other_uses: true
, and not setting it in either driver.
Ultimately what was most stable was not setting it in either, however we then have a race condition where sometimes the interrupt pin just happens to be high at time of init, and sometimes it happens to be low. And that determines which i2c address the touchpanel will use. You can see the result of that flakiness if you enable i2c.scan
, where sometimes it reports:
[i2c.idf:100]: Found i2c device at address 0x18
[i2c.idf:100]: Found i2c device at address 0x40
[i2c.idf:100]: Found i2c device at address 0x5D <-- touchscreen (primary)
[i2c.idf:100]: Found i2c device at address 0x68
and sometimes it reports:
[i2c.idf:100]: Found i2c device at address 0x14 <-- touchscreen (alternate)
[i2c.idf:100]: Found i2c device at address 0x18
[i2c.idf:100]: Found i2c device at address 0x40
[i2c.idf:100]: Found i2c device at address 0x68
This causes the touchscreen to work only some of the time, depending on the state of GPIO3 at boot.
To work around that, I added an on_boot
automation that does the same check that i2c.scan
does, in order to discover which address is active, and explicitly set the i2c address to whichever one responds. The result appears to be that it now successfully initializes regardless of which address was selected on startup.
on_boot:
# Execute this after i2c_bus init, and before touchscreen init. Priorities are:
# i2c: BUS = 1000
# ili9xxx LCD: HARDWARE = 800
# gt911 CTP: (default) DATA = 600
priority: 900
then:
# Address the race condition between LCD and Touchscreen, where the "real" i2c address
# for the touchscreen is determined at init, by utilizing the interrupt_pin and reset_pin.
# However, if we set reset_pin on either component (both need the same pin), then each init
# corrupts the other. Not initializing the pin as part of component setup means the real
# address could randomly switch at boot time.
# To account for that, this checks each i2c address the same way that i2c.scan works. So if
# 0x5d writes successfully, we'll use that, otherwise we use the fallback.
- lambda: |-
if (id(bus_a).writev(0x5d, nullptr, 0, true) == 0) {
ESP_LOGCONFIG("gt911", "Setting gt911 address to 0x5d");
id(gt911_touchscreen).set_i2c_address(0x5d);
# id(gt911_i2c_address).publish_state("0x5d"); # template text_sensor for debugging
} else if (id(bus_a).writev(0x14, nullptr, 0, true) == 0) {
ESP_LOGCONFIG("gt911", "Setting gt911 address to 0x14");
id(gt911_touchscreen).set_i2c_address(0x14);
# id(gt911_i2c_address).publish_state("0x14");
} else {
ESP_LOGW("gt911", "Could not verify either i2c address!");
# id(gt911_i2c_address).status_set_warning("Could not determine i2c address!");
}
And this appears to work correctly every time now.
The espressif code and arduino code appear to do this also, by having the gt911 driver simply fall back automatically (tries 0x5d first, and if that fails, it switches to 0x14). But as the gt911 is not specific to the s3-box(3), it wouldn’t make sense to do that in the gt911 component, at least not without adding a fallback address in the config, and I was trying to avoid modifying the component itself.
A better solution would be to figure out the right way to make ili9xx and gt911 play nice together, and/or add an option for gt911 to fallback to 0x14 if 0x5d fails.
# This is the optional debugging template text sensor mentioned above.
text_sensor:
- platform: template
name: GT911 i2c address
id: gt911_i2c_address
internal: false
disabled_by_default: true
entity_category: diagnostic
Has anyone else found a better solution to this? Or do most people just not bother with the touchscreen? FWIW I’m not currently using the voice-assistant package yaml due to the issues with esp-adf for audio and mic, and other issues with all those external_component
s being unstable and outdated. So I’m just using it as plain esphome with lvgl
.