Wrong BL=21 caused black screens; INT stays on 21 as polling input after reset. Co-authored-by: Cursor <cursoragent@cursor.com>
285 lines
7.5 KiB
C++
285 lines
7.5 KiB
C++
#include "touch.h"
|
|
#include "pins.h"
|
|
|
|
#include <Arduino.h>
|
|
|
|
#if defined(CYD_BOARD_3248S035)
|
|
#include <Wire.h>
|
|
#endif
|
|
|
|
/**
|
|
* 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;
|
|
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 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);
|
|
digitalWrite(CYD_TOUCH_CLK, HIGH);
|
|
delayMicroseconds(2);
|
|
digitalWrite(CYD_TOUCH_CLK, LOW);
|
|
delayMicroseconds(2);
|
|
}
|
|
}
|
|
|
|
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 + diagonal fix (BL/TR)");
|
|
}
|
|
|
|
void touch_read_cb(lv_indev_t * /*indev*/, lv_indev_data_t *data) {
|
|
uint16_t adc_x = xpt_read(0x90);
|
|
uint16_t adc_y = xpt_read(0xD0);
|
|
adc_x = (uint16_t)((adc_x + xpt_read(0x90)) / 2);
|
|
adc_y = (uint16_t)((adc_y + xpt_read(0xD0)) / 2);
|
|
|
|
const bool irq = (digitalRead(CYD_TOUCH_IRQ) == LOW);
|
|
const bool in_range =
|
|
(adc_x > 80 && adc_x < 4000 && adc_y > 80 && adc_y < 4000);
|
|
|
|
if (!in_range || (!irq && (adc_x < 200 || adc_y < 200))) {
|
|
data->state = LV_INDEV_STATE_RELEASED;
|
|
g_dbg_touch_down = false;
|
|
return;
|
|
}
|
|
|
|
const int16_t p_x = (int16_t)adc_x;
|
|
const int16_t p_y = (int16_t)(4095 - adc_y);
|
|
|
|
int16_t x = map(p_x, 200, 3700, 1, SCREEN_WIDTH);
|
|
int16_t y = map(p_y, 240, 3800, 1, SCREEN_HEIGHT);
|
|
x = clampi(x, 0, SCREEN_WIDTH - 1);
|
|
y = clampi(y, 0, SCREEN_HEIGHT - 1);
|
|
|
|
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,
|
|
UI_HOR_RES - 1);
|
|
int16_t ui_y = clampi((old_ux * (UI_VER_RES - 1)) / (UI_HOR_RES - 1), 0,
|
|
UI_VER_RES - 1);
|
|
|
|
const int16_t feed_x = (int16_t)((SCREEN_WIDTH - 1) - ui_y);
|
|
const int16_t feed_y = ui_x;
|
|
|
|
g_dbg_phys_x = x;
|
|
g_dbg_phys_y = y;
|
|
g_dbg_logic_x = ui_x;
|
|
g_dbg_logic_y = ui_y;
|
|
g_dbg_touch_down = true;
|
|
|
|
static uint32_t last_log = 0;
|
|
if (millis() - last_log > 80) {
|
|
last_log = millis();
|
|
Serial.printf("Touch UI(%d,%d)\n", ui_x, ui_y);
|
|
}
|
|
|
|
data->point.x = feed_x;
|
|
data->point.y = feed_y;
|
|
data->state = LV_INDEV_STATE_PRESSED;
|
|
}
|
|
|
|
#endif
|