Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue with the transformation of touchscreen coordinates to display coordinates in LVGL #7841

Open
ScottFerg56 opened this issue Feb 25, 2025 · 3 comments

Comments

@ScottFerg56
Copy link

LVGL version

v9.2.2

Platform

N/A, not relevant to the discussion

What happened?

Image

This discussion references the included image. The left half shows the default rotation 0 presentation as a 240x320 portrait display. The right half shows the rotation 90 presentation as a 320x240 landscape display. The device has been rotated left to preserve the upright view of the rotated display. The following analysis assumes that this represents the correct visual result for a 90 degree display rotation as a clockwise rotation.

The following analysis only concerns math and the LVGL code. I'm not including any user-level code as that would only distract from the analysis.

My issue is with the transformation that takes place within LVGL to convert the coordinates returned by a touchscreen indev read callback (lv_indev_read_cb_t) to display coordinates.

Here is the transform LVGL applies to the coordinates in lvgl\src\indev\lv_indev.c:indev_pointer_proc() after calling the indev read callback:

if(disp->rotation == LV_DISPLAY_ROTATION_180 || disp->rotation == LV_DISPLAY_ROTATION_270) {
	data->point.x = disp->hor_res - data->point.x - 1;
	data->point.y = disp->ver_res - data->point.y - 1;
	}
if(disp->rotation == LV_DISPLAY_ROTATION_90 || disp->rotation == LV_DISPLAY_ROTATION_270) {
	int32_t tmp = data->point.y;
	data->point.y = data->point.x;
	data->point.x = disp->ver_res - tmp - 1;
	}

The orange dot in the image represents touchscreen coordinate (0,0) at the top left of the portrait display. For the rotation 0 case, this passes untouched through the code transform yielding (0,0) as the correct display coordinate. For the rotation 90 case, we see the orange dot still at TS(0,0) but now at the lower left of the display.

For TS coordinate (0,0) and the rotation 90 case, let’s go through the transform step by step:

int32_t tmp = data->point.y;

tmp <= 0

data->point.y = data->point.x;

data->point.y <= 0

data->point.x = disp->ver_res - tmp - 1;

data->point.x <= 320 - 0 - 1
data->point.x <= 319
(data->point.x,data->point.y) <= (319,0)

(Note that disp->ver_res is actually 320 (not 240!) as these fields retain the dimensions specified at creation.)

But (319,0) is at the top right corner of the display while the touch occurred at the bottom left of the display. This seemingly incorrect result is the concern I have about this transformation.

The transform in question does appear to be a textbook rotation of the coordinate by 90 degrees CW. But looking at the image shows that the device (and the TS coordinate) has rotated CCW relative to the display, implying we need a CCW 90 rotation of the TS coordinates for proper transformation into the display coordinate system.

How to reproduce?

No response

@kisvegabor
Copy link
Member

I think the root of the problem is a misinterpretation in the rotation directions. It's really no intuitive. In your images

  1. You have physically rotated display CW
  2. LVGL rotated the image CCW

I think all you need to do is flipping the image in your display driver as you flip it for 270 deg rotation now. .

@ScottFerg56
Copy link
Author

ScottFerg56 commented Feb 26, 2025

Thanks for the answer! LVGL expects that LV_DISPLAY_ROTATION_90 will rotate the display in a CCW direction. That makes sense with how the touchscreen transform code operates. It's unfortunate that I could not find that information anywhere in the LVGL documentation. Nor is there any mention of the display's placement of the origin, or direction of the axes, or what coordinate system the touchscreen read callback should return, and no mention of the rotation that follows. Further, the display driver I'm using is provided by LVGL and my only interaction with it is:

lv_display_t * disp = lv_tft_espi_create(240, 320, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_90);

I'm letting LVGL and TFT_eSPI do their thing. I'm not involved in any of the low level driver stuff, flush callbacks, etc. It works great and makes the implementation much easier, except for now understanding the rotation is wrong. Perhaps there's some setting for TFT_eSPI that can correct this incorrect rotation? I may look into that.

Meanwhile I have worked around the problem in my touchscreen read callback by rotating my return coordinates by 180 for the 90 and 270 cases to account for this issue. As long as that works there's probably no motivation to explore further.

I would like to say that while I've only just discovered LVGL recently and been working with it only a few days, I really do appreciate what a fabulously powerful package it appears to be. I look forward to completing my current project with it and revisit some of my older ones to greatly improve their function and appearance! Like nearly all software libraries I've encountered, however, improvements in documentation would greatly improve the user experience.

Thanks!

@DragonflyNet67
Copy link

DragonflyNet67 commented Feb 27, 2025

I had the same problem, no matter if i used a CCW or CW rotation for landscape mode (LV_DISPLAY_ROTATION_90 / LV_DISPLAY_ROTATION_270)
I made a routine to recalculate the touch coordinates to match 0/0 always at the top left corner of the screen. This worked with TFT_eSPI Programs - but not with LVGL, since the coordinates are changed within LV_INDEV.C again. I found the following post in the LVGL Forum This solved the problem perfectly. With this mod in lv_indev.c i do not have to recalculate or modify the touchpoints from the touchdriver library anymore. It works like a charm.

Is there a way to include this mod in further releases? Or can i somehow make it permanent with the option to get it also in further releases of LVGL?

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants