diff --git a/CHANGELOG.md b/CHANGELOG.md index f572897..54d7ca5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,14 @@ # Changelog +## 2026-10-17 — SoftSPI touch + LVGL inverse (fix mux) + +- VSPI remux broke SD mount and froze touch at raw(0,4095). +- Touch back to SoftSPI on 25/32/39/33; SD keeps exclusive VSPI 18/19/23/5. +- Same temperature UI map, then invert LVGL ROTATION_270 for button hits. + ## 2026-10-17 — Touch = temperature driver + LVGL inverse -- Use `XPT2046_Touchscreen` + VSPI pin mux (touch/SD), same as climate project. -- Map with temperature formula to UI 320x240, then invert LVGL ROTATION_270 - so buttons align with fingers. -- On-screen `Touch L:x,y` shows intended UI coordinates. +- Attempted XPT2046 HW SPI + VSPI pin mux; superseded (broke SD/touch). ## 2026-10-17 — Touch calib from COM3 logs diff --git a/firmware/cyd/VERSION.txt b/firmware/cyd/VERSION.txt index 2f3ae3c..0dd905a 100644 --- a/firmware/cyd/VERSION.txt +++ b/firmware/cyd/VERSION.txt @@ -1,5 +1,5 @@ name: CYD TF card + touch speaker (cyd) -git: d874cb1 +git: 156d9cf 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 51A8044247B56F0E95F118490189ECD6B05E0014ACE5607AC1A1FCD666466FDE + firmware.bin 3A23773415A312ABE3DAE81652F22C618A0839C8DCCA77B10AF16682DD5E2BD0 partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1 diff --git a/firmware/cyd/firmware.bin b/firmware/cyd/firmware.bin index 300b5e9..0263d63 100644 Binary files a/firmware/cyd/firmware.bin and b/firmware/cyd/firmware.bin differ diff --git a/include/bus_vspi.h b/include/bus_vspi.h deleted file mode 100644 index a853d44..0000000 --- a/include/bus_vspi.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -#include - -// CYD:触摸与 SD 共用 VSPI,按需切换引脚 -SPIClass &cyd_vspi(); -void cyd_vspi_select_touch(); -void cyd_vspi_select_sd(); diff --git a/include/pins.h b/include/pins.h index 7bcca58..eb26129 100644 --- a/include/pins.h +++ b/include/pins.h @@ -14,7 +14,7 @@ // 板载 SC8002B 功放 → P4 喇叭座(DAC2) #define SPEAKER_PIN 26 -// 触摸 XPT2046(SoftSPI,避开 VSPI;勿用 TOUCH_CS,会与 TFT_eSPI 冲突) +// 触摸 XPT2046(SoftSPI 专用脚,VSPI 留给 SD;勿用 TOUCH_CS,会与 TFT_eSPI 冲突) #define CYD_TOUCH_IRQ 36 #define CYD_TOUCH_MOSI 32 #define CYD_TOUCH_MISO 39 diff --git a/platformio.ini b/platformio.ini index 1d2bfd0..5d72fc5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,7 +9,6 @@ board_build.partitions = default.csv lib_deps = bodmer/TFT_eSPI@^2.5.43 lvgl/lvgl@9.2.2 - https://github.com/PaulStoffregen/XPT2046_Touchscreen.git build_flags = -DCORE_DEBUG_LEVEL=0 diff --git a/src/bus_vspi.cpp b/src/bus_vspi.cpp deleted file mode 100644 index 6db60bd..0000000 --- a/src/bus_vspi.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "bus_vspi.h" -#include "pins.h" - -#include - -static SPIClass g_vspi(VSPI); -static bool g_touch_pins = false; - -SPIClass &cyd_vspi() { - return g_vspi; -} - -void cyd_vspi_select_touch() { - // 释放 SD CS,避免挂总线 - pinMode(SD_CS, OUTPUT); - digitalWrite(SD_CS, HIGH); - g_vspi.begin(CYD_TOUCH_CLK, CYD_TOUCH_MISO, CYD_TOUCH_MOSI, CYD_TOUCH_CS); - g_touch_pins = true; -} - -void cyd_vspi_select_sd() { - pinMode(CYD_TOUCH_CS, OUTPUT); - digitalWrite(CYD_TOUCH_CS, HIGH); - g_vspi.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS); - g_touch_pins = false; -} diff --git a/src/sd_info.cpp b/src/sd_info.cpp index c127d37..b5e1394 100644 --- a/src/sd_info.cpp +++ b/src/sd_info.cpp @@ -1,11 +1,11 @@ #include "sd_info.h" -#include "bus_vspi.h" #include "pins.h" #include #include #include +static SPIClass sd_spi(VSPI); static bool sd_ready = false; static const char *card_type_name(uint8_t t) { @@ -60,12 +60,13 @@ bool sd_init() { pinMode(SD_CS, OUTPUT); digitalWrite(SD_CS, HIGH); + // 触摸 SoftSPI CS 拉高,避免干扰(脚位不同,但防误选) pinMode(CYD_TOUCH_CS, OUTPUT); digitalWrite(CYD_TOUCH_CS, HIGH); - cyd_vspi_select_sd(); + sd_spi.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS); - if (!SD.begin(SD_CS, cyd_vspi(), 25000000)) { + if (!SD.begin(SD_CS, sd_spi, 25000000)) { sd_ready = false; return false; } @@ -76,7 +77,6 @@ bool sd_init() { void sd_deinit() { if (sd_ready) { - cyd_vspi_select_sd(); SD.end(); sd_ready = false; } @@ -94,8 +94,6 @@ SdCardInfo sd_read_info() { info.free_bytes = 0; info.root_files = 0; - cyd_vspi_select_sd(); - if (!sd_ready && !sd_init()) { info.error = "Mount failed"; return info; diff --git a/src/touch.cpp b/src/touch.cpp index f11bbec..6948c98 100644 --- a/src/touch.cpp +++ b/src/touch.cpp @@ -1,12 +1,13 @@ #include "touch.h" -#include "bus_vspi.h" #include "pins.h" -#include #include -// 与 temperature 完全相同的硬件触摸驱动 -static XPT2046_Touchscreen touchscreen(CYD_TOUCH_CS, CYD_TOUCH_IRQ); +/** + * SoftSPI XPT2046(与 SD 的 VSPI 分脚,互不抢总线) + * 标定对齐 temperature(rot2 + map 到 UI 320x240),再反变换喂给 LVGL + * ROTATION_270(见 lv_indev.c):out=(y_in, 239-x_in) + */ int16_t g_dbg_phys_x = -1; int16_t g_dbg_phys_y = -1; @@ -14,35 +15,74 @@ int16_t g_dbg_logic_x = -1; int16_t g_dbg_logic_y = -1; bool g_dbg_touch_down = false; -void touch_init() { - pinMode(CYD_TOUCH_IRQ, INPUT); - pinMode(CYD_TOUCH_CS, OUTPUT); - digitalWrite(CYD_TOUCH_CS, HIGH); - pinMode(SD_CS, OUTPUT); - digitalWrite(SD_CS, HIGH); - - cyd_vspi_select_touch(); - if (!touchscreen.begin(cyd_vspi())) { - Serial.println("Touch: begin FAILED"); +static void soft_write(uint8_t data) { + for (int i = 7; i >= 0; --i) { + digitalWrite(CYD_TOUCH_MOSI, (data >> i) & 1); + digitalWrite(CYD_TOUCH_CLK, HIGH); + delayMicroseconds(2); + digitalWrite(CYD_TOUCH_CLK, LOW); + delayMicroseconds(2); } - touchscreen.setRotation(2); // temperature 相同 - Serial.println("Touch: XPT2046 + temp map + LVGL inverse"); +} + +static uint16_t soft_read12() { + uint16_t v = 0; + digitalWrite(CYD_TOUCH_CLK, HIGH); + delayMicroseconds(2); + digitalWrite(CYD_TOUCH_CLK, LOW); + delayMicroseconds(2); + for (int i = 0; i < 12; ++i) { + digitalWrite(CYD_TOUCH_CLK, HIGH); + delayMicroseconds(2); + v = (uint16_t)((v << 1) | (digitalRead(CYD_TOUCH_MISO) ? 1u : 0u)); + digitalWrite(CYD_TOUCH_CLK, LOW); + delayMicroseconds(2); + } + return v; +} + +static uint16_t xpt_read(uint8_t cmd) { + digitalWrite(CYD_TOUCH_CS, LOW); + soft_write(cmd); + uint16_t v = soft_read12(); + digitalWrite(CYD_TOUCH_CS, HIGH); + return v; +} + +void touch_init() { + pinMode(CYD_TOUCH_CS, OUTPUT); + pinMode(CYD_TOUCH_CLK, OUTPUT); + pinMode(CYD_TOUCH_MOSI, OUTPUT); + pinMode(CYD_TOUCH_MISO, INPUT); + pinMode(CYD_TOUCH_IRQ, INPUT); + digitalWrite(CYD_TOUCH_CS, HIGH); + digitalWrite(CYD_TOUCH_CLK, LOW); + Serial.println("Touch: SoftSPI + temp map + LVGL inverse"); } void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) { - cyd_vspi_select_touch(); + uint16_t raw_x = xpt_read(0x90); + uint16_t raw_y = xpt_read(0xD0); + raw_x = (uint16_t)((raw_x + xpt_read(0x90)) / 2); + raw_y = (uint16_t)((raw_y + xpt_read(0xD0)) / 2); - if (!(touchscreen.tirqTouched() && touchscreen.touched())) { - g_dbg_touch_down = false; + const bool irq = (digitalRead(CYD_TOUCH_IRQ) == LOW); + const bool in_range = + (raw_x > 80 && raw_x < 4000 && raw_y > 80 && raw_y < 4000); + + if (!in_range || (!irq && (raw_x < 200 || raw_y < 200))) { data->state = LV_INDEV_STATE_RELEASED; + g_dbg_touch_down = false; return; } - TS_Point p = touchscreen.getPoint(); + // XPT2046_Touchscreen setRotation(2) + const int16_t p_x = (int16_t)raw_x; + const int16_t p_y = (int16_t)(4095 - raw_y); - // 1) 与 temperature 相同:得到「屏幕上看到的」横屏坐标 320x240 - int16_t lx = map(p.y, 240, 3800, 1, UI_HOR_RES); - int16_t ly = map(p.x, 200, 3700, UI_VER_RES, 1); + // temperature 横屏 UI 坐标 + int16_t lx = map(p_y, 240, 3800, 1, UI_HOR_RES); + int16_t ly = map(p_x, 200, 3700, UI_VER_RES, 1); if (lx < 0) { lx = 0; @@ -57,17 +97,12 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) { ly = UI_VER_RES - 1; } - // 2) LVGL 在 ROTATION_270 时还会变换一次(create 240x320): - // lx_out = y_in - // ly_out = hor_res - 1 - x_in (hor_res = 240) - // 故要让最终 = (lx, ly),应上报: - // x_in = 239 - ly - // y_in = lx + // 反变换:让 LVGL ROTATION_270 之后落到 (lx, ly) const int16_t x_in = (int16_t)((SCREEN_WIDTH - 1) - ly); const int16_t y_in = lx; - g_dbg_phys_x = p.x; - g_dbg_phys_y = p.y; + g_dbg_phys_x = p_x; + g_dbg_phys_y = p_y; g_dbg_logic_x = lx; g_dbg_logic_y = ly; g_dbg_touch_down = true; @@ -75,8 +110,8 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) { static uint32_t last_log = 0; if (millis() - last_log > 120) { last_log = millis(); - Serial.printf("Touch raw(%d,%d) UI(%d,%d) feed(%d,%d)\n", p.x, p.y, lx, ly, - x_in, y_in); + Serial.printf("Touch raw(%u,%u) UI(%d,%d) feed(%d,%d)\n", raw_x, raw_y, lx, + ly, x_in, y_in); } data->point.x = x_in;