Calibrate touch from serial logs: invert physical X axis.

Bottom LVGL buttons were mapped to the top; add on-screen logic coordinate debug.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-17 18:01:05 +08:00
parent 86064bca9c
commit b09fca956f
7 changed files with 60 additions and 22 deletions

View File

@@ -4,13 +4,18 @@
#include <Arduino.h>
/**
* SoftSPI XPT2046 → LVGL indev
* SoftSPI XPT2046 → LVGL indev(物理 240x320,LVGL 再做 ROTATION_270)
*
* 关键:必须上报与 lv_tft_espi_create(240,320) 一致的【物理竖屏】坐标。
* LVGL 在 ROTATION_270 时会自己做镜像+交换(见 lv_indev.c indev_pointer_proc)。
* 若再 map 成 320x240,等于旋转两次,就会出现「只有上 1/3 有反应、底部按钮点不到」。
* 串口实测:未反转时,点屏幕下方按钮对应到上方区域;
* 故对物理 X 取反,使视觉上下与逻辑 ly 一致。
*/
int16_t g_dbg_phys_x = -1;
int16_t g_dbg_phys_y = -1;
int16_t g_dbg_logic_x = -1;
int16_t g_dbg_logic_y = -1;
bool g_dbg_touch_down = false;
static void soft_write(uint8_t data) {
for (int i = 7; i >= 0; --i) {
digitalWrite(CYD_TOUCH_MOSI, (data >> i) & 1);
@@ -53,7 +58,7 @@ void touch_init() {
pinMode(CYD_TOUCH_IRQ, INPUT);
digitalWrite(CYD_TOUCH_CS, HIGH);
digitalWrite(CYD_TOUCH_CLK, LOW);
Serial.println("Touch: physical 240x320 for LVGL rotation");
Serial.println("Touch: phys 240x320, invert X (from serial calib)");
}
void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
@@ -66,23 +71,18 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
const bool in_range =
(raw_x > 80 && raw_x < 4000 && raw_y > 80 && raw_y < 4000);
if (!in_range) {
data->state = LV_INDEV_STATE_RELEASED;
return;
}
// 无 IRQ 时仍允许(部分板 IRQ 不可靠),但过滤空闲噪声
if (!irq && (raw_x < 150 || raw_y < 150)) {
if (!in_range || (!irq && (raw_x < 150 || raw_y < 150))) {
data->state = LV_INDEV_STATE_RELEASED;
g_dbg_touch_down = false;
return;
}
// XPT2046_Touchscreen setRotation(2) 等价变换
// setRotation(2) 等价
const int16_t p_x = (int16_t)raw_x;
const int16_t p_y = (int16_t)(4095 - raw_y);
// 物理竖屏:宽 SCREEN_WIDTH=240,高 SCREEN_HEIGHT=320
// (与 create(240,320) 的 disp->hor_res / ver_res 一致,供 LVGL 再旋转)
int16_t x = map(p_x, 200, 3700, 0, SCREEN_WIDTH - 1);
// 物理竖屏;X 反向(串口日志标定)
int16_t x = map(p_x, 200, 3700, SCREEN_WIDTH - 1, 0);
int16_t y = map(p_y, 240, 3800, 0, SCREEN_HEIGHT - 1);
if (x < 0) {
@@ -98,11 +98,22 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
y = SCREEN_HEIGHT - 1;
}
// LVGL ROTATION_270 之后的逻辑坐标(与 indev_pointer_proc 一致)
// lx = y, ly = hor_res - x - 1 (hor_res=240)
const int16_t logic_x = y;
const int16_t logic_y = (int16_t)(SCREEN_WIDTH - 1 - x);
g_dbg_phys_x = x;
g_dbg_phys_y = y;
g_dbg_logic_x = logic_x;
g_dbg_logic_y = logic_y;
g_dbg_touch_down = true;
static uint32_t last_log = 0;
if (millis() - last_log > 200) {
if (millis() - last_log > 150) {
last_log = millis();
Serial.printf("Touch phys(%d,%d) raw(%u,%u) irq=%d\n", x, y, raw_x, raw_y,
irq ? 1 : 0);
Serial.printf("Touch raw(%u,%u) phys(%d,%d) logic(%d,%d)\n", raw_x, raw_y, x,
y, logic_x, logic_y);
}
data->point.x = x;