Registoring touch device causes bad display

I have a ILI9341 TFT screen with a TP28017 touchpad connected to an ESP32. This screen uses an 8-bit parallel bus (not SPI)
Screen Manual
I am using the TFT_eSPI library as the screen driver which is all working just fine and looks great.
I am using the Adafruit TouchScreen library for the touchpad, which also works just fine.

My problem is getting the touchpad part to work WITH the screen.

This may be a TFT_eSPI issue but thought I’d ask here first.

Without registering the touchpad the display works perfectly, but when i do register it (lv_indev_drv_register(&indev_drv)) the screen stops working (white and grey lines) but I am getting touch responses via serial. EDIT - I found the pin mapping of touchscreen XP and XM were backwards, I now get a pure white screen, but no text is being displayed. With lv_indev_drv_register commented out, I see the text I expect

It seems like perhaps the read of the touch pins is blocking the write to the screen bus as they share the same pins. This is just a guess though.

I am 100% positive the wiring and pin definitions are correct as both the screen and the touchpad work independently.

Anyone have any experience with this kind of setup?

main.cpp:

#include "lvgl.h"
#include "TouchScreen.h"
#include "TFT_eSPI.h"
#include "globals.h"

// touchscreen pins
#define YP 27
#define YM 4
#define XP 14
#define XM 2

// display settings
static const uint16_t screenWidth = 240;
static const uint16_t screenHeight = 320;
static lv_disp_draw_buf_t draw_buf;
static lv_disp_drv_t disp_drv;   // Descriptor of a display driver
static lv_color_t buf[screenWidth * 10];

TSPoint oldPoint;
TSPoint currPoint;

// declare display elements
lv_obj_t *speedOutput;
lv_obj_t *touchPos;

TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); // Invoke custom library
TouchScreen touchInput = TouchScreen(XP, YP, XM, YM, 340);

#if LV_USE_LOG != 0
// Serial debugging
void my_print(lv_log_level_t level, const char *file, uint32_t line, const char *fn_name, const char *dsc)
{
    Serial.printf("%s(%s)@%d->%s\r\n", file, fn_name, line, dsc);
    Serial.flush();
}
#endif

// Display flushing
void flushDisplay(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p)
{
    uint32_t w = (area->x2 - area->x1 + 1);
    uint32_t h = (area->y2 - area->y1 + 1);

    tft.startWrite();
    tft.setAddrWindow(area->x1, area->y1, w, h);
    tft.pushColors((uint16_t *)&color_p->full, w * h, true);
    tft.endWrite();

    lv_disp_flush_ready(disp);
}

// read the touchpad
void getTouchInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
    // a point object holds x y and z coordinates
    currPoint = touchInput.getPoint();

    if (currPoint.z > touchInput.pressureThreshhold)
    {
        data->point.x = currPoint.x;
        data->point.y = currPoint.y;
        data->state = LV_INDEV_STATE_PR;
        Serial.print("X = ");
        Serial.print(currPoint.x);
        Serial.print("\tY = ");
        Serial.print(currPoint.y);
        Serial.print("\tPressure = ");
        Serial.println(currPoint.z);
        lv_label_set_text_fmt(touchPos, "X = %d : Y = %d", currPoint.x, currPoint.y);
    }
    else
    {
        data->state = LV_INDEV_STATE_REL;
    }
}

void printOutput()
{
    lv_label_set_text_fmt(speedOutput, "%4.1f mm/s", wheelSpeed);
}

void setup()
{
    lv_init();
    tft.begin();
    tft.setRotation(0);

    lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * 10);

    /*Initialize the display*/
    Serial.print("Initializing display... ");
    lv_disp_drv_init(&disp_drv);
    disp_drv.hor_res = screenWidth;
    disp_drv.ver_res = screenHeight;
    disp_drv.flush_cb = flushDisplay;
    disp_drv.draw_buf = &draw_buf;
    lv_disp_drv_register(&disp_drv);
    Serial.println("Display Initialized!");

    /*Initialize the touchpad*/
    Serial.print("Initializing touchpad... ");
    // lv_disp_drv_register(&disp_drv);
    static lv_indev_drv_t indev_drv; // Descriptor of a touch driver
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = getTouchInput;
    lv_indev_t *my_indev = lv_indev_drv_register(&indev_drv);
    // if (my_indev == NULL)
    // {
    //     Serial.println("my_indev is NULL");
    // }
    // else
    // {
    //     Serial.println("my_indev is NOT NULL");
    // }
    Serial.println("Touchpad Initialized!");

    // create elements
    speedOutput = lv_label_create(lv_scr_act());
    lv_obj_align(speedOutput, LV_ALIGN_CENTER, 0, 0);
    touchPos = lv_label_create(lv_scr_act());
    lv_obj_align(touchPos, LV_ALIGN_CENTER, 0, 50);
}

void loop()
{ // runs on core 1
    lv_task_handler(); /* let the GUI do its work */
    printOutput();
    delay(50);
}

So for anyone that stumbles across this, I found a way…
Needed to forcefully set the YP and XM pins back to OUTPUT after reading the touchscreen.
I’m sure there’s a better place to put this but for now it works just fine :slight_smile:

If anyone knows where in the LVGL or TFT_eSPI libraries this would be best placed, please let me know.

void getTouchInput(lv_indev_drv_t *indev_driver, lv_indev_data_t *data)
{
    // a point object holds x y and z coordinates
    currPoint = touchInput.getPoint();

    // restore shared pins
    pinMode(YP, OUTPUT); 
    pinMode(XM, OUTPUT);

    if (currPoint.z > touchInput.pressureThreshhold)
    {
        data->point.x = currPoint.x;
        data->point.y = currPoint.y;
        data->state = LV_INDEV_STATE_PR;
        Serial.print("X = ");
        Serial.print(currPoint.x);
        Serial.print("\tY = ");
        Serial.print(currPoint.y);
        Serial.print("\tPressure = ");
        Serial.println(currPoint.z);
        // lv_label_set_text_fmt(touchPos, "X = %d : Y = %d", currPoint.x, currPoint.y);
    }
    else
    {
        data->state = LV_INDEV_STATE_REL;
    }
}
1 Like

When with last TFT_eSPI library get me this message getTouch is no part of TFT library in line:
bool touched = tft.getTouch(&touchX, &touchY, 600);
(after set all in config files)
i delete new version, i restore a old version backup of library (2.3.7) and all work fine…

Honestly, the use of these graphics libraries (together with the limitations of C ++ in declarations or in the use of variables) make programming a stress, even in terms of time (each modification made takes a couple of minutes for compiling the code) .
With Visual Studio I made a program that takes data from a site, interprets them and puts them in a table and sends me an email warning if some data exceeds a certain value in about 3 hours of time.
I’m porting it to ESP32 and it took me a day just to build the table (without the data coming in from the web).
SquareLine doesn’t even have the table widget, and GuiGuider has it only partially (it doesn’t have a field to set the width of the cells that you have to enter manually later, but you can’t see the result in the editor)