Fix 3.5" backlight to GPIO27 and document CYD board pitfalls.
Align cyd_35r with 3248S035C pinout (BL!=INT) and point to CYD_PROJECT_GUIDE. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-10-25 — 3.5" backlight pin correction
|
||||
|
||||
- `cyd_35r`: `TFT_BL` / `TFT_BL_PIN` **GPIO27** (was wrongly 21; 21 is GT911 INT).
|
||||
- Document board pitfalls in `../CYD_PROJECT_GUIDE.md` §1.1.
|
||||
|
||||
## 2026-10-18 — Pomodoro presets + custom minutes
|
||||
|
||||
- Duration presets: 1 / 3 / 5 / 10 minutes; `Set` opens numeric keypad (1–99).
|
||||
|
||||
12
README.md
12
README.md
@@ -1,10 +1,13 @@
|
||||
# CYD Pomodoro
|
||||
|
||||
ESP32-2432S028R:LVGL 横屏番茄钟,可选内置提示音,触控喇叭播放。
|
||||
默认板:**ESP32-2432S028R**(2.8"):LVGL 横屏番茄钟,可选内置提示音,触控喇叭播放。
|
||||
|
||||
可选 **3.5"**:`pio run -e cyd_35r`(ST7796 + GT911,背光 **GPIO27**)。
|
||||
跨板约定与避坑见上级目录 [`../CYD_PROJECT_GUIDE.md`](../CYD_PROJECT_GUIDE.md)(§1.1)。
|
||||
|
||||
## 功能
|
||||
|
||||
- SoftSPI 触摸(已标定,勿改 `src/touch.cpp` 映射)
|
||||
- SoftSPI 触摸(2.8,已标定,勿改 `src/touch.cpp` 映射);3.5C 为 GT911 I2C
|
||||
- 番茄钟:预设 1 / 3 / 5 / 10 分钟;`Set` 自定义输入;`+/-` 微调;Start / Pause / Reset
|
||||
- 结束音效:内置 Beep 列表自选(默认 Alarm),点名称可试听
|
||||
- 喇叭 GPIO26 + 音量滑条;TF 卡状态显示在右上角
|
||||
@@ -13,10 +16,13 @@ ESP32-2432S028R:LVGL 横屏番茄钟,可选内置提示音,触控喇叭播
|
||||
## 构建 / 烧录
|
||||
|
||||
```bash
|
||||
# 2.8"
|
||||
pio run -e cyd -t upload --upload-port COM3
|
||||
# 3.5" 电容板
|
||||
pio run -e cyd_35r -t upload --upload-port COM3
|
||||
```
|
||||
|
||||
或 `firmware/cyd/flash.bat`。
|
||||
或 `firmware/cyd/flash.bat`(2.8 预编译包)。
|
||||
|
||||
浏览器刷写(推荐):在 [`../cydweb`](../cydweb) 运行 `npm run dev`,打开 http://localhost:3000 ,选择 **CYD Pomodoro**。
|
||||
|
||||
|
||||
@@ -8,19 +8,25 @@
|
||||
#define SCREEN_HEIGHT 480
|
||||
#define UI_HOR_RES 480
|
||||
#define UI_VER_RES 320
|
||||
/* 3.5C capacitive GT911 (ESP32-3248S035C). GPIO33 is I2C SDA, not TOUCH_CS.
|
||||
* Backlight is GPIO27; INT is GPIO21 — they are NOT the same pin. */
|
||||
#define CYD_GT911_SDA 33
|
||||
#define CYD_GT911_SCL 32
|
||||
#define CYD_GT911_INT 21
|
||||
#define CYD_GT911_RST 25
|
||||
#else
|
||||
#define TFT_BL_PIN 21
|
||||
#define SCREEN_WIDTH 240
|
||||
#define SCREEN_HEIGHT 320
|
||||
#define UI_HOR_RES 320
|
||||
#define UI_VER_RES 240
|
||||
#endif
|
||||
|
||||
/* 2.8" CYD: dedicated SoftSPI touch bus. */
|
||||
#define CYD_TOUCH_IRQ 36
|
||||
#define CYD_TOUCH_MOSI 32
|
||||
#define CYD_TOUCH_MISO 39
|
||||
#define CYD_TOUCH_CLK 25
|
||||
#define CYD_TOUCH_CS 33
|
||||
#endif
|
||||
|
||||
/* Map 320x240 design coordinates onto the active UI resolution (identity on 2.8"). */
|
||||
#define UX(x) ((int)(((long)(x) * (UI_HOR_RES)) / 320))
|
||||
@@ -28,6 +34,13 @@
|
||||
#define UW(w) UX(w)
|
||||
#define UH(h) UY(h)
|
||||
|
||||
/* Partial frame buffer: 3.5 needs smaller ratio to fit DRAM. */
|
||||
#if defined(CYD_BOARD_3248S035)
|
||||
#define DRAW_BUF_DIV 20
|
||||
#else
|
||||
#define DRAW_BUF_DIV 10
|
||||
#endif
|
||||
|
||||
|
||||
#define SD_MISO 19
|
||||
#define SD_MOSI 23
|
||||
|
||||
@@ -54,19 +54,27 @@ build_flags =
|
||||
|
||||
extra_scripts = pre:copy_lv_conf.py
|
||||
|
||||
; Optional 3.5" CYD ESP32-3248S035 (ST7796 resistive). Default remains [env:cyd].
|
||||
; Optional 3.5" CYD ESP32-3248S035C (ST7796 + GT911 capacitive). Default [env:cyd].
|
||||
; Build: pio run -e cyd_35r
|
||||
; Keep TOUCH_CS=-1 — GPIO33 is GT911 SDA, not resistive touch CS.
|
||||
; TFT_BL=GPIO27 (not 21 — 21 is GT911 INT). See ../CYD_PROJECT_GUIDE.md §1.1
|
||||
[env:cyd_35r]
|
||||
extends = env:cyd
|
||||
build_unflags =
|
||||
-DILI9341_2_DRIVER=1
|
||||
-DTFT_WIDTH=240
|
||||
-DTFT_HEIGHT=320
|
||||
-DTFT_BL=21
|
||||
-DLV_MEM_SIZE=49152
|
||||
build_flags =
|
||||
${env:cyd.build_flags}
|
||||
-UILI9341_2_DRIVER
|
||||
-DST7796_DRIVER=1
|
||||
-UTFT_WIDTH
|
||||
-UTFT_HEIGHT
|
||||
-DTFT_WIDTH=320
|
||||
-DTFT_HEIGHT=480
|
||||
-UTFT_BL
|
||||
-DTFT_BL=27
|
||||
-DCYD_BOARD_3248S035=1
|
||||
-DUSE_HSPI_PORT
|
||||
-DSUPPORT_TRANSACTIONS
|
||||
-DTFT_RGB_ORDER=TFT_BGR
|
||||
-DLV_MEM_SIZE=32768
|
||||
|
||||
|
||||
191
src/touch.cpp
191
src/touch.cpp
@@ -3,10 +3,13 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if defined(CYD_BOARD_3248S035)
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SoftSPI XPT2046
|
||||
* BL↔TR 是矩形主对角线镜像(XY 对调),不是 180°(180° 会搞成 TL↔BR)。
|
||||
* 先按 rot2 得到旧 UI,再做对角修正,反变换喂给 LVGL 270。
|
||||
* 2.8": dedicated SoftSPI + BL/TR diagonal fix.
|
||||
* 3.5C (3248S035C): capacitive GT911 on I2C SDA33/SCL32/INT21/RST25.
|
||||
*/
|
||||
|
||||
int16_t g_dbg_phys_x = -1;
|
||||
@@ -15,6 +18,173 @@ int16_t g_dbg_logic_x = -1;
|
||||
int16_t g_dbg_logic_y = -1;
|
||||
bool g_dbg_touch_down = false;
|
||||
|
||||
static int16_t clampi(int32_t v, int32_t lo, int32_t hi) {
|
||||
if (v < lo) {
|
||||
return (int16_t)lo;
|
||||
}
|
||||
if (v > hi) {
|
||||
return (int16_t)hi;
|
||||
}
|
||||
return (int16_t)v;
|
||||
}
|
||||
|
||||
#if defined(CYD_BOARD_3248S035)
|
||||
|
||||
/* Minimal GT911 — no config rewrite (TAMC setResolution can hang Wire). */
|
||||
static uint8_t s_gt_addr = 0x5D;
|
||||
static constexpr uint16_t GT_POINT_INFO = 0x814E;
|
||||
static constexpr uint16_t GT_POINT_1 = 0x814F;
|
||||
|
||||
static bool gt_write8(uint16_t reg, uint8_t val) {
|
||||
Wire.beginTransmission(s_gt_addr);
|
||||
Wire.write((uint8_t)(reg >> 8));
|
||||
Wire.write((uint8_t)(reg & 0xFF));
|
||||
Wire.write(val);
|
||||
return Wire.endTransmission() == 0;
|
||||
}
|
||||
|
||||
static bool gt_read(uint16_t reg, uint8_t *buf, uint8_t len) {
|
||||
Wire.beginTransmission(s_gt_addr);
|
||||
Wire.write((uint8_t)(reg >> 8));
|
||||
Wire.write((uint8_t)(reg & 0xFF));
|
||||
if (Wire.endTransmission(false) != 0) {
|
||||
return false;
|
||||
}
|
||||
const uint8_t n = Wire.requestFrom(s_gt_addr, len);
|
||||
if (n != len) {
|
||||
return false;
|
||||
}
|
||||
for (uint8_t i = 0; i < len; i++) {
|
||||
buf[i] = Wire.read();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gt_probe(uint8_t addr) {
|
||||
Wire.beginTransmission(addr);
|
||||
return Wire.endTransmission() == 0;
|
||||
}
|
||||
|
||||
/* TAMC-compatible address select: INT low => 0x5D, INT high => 0x14 */
|
||||
static void gt_hw_reset(bool addr_0x14) {
|
||||
pinMode(CYD_GT911_INT, OUTPUT);
|
||||
pinMode(CYD_GT911_RST, OUTPUT);
|
||||
digitalWrite(CYD_GT911_INT, LOW);
|
||||
digitalWrite(CYD_GT911_RST, LOW);
|
||||
delay(10);
|
||||
digitalWrite(CYD_GT911_INT, addr_0x14 ? HIGH : LOW);
|
||||
delay(1);
|
||||
digitalWrite(CYD_GT911_RST, HIGH);
|
||||
delay(5);
|
||||
digitalWrite(CYD_GT911_INT, LOW);
|
||||
delay(50);
|
||||
/* Backlight is GPIO27 — leave INT as input for polling / optional IRQ. */
|
||||
pinMode(CYD_GT911_INT, INPUT);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
static bool gt_find_addr() {
|
||||
for (uint8_t a : {uint8_t(0x5D), uint8_t(0x14)}) {
|
||||
if (gt_probe(a)) {
|
||||
s_gt_addr = a;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void touch_init() {
|
||||
Serial.println("Touch: GT911 I2C capacitive (3.5C) minimal");
|
||||
Wire.begin(CYD_GT911_SDA, CYD_GT911_SCL);
|
||||
Wire.setClock(100000);
|
||||
#if defined(WIRE_HAS_TIMEOUT) || defined(ESP32)
|
||||
Wire.setTimeOut(50);
|
||||
#endif
|
||||
|
||||
if (!gt_find_addr()) {
|
||||
Serial.println("GT911 not found — hw reset 0x5D");
|
||||
gt_hw_reset(false);
|
||||
if (!gt_find_addr()) {
|
||||
Serial.println("GT911 not found — hw reset 0x14");
|
||||
gt_hw_reset(true);
|
||||
gt_find_addr();
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("GT911 probe 0x5D=%s 0x14=%s using=0x%02X\n",
|
||||
gt_probe(0x5D) ? "OK" : "no", gt_probe(0x14) ? "OK" : "no",
|
||||
s_gt_addr);
|
||||
Serial.printf("GT911 SDA=%d SCL=%d INT=%d RST=%d\n", CYD_GT911_SDA,
|
||||
CYD_GT911_SCL, CYD_GT911_INT, CYD_GT911_RST);
|
||||
}
|
||||
|
||||
void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
|
||||
uint8_t info = 0;
|
||||
static uint32_t last_log = 0;
|
||||
const bool do_log = (millis() - last_log > 200);
|
||||
|
||||
if (!gt_read(GT_POINT_INFO, &info, 1)) {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
g_dbg_touch_down = false;
|
||||
if (do_log) {
|
||||
last_log = millis();
|
||||
Serial.println("TouchProbe GT911 I2C err");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const uint8_t touches = info & 0x0F;
|
||||
const bool buffered = (info & 0x80) != 0;
|
||||
|
||||
if (!buffered || touches == 0) {
|
||||
if (buffered) {
|
||||
gt_write8(GT_POINT_INFO, 0);
|
||||
}
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
g_dbg_touch_down = false;
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pt[7];
|
||||
if (!gt_read(GT_POINT_1, pt, 7)) {
|
||||
gt_write8(GT_POINT_INFO, 0);
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
g_dbg_touch_down = false;
|
||||
return;
|
||||
}
|
||||
gt_write8(GT_POINT_INFO, 0);
|
||||
|
||||
const int16_t raw_x = (int16_t)(pt[1] | (pt[2] << 8));
|
||||
const int16_t raw_y = (int16_t)(pt[3] | (pt[4] << 8));
|
||||
|
||||
/* Native 320x480 → LVGL 270. Mirror long axis so L/R matches UI
|
||||
* (else preset 3 hits 10). Resulting UI ≈ (H-1-raw_y, raw_x). */
|
||||
const int16_t nx = clampi(raw_x, 0, SCREEN_WIDTH - 1);
|
||||
const int16_t ny = clampi(raw_y, 0, SCREEN_HEIGHT - 1);
|
||||
const int16_t feed_x = (int16_t)((SCREEN_WIDTH - 1) - nx);
|
||||
const int16_t feed_y = (int16_t)((SCREEN_HEIGHT - 1) - ny);
|
||||
const int16_t ui_x = (int16_t)((SCREEN_HEIGHT - 1) - ny);
|
||||
const int16_t ui_y = nx;
|
||||
|
||||
g_dbg_phys_x = raw_x;
|
||||
g_dbg_phys_y = raw_y;
|
||||
g_dbg_logic_x = ui_x;
|
||||
g_dbg_logic_y = ui_y;
|
||||
g_dbg_touch_down = true;
|
||||
|
||||
if (do_log) {
|
||||
last_log = millis();
|
||||
Serial.printf("Touch HIT GT911 raw(%d,%d) ~ui(%d,%d)\n", raw_x, raw_y,
|
||||
ui_x, ui_y);
|
||||
}
|
||||
|
||||
data->point.x = feed_x;
|
||||
data->point.y = feed_y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void soft_write(uint8_t data) {
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
digitalWrite(CYD_TOUCH_MOSI, (data >> i) & 1);
|
||||
@@ -49,16 +219,6 @@ static uint16_t xpt_read(uint8_t cmd) {
|
||||
return v;
|
||||
}
|
||||
|
||||
static int16_t clampi(int32_t v, int32_t lo, int32_t hi) {
|
||||
if (v < lo) {
|
||||
return (int16_t)lo;
|
||||
}
|
||||
if (v > hi) {
|
||||
return (int16_t)hi;
|
||||
}
|
||||
return (int16_t)v;
|
||||
}
|
||||
|
||||
void touch_init() {
|
||||
pinMode(CYD_TOUCH_CS, OUTPUT);
|
||||
pinMode(CYD_TOUCH_CLK, OUTPUT);
|
||||
@@ -94,8 +254,6 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
|
||||
x = clampi(x, 0, SCREEN_WIDTH - 1);
|
||||
y = clampi(y, 0, SCREEN_HEIGHT - 1);
|
||||
|
||||
// 旧 UI(LVGL270):(y, 239-x) — 该空间里 BL↔TR,做主对角线镜像
|
||||
// (ux,uy) -> (uy*(319/239), ux*(239/319))
|
||||
const int32_t old_ux = y;
|
||||
const int32_t old_uy = (SCREEN_WIDTH - 1) - x;
|
||||
int16_t ui_x = clampi((old_uy * (UI_HOR_RES - 1)) / (UI_VER_RES - 1), 0,
|
||||
@@ -103,7 +261,6 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
|
||||
int16_t ui_y = clampi((old_ux * (UI_VER_RES - 1)) / (UI_HOR_RES - 1), 0,
|
||||
UI_VER_RES - 1);
|
||||
|
||||
// 反变换喂 LVGL,使最终落在 (ui_x, ui_y)
|
||||
const int16_t feed_x = (int16_t)((SCREEN_WIDTH - 1) - ui_y);
|
||||
const int16_t feed_y = ui_x;
|
||||
|
||||
@@ -123,3 +280,5 @@ void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
|
||||
data->point.y = feed_y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user