nopnop2002 / esp-idf-ili9340

SPI TFT and XPT2046 touch screen controller driver for esp-idf
MIT License
163 stars 34 forks source link

xpt2046 issue #38

Closed nawazawanswl closed 5 months ago

nawazawanswl commented 2 years ago

Hi i have downloaded and compiled sucessfully. TFT ili9341 works fine all graphics and pics. The touch calibrates but when i am in Touchtest it does not do any thing out. when i press the touch from right or left edges it draws a line across whole screnn. Not working elsewhere except edges. Plz help in this regard 20211223_195336_001

nopnop2002 commented 2 years ago

Does your TFT equipped with XPT2046?

There is a TFT equipped with HR2046. XPT2046 and HR2046 are very similar. But HR2046 does not work properly. You can't tell just by looking at it like the picture. You need to use a magnifying glass to read the IC markings.

XPT2046-2

nawazawanswl commented 2 years ago

it is xpt2046. it is working properly with Tft_eSpi LVGL GuiSlice and others. I have around 12 of these Displays. i hav changed and checked, they are all ok. there is something in your code which i cannot figure out, hopfully you can, plz check attached pics it is xpt 2046 20211224_131632_001 20211224_131715

nopnop2002 commented 2 years ago

Thank you for picture.

Your TFT is definitely XPT.

I'm about to start making a simple project for XPT.

I will publish it when it is completed.

nawazawanswl commented 2 years ago

Edit during calibration if i touch opposit to dot for calibration , touch works but from left it draws pixles to the right and from right it draws pixels to the left on the same posittion. i mean its inverted.

nawazawanswl commented 2 years ago

thanx i am waiting for it.............

nopnop2002 commented 2 years ago

Please test only one.

Looking at the photo, SDO (MISO) is connected to the ESP32.

Please try disconnecting this connection.

147334417-3741c731-2e53-4065-b8c1-54f9f231d4da

xpt2046

nawazawanswl commented 2 years ago

i have already tried by disconnecting the SDO (MISO) but not working. The IRQ Low is working. Display is Working Correctly. It enters into calibration and passes to touch test.

nawazawanswl commented 2 years ago

and also its showing x and y coordinates in debug window when i touch the at different points. but the output it shows is out of range varies from 0 to 1890 at x and y.

nawazawanswl commented 2 years ago

debug window debugxpt2046

nopnop2002 commented 2 years ago

I noticed one.

It looks like this on my TFT. XPT2046-3

It will be displayed in rotation in your TFT. xpt_your

I don't know why.

nopnop2002 commented 2 years ago

I want to see your same screen.

Left:3.2" Right:2.4" 3_2_ili9341

Left:2.8" Right:2.4" screen_2-8_240x320

nawazawanswl commented 2 years ago

i have just changed the rotation of font in touch test, nothing else is changed. plz check the attched picture. 20211225_172203

nawazawanswl commented 2 years ago

i am compiling in esp-idf v 4.3.1 , does it make any difference ..? i dont think so, because every other piece of code is working correctly. can you plz make a separate file or if you plz download from the repo and check again , i dont think your touch will work. some times we do some in comments and forgot to revert....... waiting..........................

nawazawanswl commented 2 years ago

only workink on the edges....as you can see in attached pic. 20211225_174829

nopnop2002 commented 2 years ago

Added TouchPosition function.

You can check if XPT2046 works properly.
config-xpt2046-2

If you touch it at this time, the touched coordinates will be displayed.
TouchPosition-1

Touch the vertical and horizontal directions to check the X and Y coordinates. TouchPosition-2

nawazawanswl commented 2 years ago

i will check it today , thanks for the effort... by the way in lvgl and tft_espi the address for X position = 0x90 and for Y position = D0.. it works there and i changed it in your code where it started working some times in the middle of screen.... anyway i will check and be back....

nopnop2002 commented 2 years ago

In my environment, moving the pen like this increases the X coordinate.

<-----  GPIO Pin  ----->
+----------------------+
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
| -------------------> |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
+----------------------+

In my environment, moving the pen like this increases the Y coordinate.

<-----  GPIO Pin  ----->
+----------------------+
|          ^           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
|          |           |
+----------------------+

When I touch the location of A, X and Y are the minimum values.(_xp=134 _yp=114) When I touch the location of B, X and Y are the maximum values.(_xp=1809 _yp=1772)

<-----  GPIO Pin  ----->
+----------------------+
|                    B |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
| A                    |
+----------------------+
nawazawanswl commented 2 years ago

well..... i was able to get coorinates before you added raw touch coordinates. so need to be calibrated according to your pics above. your calibration code does not works for me. i cannot get calibration by simple methodes and need to write a piece of good code for it, may be you can help in that manner. plz check the attached pics, dots are drawn in opposit side where ever i touch, may be X cordinates inversion is required....? 20211226_140703 20211226_140747

