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

@@ -1,5 +1,5 @@
name: CYD TF card + touch speaker (cyd)
git: 36bf614
git: 86064bc
date: 2026-10-17
board: ESP32-2432S028R (ILI9341)
features: TF/SD info, SoftSPI touch, GPIO26 speaker
@@ -12,5 +12,5 @@ offsets:
sha256:
bootloader.bin 3D234A7471F67B013686DABD4DEE7C1FA915C9928463616A94BC9297ACF1ABF8
boot_app0.bin F94C5D786A7A8FAB06AC5D10E33BF37711A6697636DC037559EA19CC410A17F0
firmware.bin 5AFF818CB116CF68761168F931E9B9B5EB1B39AA0CFE40D79815BF85F0E2B007
firmware.bin 142CB38A32343602F699F1CE8CE3BB699D6F3AFD03EA38A9B961EB2897B38797
partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1

Binary file not shown.

View File

@@ -1,6 +1,12 @@
#pragma once
#include <lvgl.h>
#include <stdint.h>
void touch_init();
void touch_read_cb(lv_indev_t *indev, lv_indev_data_t *data);
// 调试:最近一次触点(物理 / LVGL 旋转后逻辑)
extern int16_t g_dbg_phys_x, g_dbg_phys_y;
extern int16_t g_dbg_logic_x, g_dbg_logic_y;
extern bool g_dbg_touch_down;

View File

@@ -5,3 +5,4 @@
void ui_create();
void ui_update(const SdCardInfo &info);
void ui_refresh_audio_buttons();
void ui_set_touch_debug(int16_t lx, int16_t ly, bool down);

View File

@@ -77,10 +77,11 @@ void loop() {
refresh_sd_ui();
}
// 播放过程中刷新按钮文字(Playing / Stop)
if (now - last_btn_ui_ms >= 300) {
// 播放过程中刷新按钮文字;同步触点调试
if (now - last_btn_ui_ms >= 200) {
last_btn_ui_ms = now;
ui_refresh_audio_buttons();
ui_set_touch_debug(g_dbg_logic_x, g_dbg_logic_y, g_dbg_touch_down);
}
delay(5);

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;

View File

@@ -13,6 +13,7 @@ static lv_obj_t *btn_speaker;
static lv_obj_t *btn_play;
static lv_obj_t *lbl_speaker;
static lv_obj_t *lbl_play;
static lv_obj_t *lbl_touch_dbg;
static lv_obj_t *make_row(lv_obj_t *parent, const char *title, lv_obj_t **value_out) {
lv_obj_t *row = lv_obj_create(parent);
@@ -149,9 +150,27 @@ void ui_create() {
lv_obj_set_style_text_font(lbl_play, &lv_font_montserrat_14, 0);
lv_obj_center(lbl_play);
lbl_touch_dbg = lv_label_create(col);
lv_label_set_text(lbl_touch_dbg, "Touch: --");
lv_obj_set_style_text_font(lbl_touch_dbg, &lv_font_montserrat_14, 0);
lv_obj_set_style_text_color(lbl_touch_dbg, lv_color_hex(0xFFB74D), 0);
ui_refresh_audio_buttons();
}
void ui_set_touch_debug(int16_t lx, int16_t ly, bool down) {
if (!lbl_touch_dbg) {
return;
}
if (!down) {
lv_label_set_text(lbl_touch_dbg, "Touch: up");
return;
}
char buf[40];
snprintf(buf, sizeof(buf), "Touch L:%d,%d", (int)lx, (int)ly);
lv_label_set_text(lbl_touch_dbg, buf);
}
void ui_update(const SdCardInfo &info) {
if (!info.mounted || !info.present) {
lv_label_set_text(lbl_status, info.error.length() ? info.error.c_str() : "Fail");