fix XPT2046 sampling to IRQ-only with stable screen mapping.
Reject idle ADC noise (y stuck at full scale) that caused ghost clicks; keep Y-mirror mapping for mode-select. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
956eeee1a5
commit
5a9f7c81ea
|
|
@ -20,9 +20,9 @@ void XPT2046_Init(void)
|
|||
gpio_init_struct.gpio_pins = TP_CLK_PIN | TP_DIN_PIN | TP_CS_PIN;
|
||||
gpio_init(GPIOC, &gpio_init_struct);
|
||||
|
||||
// 输入引脚:OUT(上拉)、IRQ(上拉)
|
||||
// DOUT:浮空输入(内部上拉易把空闲读成满量程)
|
||||
gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
|
||||
gpio_init_struct.gpio_pull = GPIO_PULL_UP;
|
||||
gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
|
||||
gpio_init_struct.gpio_pins = TP_OUT_PIN;
|
||||
gpio_init(TP_OUT_PORT, &gpio_init_struct);
|
||||
|
||||
|
|
@ -92,13 +92,12 @@ void TP_Write_Byte(uint8_t data)
|
|||
//从触摸屏IC读取adc值
|
||||
//CMD:指令
|
||||
//返回值:读到的数据
|
||||
uint16_t TP_Read_AD(uint8_t cmd)
|
||||
/* 在 CS 已拉低时写命令并读:与量产一致,16 时钟取高 12bit */
|
||||
static uint16_t TP_Read_AD_CSHeld(uint8_t cmd)
|
||||
{
|
||||
uint8_t i;
|
||||
uint16_t adc_val = 0;
|
||||
|
||||
TP_CS_Clr();
|
||||
Delay_us(2);
|
||||
TP_Write_Byte(cmd);
|
||||
Delay_us(6);
|
||||
|
||||
|
|
@ -113,91 +112,93 @@ uint16_t TP_Read_AD(uint8_t cmd)
|
|||
adc_val |= 0x01;
|
||||
}
|
||||
|
||||
return (uint16_t)(adc_val >> 4);
|
||||
}
|
||||
|
||||
uint16_t TP_Read_AD(uint8_t cmd)
|
||||
{
|
||||
uint16_t v;
|
||||
|
||||
TP_CS_Clr();
|
||||
Delay_us(2);
|
||||
v = TP_Read_AD_CSHeld(cmd);
|
||||
TP_CS_Set();
|
||||
return adc_val >> 4;
|
||||
return v;
|
||||
}
|
||||
|
||||
uint8_t TP_CheckPressed(uint8_t n)
|
||||
#define TP_ADC_PRESS_MIN 120u
|
||||
#define TP_ADC_PRESS_MAX 4095u
|
||||
#define TP_PRESSURE_MIN 80u
|
||||
/* 本板 IRQ 无效;压力仅作弱参考,不过度拦截(真触摸 z 也常偏大) */
|
||||
#define TP_PRESSURE_MAX 5000u
|
||||
|
||||
static uint16_t TP_Median5(uint16_t *a)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
uint8_t i, j;
|
||||
uint16_t t;
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
for (j = (uint8_t)(i + 1U); j < 5U; j++) {
|
||||
if (a[j] < a[i]) {
|
||||
t = a[i];
|
||||
a[i] = a[j];
|
||||
a[j] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
return a[2];
|
||||
}
|
||||
|
||||
static void TP_SampleXY(uint16_t *out_x, uint16_t *out_y)
|
||||
{
|
||||
uint16_t xs[5], ys[5];
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (TP_IRQ_Read() == 0)
|
||||
count++;
|
||||
Delay_us(100);
|
||||
}
|
||||
return (count >= (n / 2)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static uint16_t TP_SampleAxis(uint8_t cmd)
|
||||
{
|
||||
(void)TP_Read_AD(cmd);
|
||||
for (i = 0; i < 5; i++) {
|
||||
xs[i] = TP_Read_AD(XPT2046_READ_X);
|
||||
Delay_us(15);
|
||||
return TP_Read_AD(cmd);
|
||||
}
|
||||
|
||||
TP_Point TP_ReadRaw(void)
|
||||
{
|
||||
TP_Point p = {0, 0, 0};
|
||||
uint32_t x_sum = 0, y_sum = 0;
|
||||
uint8_t i;
|
||||
static uint8_t s_raw_logged;
|
||||
|
||||
if (!TP_CheckPressed(3)) {
|
||||
s_raw_logged = 0U;
|
||||
return p;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
x_sum += TP_SampleAxis(XPT2046_READ_X);
|
||||
Delay_us(15);
|
||||
y_sum += TP_SampleAxis(XPT2046_READ_Y);
|
||||
ys[i] = TP_Read_AD(XPT2046_READ_Y);
|
||||
Delay_us(15);
|
||||
}
|
||||
|
||||
p.x = (uint16_t)(x_sum / 5);
|
||||
p.y = (uint16_t)(y_sum / 5);
|
||||
*out_x = TP_Median5(xs);
|
||||
*out_y = TP_Median5(ys);
|
||||
}
|
||||
|
||||
/* Y 通道常为 0 时,交换 X/Y 命令再采一次 */
|
||||
if (p.y < 80u && p.x > 80u)
|
||||
static uint16_t TP_ReadPressure(void)
|
||||
{
|
||||
uint32_t sx = 0, sy = 0;
|
||||
uint16_t z1, z2;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
sx += TP_SampleAxis(XPT2046_READ_Y);
|
||||
z1 = TP_Read_AD(XPT2046_READ_Z1);
|
||||
Delay_us(15);
|
||||
sy += TP_SampleAxis(XPT2046_READ_X);
|
||||
Delay_us(15);
|
||||
}
|
||||
if (sy / 3u > p.y)
|
||||
{
|
||||
p.x = (uint16_t)(sx / 3);
|
||||
p.y = (uint16_t)(sy / 3);
|
||||
}
|
||||
z2 = TP_Read_AD(XPT2046_READ_Z2);
|
||||
|
||||
return (z1 > z2) ? (uint16_t)(z1 - z2) : 0U;
|
||||
}
|
||||
|
||||
p.pressed = 1;
|
||||
if (!s_raw_logged) {
|
||||
LOG_TP("raw x=%u y=%u irq=%u", (unsigned)p.x, (unsigned)p.y,
|
||||
(unsigned)(TP_IRQ_Read() == 0U));
|
||||
s_raw_logged = 1U;
|
||||
}
|
||||
return p;
|
||||
static uint8_t TP_AdcCoordValid(uint16_t x, uint16_t y)
|
||||
{
|
||||
/* 仅排除明显无效;双高在本板上也可能是真触摸(Y 常贴高,垂直靠 raw.x) */
|
||||
if (x < TP_ADC_PRESS_MIN && y < TP_ADC_PRESS_MIN)
|
||||
return 0U;
|
||||
if (x > 4000u && y > 4000u)
|
||||
return 0U;
|
||||
return (x <= TP_ADC_PRESS_MAX && y <= TP_ADC_PRESS_MAX) ? 1U : 0U;
|
||||
}
|
||||
|
||||
#define CALIB_X_MIN 200
|
||||
#define CALIB_X_MAX 3800
|
||||
#define CALIB_Y_MIN 200
|
||||
#define CALIB_Y_MAX 3800
|
||||
#define CALIB_Y_MAX 3950
|
||||
|
||||
/* 竖屏:多数 ILI9341+XPT2046 板级需 XY 对调;X 镜像与历史 240-tp.x 一致 */
|
||||
#define TP_SWAP_XY 1
|
||||
#define TP_MIRROR_X 1
|
||||
#define TP_MIRROR_Y 0
|
||||
/*
|
||||
* 实测(IRQ 有效按下):raw.x 常贴高,上下主要改 raw.y → 不要 SWAP。
|
||||
* Y 镜像:上方「万能」对应更大 raw.y。
|
||||
* 空闲 ADC 噪声是 raw.y=4095,禁止走 ADC 回退,否则幽灵点击。
|
||||
*/
|
||||
#define TP_SWAP_XY 0
|
||||
#define TP_MIRROR_X 0
|
||||
#define TP_MIRROR_Y 1
|
||||
|
||||
static uint16_t TP_MapAxis(uint16_t adc, uint16_t adc_min, uint16_t adc_max, uint16_t px_max)
|
||||
{
|
||||
|
|
@ -221,32 +222,120 @@ static uint16_t TP_MapAxis(uint16_t adc, uint16_t adc_min, uint16_t adc_max, uin
|
|||
return (uint16_t)px;
|
||||
}
|
||||
|
||||
TP_Point TP_Read(void)
|
||||
static void TP_RawToScreen(uint16_t raw_x, uint16_t raw_y, uint16_t *sx, uint16_t *sy)
|
||||
{
|
||||
TP_Point raw = TP_ReadRaw();
|
||||
TP_Point calib = {0, 0, raw.pressed};
|
||||
uint16_t ax, ay;
|
||||
|
||||
if (!raw.pressed)
|
||||
return calib;
|
||||
|
||||
#if TP_SWAP_XY
|
||||
ax = TP_MapAxis(raw.y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_W - 1));
|
||||
ay = TP_MapAxis(raw.x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_H - 1));
|
||||
ax = TP_MapAxis(raw_y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_W - 1));
|
||||
ay = TP_MapAxis(raw_x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_H - 1));
|
||||
#else
|
||||
ax = TP_MapAxis(raw.x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_W - 1));
|
||||
ay = TP_MapAxis(raw.y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_H - 1));
|
||||
ax = TP_MapAxis(raw_x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_W - 1));
|
||||
ay = TP_MapAxis(raw_y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_H - 1));
|
||||
#endif
|
||||
|
||||
#if TP_MIRROR_X
|
||||
ax = (uint16_t)(LCD_W - 1 - ax);
|
||||
#endif
|
||||
#if TP_MIRROR_Y
|
||||
ay = (uint16_t)(LCD_H - 1 - ay);
|
||||
#endif
|
||||
*sx = ax;
|
||||
*sy = ay;
|
||||
}
|
||||
|
||||
calib.x = ax;
|
||||
calib.y = ay;
|
||||
void TP_LogStatus(void)
|
||||
{
|
||||
uint16_t x, y, z;
|
||||
uint16_t sx, sy;
|
||||
|
||||
z = TP_ReadPressure();
|
||||
TP_SampleXY(&x, &y);
|
||||
TP_RawToScreen(x, y, &sx, &sy);
|
||||
LOG_TPI("status irq=%u z=%u raw=%u,%u cal=%u,%u",
|
||||
(unsigned)(TP_IRQ_Read() == 0U),
|
||||
(unsigned)z,
|
||||
(unsigned)x, (unsigned)y,
|
||||
(unsigned)sx, (unsigned)sy);
|
||||
}
|
||||
|
||||
static uint8_t s_tp_live;
|
||||
|
||||
void TP_SetLiveMode(uint8_t on)
|
||||
{
|
||||
s_tp_live = on ? 1U : 0U;
|
||||
LOG_TPI("live %s (events only)", s_tp_live ? "on" : "off");
|
||||
}
|
||||
|
||||
/* 不再空闲刷屏;按下事件仍由 touch task 的 scan/press/release 打印 */
|
||||
void TP_LivePoll(void)
|
||||
{
|
||||
(void)s_tp_live;
|
||||
}
|
||||
|
||||
uint8_t TP_CheckPressed(uint8_t n)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
if (TP_IRQ_Read() == 0)
|
||||
count++;
|
||||
Delay_us(100);
|
||||
}
|
||||
return (count >= ((n + 1U) / 2U)) ? 1U : 0U;
|
||||
}
|
||||
|
||||
TP_Point TP_ReadRaw(void)
|
||||
{
|
||||
TP_Point p = {0, 0, 0};
|
||||
uint8_t irq_pressed;
|
||||
static uint8_t s_raw_logged;
|
||||
uint16_t rx, ry;
|
||||
|
||||
irq_pressed = TP_CheckPressed(3);
|
||||
if (!irq_pressed) {
|
||||
/*
|
||||
* 空闲时 ADC 常读成 y=4095,会误触发幽灵点击。
|
||||
* 本板真触摸 IRQ 能拉低,只认 IRQ 路径。
|
||||
*/
|
||||
s_raw_logged = 0U;
|
||||
return p;
|
||||
}
|
||||
|
||||
TP_SampleXY(&rx, &ry);
|
||||
if (!TP_AdcCoordValid(rx, ry)) {
|
||||
s_raw_logged = 0U;
|
||||
return p;
|
||||
}
|
||||
|
||||
p.x = rx;
|
||||
p.y = ry;
|
||||
p.pressed = 1;
|
||||
if (!s_raw_logged) {
|
||||
LOG_TPI("raw x=%u y=%u irq=1", (unsigned)p.x, (unsigned)p.y);
|
||||
s_raw_logged = 1U;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
TP_Point TP_Read(void)
|
||||
{
|
||||
TP_Point raw = TP_ReadRaw();
|
||||
TP_Point calib = {0, 0, raw.pressed};
|
||||
static uint8_t s_cal_logged;
|
||||
|
||||
if (!raw.pressed) {
|
||||
s_cal_logged = 0U;
|
||||
return calib;
|
||||
}
|
||||
|
||||
TP_RawToScreen(raw.x, raw.y, &calib.x, &calib.y);
|
||||
if (!s_cal_logged) {
|
||||
LOG_TPI("cal x=%u y=%u (raw %u,%u)", (unsigned)calib.x, (unsigned)calib.y,
|
||||
(unsigned)raw.x, (unsigned)raw.y);
|
||||
s_cal_logged = 1U;
|
||||
}
|
||||
return calib;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#define TP_DIN_Clr() gpio_bits_reset(TP_DIN_PORT, TP_DIN_PIN) // DIN输出低(MCU→XPT2046)
|
||||
#define TP_DIN_Set() gpio_bits_set(TP_DIN_PORT, TP_DIN_PIN) // DIN输出高(MCU→XPT2046)
|
||||
|
||||
// XPT2046命令(与 BOOT 工程一致)
|
||||
/* 与量产/BOOT 一致:PD1:PD0=00(转换后掉电);时序用 16clk>>4 */
|
||||
#define XPT2046_READ_X 0xD0
|
||||
#define XPT2046_READ_Y 0x90
|
||||
#define XPT2046_READ_Z1 0xB0
|
||||
|
|
@ -64,6 +64,9 @@ extern uint16_t TP_Read_AD(uint8_t CMD); // 从触摸屏IC读取adc值
|
|||
extern uint8_t TP_CheckPressed(uint8_t n); // 简单去抖动读取(连续n次相同状态视为有效)
|
||||
extern TP_Point TP_ReadRaw(void); // 读取原始坐标(未校准)
|
||||
extern TP_Point TP_Read(void); // 校准后获取LCD坐标
|
||||
extern void TP_LogStatus(void); // 打印 IRQ/ADC 诊断(RTT tp status)
|
||||
extern void TP_SetLiveMode(uint8_t on); // 实时采样日志开关(RTT tp live / tp live off)
|
||||
extern void TP_LivePoll(void); // live 模式下周期性打印 raw/cal
|
||||
|
||||
extern void EXTI15_10_IRQHandler(void); // EXTI15_10中断服务函数(处理TP_IRQ触发)
|
||||
//extern void HAL_EXTI_Callback(EXTI_HandleTypeDef *hexti); // 中断回调函数(触摸触发时执行)
|
||||
|
|
|
|||
Loading…
Reference in New Issue