nawazawanswl commented 2 years ago

sorry..... my mistake, clicked on close

nawazawanswl commented 2 years ago

plz advise on how to rotate the tft display.....?

nopnop2002 commented 2 years ago

TouchPosition () just displays the coordinates obtained from XPT on the console.

Do not display it on the TFT with this function.

The data obtained from XPT is different from the coordinates of TFT.

By performing calibration, the data acquired from XPT is converted to TFT coordinates.


When I touch the location of A, X and Y are the minimum values.(_xp=134 _yp=114) This corresponds to the TFT coordinates of X=239,Y=0.

When I touch the location of B, X and Y are the maximum values.(_xp=1809 _yp=1772) This corresponds to the TFT coordinates of X=0,Y=319.

The data obtained from XPT is different from the coordinates of TFT.

<-----  GPIO Pin  ----->
+----------------------+
|                    B |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
| A                    |
+----------------------+

TouchPosition () is only used to get the correct value from XPT.

nopnop2002 commented 2 years ago

There are two coordinate systems.

Get the physical coordinates from XPT.

By performing calibration, you get the conversion factor, which translates from physical coordinates to logical coordinates.

When you touch the location of A: physical coordinates from XPT is xp=134 yp=114. Logical coordinates after conversion is X=239,Y=0.

nawazawanswl commented 2 years ago

ok......i will give it a try.

nawazawanswl commented 2 years ago

i am try to write 2D system coordinates, and i think ineed to invert X coordinate to work with Landscape mode. the code in the touch test is unmanageable, is it possible that you can modify it like that.......?

nopnop2002 commented 2 years ago

I don't understand exactly what you want to do.

You can change the coordinates by changing the initial register settings of the ILI9341.

You should read the ILI9341 datasheet carefully.


If I can understand exactly what you want to do, I may be able to give you some advice.

nawazawanswl commented 2 years ago

sorry i was away with other project for a while. What i want to do is write an XPT2046 driver which can work in every rotation of TFT_LCD. You are right i must consult ILI9341 data sheet. I will write test and give you feed back and share my code.

nawazawanswl commented 2 years ago

And may be i could not write properly which you could not understand properly. What i wanted to tell you from the begining was that your code for touch is not working properly with my touch , although from the first time it was getting RAW data from XTP2046 and proccesing the coordinates in TOUCH_TEST function , but for me touch always worked but in a different manner. May be you can understand now...?

nopnop2002 commented 2 years ago

Sorry. Your English is a little difficult for me to understand. I'm not native speaker.


First of all, are the physical coordinates displayed by TouchPosition () displayed correctly?

Q1 I want to know the display when you touch A and B.

Q2 I want to know the display when you touch a and b.

<-----  GPIO Pin  ----->
+----------------------+
| b                  B |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
|                      |
| A                  a |
+----------------------+
nawazawanswl commented 2 years ago

Ok..........i wil be back within 24 Hrs along with answers of Q1 and Q2 many thanks and Regards.

nawazawanswl commented 2 years ago

sorry for late reply...... raw values taken with touchposition function A _xp = 1087 _yp = 247

B _xp = 239 _yp = 1919

a _xp = 1087 _yp = 237

b _xp = 1744 _yp = 1896

Hope it will help my problem...... waiting for reply

nawazawanswl commented 2 years ago

and some times

A _xp = 1087 _yp = 247

B _xp = 239 _yp = 1919

a _xp = 167 _yp = 239

b _xp = 1744 _yp = 1896

nopnop2002 commented 2 years ago

Thank you for information.

A
_xp = 1087 _yp = 247 ---> This is correct.

B
_xp = 239 _yp = 1919 ---> This is correct.

a
_xp = 1087 _yp = 237 ---> This is incorrect.

b
_xp = 1744 _yp = 1896 ---> This is correct.

A and a cannot have the same value.

If calibration is performed in this state, correct results will not be obtained.

A
_xp = 1087 _yp = 247 ---> This is correct.

B
_xp = 239 _yp = 1919 ---> This is correct.

a
_xp = 167 _yp = 239 ---> This is correct.

b
_xp = 1744 _yp = 1896 ---> This is correct.

Maybe the XPT soldering is incomplete.

nawazawanswl commented 2 years ago

but........with other touch drivers it is always working correctly. can you please post a close snapshot of your xpt2046 pcb layout, so that i can confirm the pins....?

nopnop2002 commented 2 years ago

but........with other touch drivers it is always working correctly.

Can you get the raw values ​​of A, a, B, b in the same way with other touch drivers?

nopnop2002 commented 2 years ago

SPI speed may be relevant.

https://github.com/nopnop2002/esp-idf-ili9340/blob/master/main/ili9340.c#L35

