T-Display S3 Pro Touchscreen Support - CST226SE Chip Help Needed for ESPhome

T-Display S3 Pro Touchscreen Support - CST226SE Chip Help Needed

Hardware & Setup

Problem Summary

I’ve been trying to get the touchscreen working on the T-Display S3 Pro and have discovered it uses a CST226SE chip, not the commonly assumed GT911 or CST816. The display works perfectly, but touch detection remains elusive despite successful I2C communication.

What We’ve Tried

Uploaded the stock firmware and confirmed touch screen works.

1. Initial Driver Attempts

  • GT911 touchscreen component: Failed with “Failed to read calibration values from touchscreen”
  • CST816 driver: Failed - not compatible with CST226SE hardware
  • FT5x06 and TT21100: Also incompatible

2. Hardware Discovery

Through the official LilyGO Chinese documentation and the utilities.h file

, we confirmed:

  • I2C Address: 0x6A
  • Pins:
    • SDA: GPIO5
    • SCL: GPIO6
    • Reset: GPIO13
    • Interrupt: GPIO21
    • Power Enable: GPIO38

3. CST226SE Register Protocol Implementation

From the official Chinese datasheet, we implemented the complete register map:

  • 0x00: Work mode (0x00 = NORMAL, 0x40 = SLEEP)
  • 0x01: Proximity detection
  • 0x02: Touch point count
  • 0x03-0x06: Touch coordinates with event flags and touch ID

4. Initialization Sequence

We’ve tried multiple initialization approaches:

  • Power cycling with GPIO38
  • Proper reset sequence with GPIO13
  • Wake-up command (0xA5, 0x00)
  • Calibration command (0xD104)
  • Setting NORMAL mode (register 0x00 = 0x00)

Current Status

:white_check_mark: Working: Display, WiFi, I2C communication with CST226SE
:x: Not Working: Actual touch detection (coordinates remain static)

The chip responds correctly at I2C address 0x6A and we can read all registers, but physical touches don’t register any coordinate changes or touch count updates.

Working Configuration

Here’s our current ESPHome config with display working and CST226SE communication established:

esphome:
  name: t-display-s3-pro-touch-screen
  on_boot:
    then:
      - output.turn_on: touchscreen_power
      - delay: 10ms
      - output.turn_off: touchscreen_reset  # Reset low
      - delay: 10ms
      - output.turn_on: touchscreen_reset   # Reset high
      - delay: 100ms
      - lambda: |-
          // Initialize CST226SE according to official manual
          uint8_t normal_mode[] = {0x00, 0x00};  // NORMAL mode
          id(bus_a).write(0x6A, normal_mode, sizeof(normal_mode));
          ESP_LOGI("touch", "CST226SE set to NORMAL mode");
          
          // Calibration command from datasheet
          uint8_t cal_cmd[] = {0xD1, 0x04};
          id(bus_a).write(0x6A, cal_cmd, sizeof(cal_cmd));
      - delay: 200ms

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf

# Pin configuration from official LilyGO utilities.h
output:
  - platform: ledc
    frequency: 9765Hz
    pin: GPIO48
    id: backlight_output
  - platform: gpio
    pin: GPIO38
    id: touchscreen_power
  - platform: gpio
    pin: GPIO13
    id: touchscreen_reset

light:
  - platform: monochromatic
    output: backlight_output
    name: LCD Backlight
    id: led
    restore_mode: ALWAYS_ON

# Display works perfectly
spi:
  - id: spi_id_3
    interface: any
    clk_pin: 18
    mosi_pin: 17

display:
  - platform: mipi_spi
    model: t-display-s3-pro
    id: my_display
    lambda: |-
      // Your display rendering code here
      it.print(10, 10, id(roboto), "Display Working!");

# I2C with CST226SE - communication works
i2c:
  sda: GPIO5
  scl: GPIO6
  id: bus_a
  frequency: 100kHz
  scan: true

# CST226SE register reading (for debugging)
interval:
  - interval: 1s
    then:
      - lambda: |-
          uint8_t start_reg = 0x00;
          id(bus_a).write(0x6A, &start_reg, 1, false);
          uint8_t reg_data[8];
          auto result = id(bus_a).read(0x6A, reg_data, sizeof(reg_data));
          
          if (result == esphome::i2c::ERROR_OK) {
            uint8_t work_mode = reg_data[0];
            uint8_t touch_count = reg_data[2];
            uint16_t x = ((reg_data[3] & 0x0F) << 8) | reg_data[4];
            uint16_t y = ((reg_data[5] & 0x0F) << 8) | reg_data[6];
            
            ESP_LOGI("touch", "CST226SE: mode=0x%02X, count=%d, x=%d, y=%d", 
                     work_mode, touch_count, x, y);
          }

