Fix touchscreen offset to match temperature calibration.
Apply XPT2046 rotation-2 transform and the same landscape map used by the climate project. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
# Changelog
|
||||
|
||||
## 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.
|
||||
|
||||
## 2026-10-17 — Prebuilt firmware folder
|
||||
|
||||
- Add `firmware/cyd/` with bin + `flash.ps1` / `flash.bat` (same pattern as temperature).
|
||||
|
||||
@@ -60,8 +60,7 @@ pio device monitor
|
||||
## 注意事项
|
||||
|
||||
- TF 需 **FAT/FAT32**。
|
||||
- 若触屏坐标偏移,改 `src/touch.cpp` 里 `map(...)` 校准范围。
|
||||
- 若点按无反应,检查排线/旋转;可尝试交换 raw_x/raw_y 映射。
|
||||
- 触屏校准与 `temperature` 工程一致(`setRotation(2)` + map);仍偏可改 `src/touch.cpp` 的 `map(...)` 边界。
|
||||
- 变更请更新 `CHANGELOG.md`、必要时重新 `export_from_build.ps1`,并提交本地 git。
|
||||
|
||||
## 版本
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: CYD TF card + touch speaker (cyd)
|
||||
git: f05c5d6
|
||||
git: b54e36b
|
||||
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 1FB845985551DBB1C92D5510278EFAF773311F4CE370B06F78585D397144FE87
|
||||
firmware.bin 48A37AE15A12242AE5B965D0A326E0D272CF62DB8137654A1528DD1ABE033192
|
||||
partitions.bin 148B959CBFF1C38AA8E1D5C0BA9D612C54997B945E56A63F41223EEF650653A1
|
||||
|
||||
Binary file not shown.
116
src/touch.cpp
116
src/touch.cpp
@@ -3,39 +3,88 @@
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
static void soft_spi_write(uint8_t data) {
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
digitalWrite(CYD_TOUCH_MOSI, (data >> i) & 1);
|
||||
digitalWrite(CYD_TOUCH_CLK, HIGH);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(CYD_TOUCH_CLK, LOW);
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
}
|
||||
// SoftSPI bitbang XPT2046 — 坐标变换对齐 temperature 工程(setRotation(2) + map)
|
||||
|
||||
static uint16_t soft_spi_read12() {
|
||||
uint16_t v = 0;
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
digitalWrite(CYD_TOUCH_CLK, HIGH);
|
||||
delayMicroseconds(1);
|
||||
v = (v << 1) | (digitalRead(CYD_TOUCH_MISO) ? 1 : 0);
|
||||
digitalWrite(CYD_TOUCH_CLK, LOW);
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
// 丢掉多余时钟位
|
||||
static void clk_pulse() {
|
||||
digitalWrite(CYD_TOUCH_CLK, HIGH);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(CYD_TOUCH_CLK, LOW);
|
||||
return v;
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
|
||||
static uint16_t xpt_read(uint8_t cmd) {
|
||||
static void soft_spi_write8(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);
|
||||
digitalWrite(CYD_TOUCH_CLK, LOW);
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
return v >> 3;
|
||||
}
|
||||
|
||||
static uint16_t xpt_cmd_read(uint8_t cmd) {
|
||||
soft_spi_write8(cmd);
|
||||
return soft_spi_transfer16_shr3();
|
||||
}
|
||||
|
||||
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) {
|
||||
digitalWrite(CYD_TOUCH_CS, LOW);
|
||||
soft_spi_write(cmd);
|
||||
delayMicroseconds(5);
|
||||
uint16_t v = soft_spi_read12();
|
||||
|
||||
// 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);
|
||||
|
||||
digitalWrite(CYD_TOUCH_CS, HIGH);
|
||||
return v;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void touch_init() {
|
||||
@@ -46,23 +95,20 @@ void touch_init() {
|
||||
pinMode(CYD_TOUCH_IRQ, INPUT);
|
||||
digitalWrite(CYD_TOUCH_CS, HIGH);
|
||||
digitalWrite(CYD_TOUCH_CLK, LOW);
|
||||
Serial.println("Touch: XPT2046 SoftSPI ready");
|
||||
Serial.println("Touch: SoftSPI calib = temperature map (rot2)");
|
||||
}
|
||||
|
||||
void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
|
||||
const bool irq = (digitalRead(CYD_TOUCH_IRQ) == LOW);
|
||||
|
||||
uint16_t raw_x = xpt_read(0x90);
|
||||
uint16_t raw_y = xpt_read(0xD0);
|
||||
|
||||
if (!irq || raw_x < 80 || raw_y < 80 || raw_x > 4000 || raw_y > 4000) {
|
||||
int16_t p_x = 0;
|
||||
int16_t p_y = 0;
|
||||
if (!touch_sample(&p_x, &p_y)) {
|
||||
data->state = LV_INDEV_STATE_RELEASED;
|
||||
return;
|
||||
}
|
||||
|
||||
// LV_DISPLAY_ROTATION_270 → 逻辑 320x240
|
||||
int16_t x = map((int)raw_y, 200, 3800, 0, UI_HOR_RES - 1);
|
||||
int16_t y = map((int)raw_x, 240, 3700, 0, UI_VER_RES - 1);
|
||||
// 与 temperature/src/main.cpp 完全一致(逻辑横屏 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);
|
||||
|
||||
if (x < 0) {
|
||||
x = 0;
|
||||
|
||||
Reference in New Issue
Block a user