I checked the XPT datasheet, but there was no mention of the maximum SPI speed.

I want to know about other touch drivers you are using.

nopnop2002 commented 2 years ago

I checked this driver.

https://github.com/Links2004/XPT2046/blob/master/src/XPT2046.cpp#L51

The SPI speed is 2500000.

nawazawanswl commented 2 years ago

i have checked them already, what i do is... max X coordinates = 1850 to 1900 max Y coodinates = 1850 to 1900 in LANDSCAP mode i do invert X coordinates.. The problem is in your code where it tries to convert them with display width and height. i will post the code which is working correctly. and yes you are right MAX SPI speed of XTP2046 is around 3.2 MHz, but it works correctly at 2.5MHz

nawazawanswl commented 2 years ago

here is the driver and conversion which works correctly....... this driver belongs to LVGL

bool xpt2046_read(lv_indev_drv_t drv, lv_indev_data_t data) {

static int16_t last_x = 0;
static int16_t last_y = 0;
bool valid = false;
int16_t x = last_x;
int16_t y = last_y;
if (xpt2048_is_touch_detected() == TOUCH_DETECTED)
{
    valid = true;

    x = xpt2046_cmd(CMD_X_READ);
    y = xpt2046_cmd(CMD_Y_READ);
    ESP_LOGI(TAG, "P(%d,%d)", x, y);

    /*Normalize Data back to 12-bits*/
    x = x >> 4;
    y = y >> 4;
    ESP_LOGI(TAG, "P_norm(%d,%d)", x, y);

    xpt2046_corr(&x, &y);
    xpt2046_avg(&x, &y);
    last_x = x;
    last_y = y;

    ESP_LOGI(TAG, "x = %d, y = %d", x, y);
}
else
{
    avg_last = 0;
}

data->point.x = x;
data->point.y = y;
data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;

return false;

}

/**

static int16_t xpt2046_cmd(uint8_t cmd) { uint8_t data[2]; tp_spi_read_reg(cmd, data, 2); int16_t val = (data[0] << 8) | data[1]; return val; }

static void xpt2046_corr(int16_t x, int16_t y) {

if XPT2046_XY_SWAP != 0

int16_t swap_tmp;
swap_tmp = *x;
*x = *y;
*y = swap_tmp;

endif

if((*x) > XPT2046_X_MIN)(*x) -= XPT2046_X_MIN;
else(*x) = 0;

if((*y) > XPT2046_Y_MIN)(*y) -= XPT2046_Y_MIN;
else(*y) = 0;

(*x) = (uint32_t)((uint32_t)(*x) * LV_HOR_RES) /
       (XPT2046_X_MAX - XPT2046_X_MIN);

(*y) = (uint32_t)((uint32_t)(*y) * LV_VER_RES) /
       (XPT2046_Y_MAX - XPT2046_Y_MIN);

if XPT2046_X_INV != 0

(*x) =  LV_HOR_RES - (*x);

endif

if XPT2046_Y_INV != 0

(*y) =  LV_VER_RES - (*y);

endif

}

static void xpt2046_avg(int16_t x, int16_t y) { /Shift out the oldest data/ uint8_t i; for(i = XPT2046_AVG - 1; i > 0 ; i--) { avg_buf_x[i] = avg_buf_x[i - 1]; avg_buf_y[i] = avg_buf_y[i - 1]; }

/*Insert the new point*/
avg_buf_x[0] = *x;
avg_buf_y[0] = *y;
if(avg_last < XPT2046_AVG) avg_last++;

/*Sum the x and y coordinates*/
int32_t x_sum = 0;
int32_t y_sum = 0;
for(i = 0; i < avg_last ; i++) {
    x_sum += avg_buf_x[i];
    y_sum += avg_buf_y[i];
}

/*Normalize the sums*/
(*x) = (int32_t)x_sum / avg_last;
(*y) = (int32_t)y_sum / avg_last;

}

nawazawanswl commented 2 years ago

i have checked your code with followingSPI speeds... 1 = 1 MHz 2 = 2 MHz 3 = 2.5 MHz there is no big difference among these speeds....... all are returning good raw values.

nawazawanswl commented 2 years ago

in arduino and TFT_eSPI touch algorithem is almost identical,

nopnop2002 commented 2 years ago

I saw your code.

The conversion factor used when converting from physical coordinates to logical coordinates is a constant. LV_HOR_RES LV_VER_RES

Therefore, even if the values ​​of A, B, a, b are strange, it works as it is.

In my project this is not a constant, it is obtained dynamically by calibration.

I don't know if the conversion factors are the same even if you use TFTs with different resolutions and manufacturers.