font:
  - file: "gfonts://Roboto"
    id: roboto
    size: 20

Questions for the Community

  1. Has anyone successfully implemented CST226SE support in ESPHome?
  2. Are there additional initialization steps needed for CST226SE touch sensing?
  3. Should we consider creating a custom ESPHome component for CST226SE?
  4. Any insights on why I2C communication works but touch detection doesn’t?

@clydebarrow I saw you have good experience in this area and closely followed in post EspHome on T-Display S3 Pro but as someone did mention in Any way to get the new T-Display-S3 AMOLED to work with ESPHome? that there was no driver for CST226SE.

Debug Output

The chip responds with consistent values:

CST226SE: mode=0x00, prox=0x06, count=29(0), x=2592, y=862, event=0x00, id=1

But these values never change despite physical touches on the screen.

Request

If anyone has experience with CST226SE or similar Chipone touch controllers, or has successfully got touch working on T-Display S3 Pro, I’d greatly appreciate any guidance!

Thanks in advance for any help! :pray:


Hardware confirmed through official LilyGO documentation and Chinese CST226SE datasheet
Post wirtten with help of AI after hours of vibe debugging with Claude Sonnet 4

Did you try the CST226 Component?

oh my gosh why did I not find that in my search before? Maybe the new docs site :slight_smile: Thanks! Works with that!

Too much AI assistance? :wink:

Nope, it’s in the old docs site too. All you had to do was type “cst226” into the search box. Even ChatGPT knows about it :rofl:

@samburner3 Do you have a repo with the working configurafion of using esphome with working touchscreen now?

2 Likes

Were you able to get the onboard ambient light sensor exposed in Esphome, to controle the backlight brightness for example?

Edit: never mind, it seems this board doesn’t have such a sensor.
Edit2: The pro should have them, based on LTR-553. I have the pro external and can also see sensor holes behind the screen, but it doesn’t appear on the i2c bus scan and as such fails to initialize. Wonder if it was omitted on the pro external version?

[13:30:46.791][C][i2c.idf:090]: I2C Bus:
[13:30:46.795][C][i2c.idf:091]:   SDA Pin: GPIO5
[13:30:46.795][C][i2c.idf:091]:   SCL Pin: GPIO6
[13:30:46.795][C][i2c.idf:091]:   Frequency: 100000 Hz
[13:30:46.797][C][i2c.idf:101]:   Recovery: bus successfully recovered
[13:30:46.800][C][i2c.idf:111]: Results from bus scan:
[13:30:46.802][C][i2c.idf:117]: Found device at address 0x5A
[13:30:46.807][C][i2c.idf:117]: Found device at address 0x6A
...
[13:30:46.959][C][ltr_als_ps:085]:   Address: 0x23
[13:30:46.964][C][ltr_als_ps:086]:   Device type: ALS + PS
[13:30:46.965][C][ltr_als_ps:088]:   Automatic mode: ON
[13:30:46.965][C][ltr_als_ps:088]:   Gain: 1x
[13:30:46.965][C][ltr_als_ps:088]:   Integration time: 100 ms
[13:30:46.965][C][ltr_als_ps:088]:   Measurement repeat rate: 500 ms
[13:30:46.965][C][ltr_als_ps:088]:   Glass attenuation factor: 1.000000
[13:30:46.971][C][ltr_als_ps:017]:   ALS calculated lux 'Ambient Light'
[13:30:46.971][C][ltr_als_ps:017]:     State Class: 'measurement'
[13:30:46.971][C][ltr_als_ps:017]:     Unit of Measurement: 'lx'
[13:30:46.971][C][ltr_als_ps:017]:     Accuracy Decimals: 1
[13:30:46.978][C][ltr_als_ps:027]:     Device Class: 'illuminance'
[13:30:46.978][C][ltr_als_ps:031]:     Icon: 'mdi:brightness-6'
[13:30:46.981][C][ltr_als_ps:103]:   Proximity gain: 16x
[13:30:46.981][C][ltr_als_ps:103]:   Proximity cooldown time: 5 s
[13:30:46.981][C][ltr_als_ps:103]:   Proximity high threshold: 65535
[13:30:46.981][C][ltr_als_ps:103]:   Proximity low threshold: 0
[13:30:46.989][C][ltr_als_ps:399]:   Update Interval: 5.0s
[13:30:46.989][E][ltr_als_ps:115]: Communication failed
[13:30:46.990][E][component:188]:   ltr_als_ps.sensor is marked FAILED: unspecified