diff --git a/CHANGELOG.md b/CHANGELOG.md index e008969..3d34e3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,15 @@ # Changelog +## 2026-10-17 — Restore LVGL touch + +- SoftSPI + LVGL `lv_indev` (with `lv_indev_set_display`). +- Same landscape map as `temperature`; IRQ optional (sample-range fallback). +- Larger clickable speaker/play buttons. + ## 2026-10-17 — Fix touch offset - SoftSPI touch now uses the same rotation=2 transform + map as `temperature`. -- Pressure (Z) sampling instead of IRQ-only; oversampled like XPT2046_Touchscreen. +- (Pressure-only path was too strict; superseded by restore above.) ## 2026-10-17 — Prebuilt firmware folder diff --git a/firmware/cyd/VERSION.txt b/firmware/cyd/VERSION.txt index a75a528..853ab79 100644 --- a/firmware/cyd/VERSION.txt +++ b/firmware/cyd/VERSION.txt @@ -1,5 +1,5 @@ name: CYD TF card + touch speaker (cyd) -git: b54e36b +git: fe4b085 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 48A37AE15A12242AE5B965D0A326E0D272CF62DB8137654A1528DD1ABE033192 + firmware.bin 6EA45305C88045B6ECBA897D200294C05570C19619F498BE25B57C2419B94DC4 partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1 diff --git a/firmware/cyd/firmware.bin b/firmware/cyd/firmware.bin index e4f0c74..4df47f8 100644 Binary files a/firmware/cyd/firmware.bin and b/firmware/cyd/firmware.bin differ diff --git a/src/main.cpp b/src/main.cpp index b0df454..59fff8d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,11 +47,13 @@ void setup() { lv_display_t *disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf)); + // 横屏;触点报物理 240x320,由 LVGL 做旋转变换 lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270); lv_indev_t *indev = lv_indev_create(); lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER); lv_indev_set_read_cb(indev, touch_read_cb); + lv_indev_set_display(indev, disp); ui_create(); diff --git a/src/touch.cpp b/src/touch.cpp index 13bbe74..172aa07 100644 --- a/src/touch.cpp +++ b/src/touch.cpp @@ -3,88 +3,43 @@ #include -// SoftSPI bitbang XPT2046 — 坐标变换对齐 temperature 工程(setRotation(2) + map) +/** + * SoftSPI XPT2046 → LVGL pointer indev + * 读数用简单稳定协议(此前能点到);坐标变换对齐 temperature(rot2 + map 320x240)。 + */ -static void clk_pulse() { - digitalWrite(CYD_TOUCH_CLK, HIGH); - delayMicroseconds(1); - digitalWrite(CYD_TOUCH_CLK, LOW); - delayMicroseconds(1); -} - -static void soft_spi_write8(uint8_t data) { +static void soft_write(uint8_t data) { for (int i = 7; i >= 0; --i) { digitalWrite(CYD_TOUCH_MOSI, (data >> i) & 1); - clk_pulse(); - } -} - -// 模拟 library 的 transfer16 >> 3(12-bit ADC) -static uint16_t soft_spi_transfer16_shr3() { - uint16_t v = 0; - for (int i = 0; i < 16; ++i) { digitalWrite(CYD_TOUCH_CLK, HIGH); - delayMicroseconds(1); - v = (v << 1) | (digitalRead(CYD_TOUCH_MISO) ? 1u : 0u); + delayMicroseconds(2); digitalWrite(CYD_TOUCH_CLK, LOW); - delayMicroseconds(1); + delayMicroseconds(2); } - return v >> 3; } -static uint16_t xpt_cmd_read(uint8_t cmd) { - soft_spi_write8(cmd); - return soft_spi_transfer16_shr3(); +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 int16_t best_two_avg(int16_t a, int16_t b, int16_t c) { - const int16_t ab = abs(a - b); - const int16_t ac = abs(a - c); - const int16_t bc = abs(b - c); - if (ab <= ac && ab <= bc) { - return (a + b) >> 1; - } - if (ac <= ab && ac <= bc) { - return (a + c) >> 1; - } - return (b + c) >> 1; -} - -// 返回 true 并写出 raw(已做 rotation=2,与 XPT2046_Touchscreen 一致) -static bool touch_sample(int16_t *out_x, int16_t *out_y) { +static uint16_t xpt_read(uint8_t cmd) { digitalWrite(CYD_TOUCH_CS, LOW); - - // Z 压力(参考 Stoffregen 库) - int16_t z1 = (int16_t)xpt_cmd_read(0xB1); - int16_t z2 = (int16_t)xpt_cmd_read(0xC1); - int z = z1 + 4095; - z -= (int16_t)xpt_cmd_read(0x91); - - int16_t data[6] = {0, 0, 0, 0, 0, 0}; - if (z >= 300) { - (void)xpt_cmd_read(0x91); // dummy X - data[0] = (int16_t)xpt_cmd_read(0xD1); // Y - data[1] = (int16_t)xpt_cmd_read(0x91); // X - data[2] = (int16_t)xpt_cmd_read(0xD1); - data[3] = (int16_t)xpt_cmd_read(0x91); - } - data[4] = (int16_t)xpt_cmd_read(0xD0); // Y power down - data[5] = (int16_t)xpt_cmd_read(0x00); - + soft_write(cmd); + uint16_t v = soft_read12(); digitalWrite(CYD_TOUCH_CS, HIGH); - - if (z < 300) { - return false; - } - - // 库内:x=avg(Y采样), y=avg(X采样) - const int16_t avg_y_cmd = best_two_avg(data[0], data[2], data[4]); - const int16_t avg_x_cmd = best_two_avg(data[1], data[3], data[5]); - - // setRotation(2) - *out_x = avg_x_cmd; - *out_y = 4095 - avg_y_cmd; - return true; + return v; } void touch_init() { @@ -95,18 +50,30 @@ void touch_init() { pinMode(CYD_TOUCH_IRQ, INPUT); digitalWrite(CYD_TOUCH_CS, HIGH); digitalWrite(CYD_TOUCH_CLK, LOW); - Serial.println("Touch: SoftSPI calib = temperature map (rot2)"); + Serial.println("Touch: LVGL indev SoftSPI"); } void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) { - int16_t p_x = 0; - int16_t p_y = 0; - if (!touch_sample(&p_x, &p_y)) { + // 不依赖 IRQ(部分板子 IRQ 不可靠):用采样有效性判断 + 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); + + 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; return; } - // 与 temperature/src/main.cpp 完全一致(逻辑横屏 320x240) + // XPT2046_Touchscreen setRotation(2) + const int16_t p_x = (int16_t)raw_x; + const int16_t p_y = (int16_t)(4095 - raw_y); + + // temperature 横屏逻辑坐标(UI 320x240) int16_t x = map(p_y, 240, 3800, 1, UI_HOR_RES); int16_t y = map(p_x, 200, 3700, UI_VER_RES, 1); @@ -123,6 +90,13 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) { y = UI_VER_RES - 1; } + static uint32_t last_log = 0; + if (millis() - last_log > 250) { + last_log = millis(); + Serial.printf("LVGL touch irq=%d raw(%u,%u) -> (%d,%d)\n", irq ? 1 : 0, raw_x, + raw_y, x, y); + } + data->point.x = x; data->point.y = y; data->state = LV_INDEV_STATE_PRESSED; diff --git a/src/ui.cpp b/src/ui.cpp index 8bac0b2..40ab4c1 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -130,8 +130,9 @@ void ui_create() { lv_obj_clear_flag(row_btns, LV_OBJ_FLAG_SCROLLABLE); btn_speaker = lv_button_create(row_btns); - lv_obj_set_size(btn_speaker, 145, 46); + lv_obj_set_size(btn_speaker, 148, 50); lv_obj_set_style_radius(btn_speaker, 8, 0); + lv_obj_add_flag(btn_speaker, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_event_cb(btn_speaker, on_speaker_clicked, LV_EVENT_CLICKED, nullptr); lbl_speaker = lv_label_create(btn_speaker); lv_label_set_text(lbl_speaker, "Speaker OFF"); @@ -139,8 +140,9 @@ void ui_create() { lv_obj_center(lbl_speaker); btn_play = lv_button_create(row_btns); - lv_obj_set_size(btn_play, 145, 46); + lv_obj_set_size(btn_play, 148, 50); lv_obj_set_style_radius(btn_play, 8, 0); + lv_obj_add_flag(btn_play, LV_OBJ_FLAG_CLICKABLE); lv_obj_add_event_cb(btn_play, on_play_clicked, LV_EVENT_CLICKED, nullptr); lbl_play = lv_label_create(btn_play); lv_label_set_text(lbl_play, "Play Music");