bool xpt2046_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{

static int16_t last_x = 0;
static int16_t last_y = 0;
bool valid = false;
int16_t x = last_x;
int16_t y = last_y;
if (xpt2048_is_touch_detected() == TOUCH_DETECTED)
{
    valid = true;

    x = xpt2046_cmd(CMD_X_READ);
    y = xpt2046_cmd(CMD_Y_READ);
    ESP_LOGI(TAG, "P(%d,%d)", x, y);

    /*Normalize Data back to 12-bits*/
    x = x >> 4;
    y = y >> 4;
    ESP_LOGI(TAG, "P_norm(%d,%d)", x, y);

    xpt2046_corr(&x, &y);
    xpt2046_avg(&x, &y);
    last_x = x;
    last_y = y;

    ESP_LOGI(TAG, "x = %d, y = %d", x, y);
}
else
{
    avg_last = 0;
}

data->point.x = x;
data->point.y = y;
data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;

return false;
}

/**********************

STATIC FUNCTIONS
**********************/
static xpt2046_touch_detect_t xpt2048_is_touch_detected()
{
// check IRQ pin if we IRQ or IRQ and preessure
#if XPT2046_TOUCH_IRQ || XPT2046_TOUCH_IRQ_PRESS
uint8_t irq = gpio_get_level(XPT2046_IRQ);
if (irq != 0) {
    return TOUCH_NOT_DETECTED;
}
#endif
// check pressure if we are pressure or IRQ and pressure
#if XPT2046_TOUCH_PRESS || XPT2046_TOUCH_IRQ_PRESS
int16_t z1 = xpt2046_cmd(CMD_Z1_READ) >> 3;
int16_t z2 = xpt2046_cmd(CMD_Z2_READ) >> 3;

// this is not what the confusing datasheet says but it seems to
// be enough to detect real touches on the panel
int16_t z = z1 + 4096 - z2;

if (z < XPT2046_TOUCH_THRESHOLD)
{
    return TOUCH_NOT_DETECTED;
}
#endif

return TOUCH_DETECTED;
}

static int16_t xpt2046_cmd(uint8_t cmd)
{
uint8_t data[2];
tp_spi_read_reg(cmd, data, 2);
int16_t val = (data[0] << 8) | data[1];
return val;
}

static void xpt2046_corr(int16_t * x, int16_t * y)
{
#if XPT2046_XY_SWAP != 0
int16_t swap_tmp;
swap_tmp = *x;
*x = *y;
*y = swap_tmp;
#endif

if((*x) > XPT2046_X_MIN)(*x) -= XPT2046_X_MIN;
else(*x) = 0;

if((*y) > XPT2046_Y_MIN)(*y) -= XPT2046_Y_MIN;
else(*y) = 0;

(*x) = (uint32_t)((uint32_t)(*x) * LV_HOR_RES) /
       (XPT2046_X_MAX - XPT2046_X_MIN);

(*y) = (uint32_t)((uint32_t)(*y) * LV_VER_RES) /
       (XPT2046_Y_MAX - XPT2046_Y_MIN);
#if XPT2046_X_INV != 0
(*x) = LV_HOR_RES - (*x);
#endif

#if XPT2046_Y_INV != 0
(*y) = LV_VER_RES - (*y);
#endif

}

static void xpt2046_avg(int16_t * x, int16_t * y)
{
/Shift out the oldest data/
uint8_t i;
for(i = XPT2046_AVG - 1; i > 0 ; i--) {
avg_buf_x[i] = avg_buf_x[i - 1];
avg_buf_y[i] = avg_buf_y[i - 1];
}

/*Insert the new point*/
avg_buf_x[0] = *x;
avg_buf_y[0] = *y;
if(avg_last < XPT2046_AVG) avg_last++;

/*Sum the x and y coordinates*/
int32_t x_sum = 0;
int32_t y_sum = 0;
for(i = 0; i < avg_last ; i++) {
    x_sum += avg_buf_x[i];
    y_sum += avg_buf_y[i];
}

/*Normalize the sums*/
(*x) = (int32_t)x_sum / avg_last;
(*y) = (int32_t)y_sum / avg_last;
}
nopnop2002 commented 2 years ago

For your TFT, adding the following 4 lines may work.

https://github.com/nopnop2002/esp-idf-ili9340/blob/master/main/main.c#L1202

This change changes the conversion factor to a constant.

dev->_calibration = false;
dev->_min_xp = 167;
dev->_min_yp = 239;
dev->_max_xp = 1744;
dev->_max_yp = 1896;
}
nawazawanswl commented 2 years ago

thanx.............i will give em a try.

nawazawanswl commented 2 years ago

hi, i have written my own driver and its working perfectly. anyway i was already adopting these values in Tft_Espi and Lvgl. but your driver also helped me in writting a universal alike code. thanks for your help and Best Regards