I2C电容触摸屏(Atmel maXTouch)故障排查与解决
硬件平台:ATK-DLRK3568(Rockchip RK3568)
触摸芯片:Atmel maXTouch(型号系列,Family: 164, Variant: 54)
驱动:atmel_mxt_ts
一、初始问题:正常电压是多少?
1. I2C 触摸屏引脚电压(通用情况)
| 引脚 | 典型电压 | 说明 |
|---|---|---|
| VCC | 3.0V – 3.6V(最常见 3.3V) | 部分芯片支持 2.8V 或 5.0V,需查数据手册 |
| GND | 0V | 地 |
| SCL / SDA | 1.8V 或 3.3V(必须与主控IO电平一致) | 开漏输出,需外接上拉电阻(典型 4.7kΩ)至该电平 |
| INT(中断) | 1.8V 或 3.3V | 与主控IO电平匹配 |
| RST(复位) | 1.8V 或 3.3V | 与主控IO电平匹配 |
关键原则:实际电压以所用触摸屏的数据手册(Datasheet)为准;SCL/SDA 必须接上拉电阻,否则 I2C 无法通信。
二、系统日志分析(dmesg)
第一轮:引脚占用
[ 3.379548] atmel_mxt_ts 1-004a: Direct firmware load for maxtouch.cfg failed with error -2 [ 3.382094] rockchip-pinctrl pinctrl: pin gpio1-1 already requested by 1-004a; cannot claim for fe5c0000.i2c [ 3.382910] rockchip-pinctrl pinctrl: pin-33 (fe5c0000.i2c) status -22 [ 3.382927] rockchip-pinctrl pinctrl: could not request pin 33 (gpio1-1) from group i2c3m0-xfer on device rockchip-pinctrl [ 3.382989] rk3x-i2c: probe of fe5c0000.i2c failed with error -22触摸设备(地址 0x4a)占用了 gpio1-1,但 I2C 控制器 fe5c0000.i2c 也想用同一引脚。
排查步骤
- 读 touchscreen/maXTouch.dtsi:确认触摸节点声明了
touch-gpio = <&gpio1 RK_PA1>(INT)reset-gpio = <&gpio1 RK_PA0>(RST)- pinctrl 组
atmel_touch_gpio同样申请<1 RK_PA1>和<1 RK_PA0>
- 全树搜索
fe5c0000/i2c3:定位到两处关键定义rk3568.dtsi:3125→i2c3: i2c@fe5c0000,默认status="disabled",默认pinctrl-0 = <&i2c3m0_xfer>rk3568-pinctrl.dtsi:855-873→i2c3m0_xfer的成员引脚就是<1 RK_PA1>(scl_m0)和<1 RK_PA0>(sda_m0)
- 对照结论:冲突是100% 重叠,不是部分重叠:
| 物理引脚 | 内核 pin 编号 | 触摸驱动占用为 | i2c3m0_xfer 占用为 |
|---|---|---|---|
| GPIO1_A0 | pin 32 | reset-gpio | i2c3_sda_m0 |
| GPIO1_A1 | pin 33 | touch-gpio(INT) | i2c3_scl_m0 |
日志只报 gpio1-1 是因为 pinctrl 申请一个 pin group 时遇到第一个失败就中止并回退;实际上 gpio1-0 同样冲突。
日志中 i2c3 能走到 probe 阶段说明板级 DTS 某处把&i2c3置为"okay"(后来证实是rk3568-atk-evb1-ddr4-v10.dtsi:589的 LVDS 屏 gt911 触摸,无条件开了 i2c3)。
给出的三个方案
- 方案 A(推荐):若不用 i2c3,板级 DTS 显式
status = "disabled"。 - 方案 B:若硬件把 i2c3 走 m1 组(GPIO3_B5/B6),改
pinctrl-0 = <&i2c3m1_xfer>。 - 方案 C:若必须用 m0,只能挪触摸屏 RST/INT 到空闲 GPIO。
选择的是方案A
第二轮:evtest 列出设备但触摸无任何事件
现象(用户在板上实测)
$ dmesg | grep -iE "atmel" [ 3.378663] atmel_mxt_ts 1-004a: CHG pin isn't cleared [ 3.379383] atmel_mxt_ts 1-004a: Enabling RETRIGEN feature [ 3.381402] atmel_mxt_ts 1-004a: Direct firmware load for maxtouch.cfg failed with error -2 ... [ 3.387156] input: Atmel maXTouch Touchscreen as .../1-004a/input/input2- 对比第一轮日志:i2c3 引脚冲突那几行消失了(说明中间某次调整起效)。
- evtest 里
/dev/input/event2: Atmel maXTouch Touchscreen存在,ABS_X/ABS_Y 范围 1024×600 与芯片自报一致——注册链路完全正常。 - 但触摸屏幕 → evtest 零输出。
mxt_start: Starting也打印了(suspend/resume 框架正常)。
排查线索解读
两条可疑日志的含义:
CHG pin isn't cleared:驱动读 INT(CHG)引脚电平,期望复位后为低但读到高——在 INT 线接错引脚时会必然出现(读的是一根悬空/被上拉的无关系引脚)。Enabling RETRIGEN feature:驱动的兜底逻辑——如果硬件不支持自动重触发中断,就让固件在电平未释放时反复重发中断。随后RETRIGEN bit already enabled说明位已是 1。
这两条组合本身就是"INT 线没接到 CPU 实际监听的引脚"的典型指纹,但还需要 DTB 层面的证据。
关键证据:预处理产物.dtb.dts.tmp
打开了 IDE 中 IDE 打开的构建产物.rk3568-atk-evb1-ddr4-v10-linux.dtb.dts.tmp(C 预处理器展开后的最终 DTS,编译进 dtb 的就是它),在 L10886-L10931 找到最终生效的 atmel 节点:
touch-gpio = <&gpio1 1 8>; /* GPIO1_A1 */ reset-gpio = <&gpio1 0 1>; /* GPIO1_A0 */ interrupt-parent = <&gpio0>; interrupts = <21 2>; /* GPIO0_C5 */ pinctrl-0 = <&atmel_touch_gpio>; /* 申请的是 GPIO1_A1/A0 */而板级 DTSrk3568-atk-evb1-ddr4-v10.dtsi:564-587内联块写的是(与板上实际接线注释gpio3_c4---rst / gpio3_c5---int一致):
interrupt-parent = <&gpio3>; interrupts = <21 2>; /* GPIO3_C5 ✓ */ touch-gpio = <&gpio3 RK_PC5 IRQ_TYPE_LEVEL_LOW>; reset-gpio = <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH>;pinctrl 侧同样查实:.dtsi:871-876的atmel_touch_gpio申请<3 RK_PC5>/<3 RK_PC4>(正确);tmp 里的却是 GPIO1_A1/A0(错误)。
根因确认:include 顺序导致"后到者覆盖"
入口.dts的包含顺序:
#include "rk3568-atk-evb1-ddr4-v10.dtsi" /* L7 内联 atmel 块:GPIO3(正确) */ #include "rk3568-linux.dtsi" #include "rk3568-screen_choose.dtsi" #include "rk3568-lcds.dtsi" /* hxkj 2026.8.25 */ #include "touchscreen/maXTouch.dtsi" /* L12 最后包含:GPIO1/gpio0(错误) */DTC 对同名重复节点的合并规则是标量属性后者胜。maXTouch.dtsi作为最后一个 include,其错误引脚定义全部覆盖了前面正确的内联值。
于是形成了一条完整的因果链:
1-004a 的 IRQ 注册在 GPIO0_C5(interrupt-parent=&gpio0, interrupts=21) ↓ 而芯片 INT 硬件线接在 GPIO3_C5 ↓ CPU 永远等不到边沿 → 无中断 → 无 input event → evtest 无反应 同时 maXTouch.dtsi 的 pinctrl 把 GPIO1_A0/A1 当成 RST/INT 申请 ↓ GPIO1_A0/A1 恰好是 i2c3m0 的 SDA/SCL → i2c3 probe 失败(第一轮的冲突) ↓ 更早的表现:CHG pin isn't cleared + RETRIGEN 兜底三个表象、一个根因:都源自最后 include 的旧版maXTouch.dtsi。
顺带发现:旧版maXTouch.dtsi:22的注释自己写着"代表中断脚是gpio3下的第 21 脚",但interrupt-parent却写了&gpio0——作者本意是 gpio3,抄漏了一行。
第三轮:确定技术路线 —— 修正 maXTouch.dtsi 本身
用户明确表示"现在使用的是 maxTouch.dtsi"(保留 include 这条路线,并已将 include 还原激活)。因此策略改为:把 maXTouch.dtsi 的引脚改成与硬件一致的 GPIO3_C5/C4,而不是禁用 include。
对 touchscreen/maXTouch.dtsi 的修正矩阵:
| 属性 | 修正前(错) | 修正后(对) |
|---|---|---|
touch-gpio | <&gpio1 RK_PA1 IRQ_TYPE_LEVEL_LOW> | <&gpio3 RK_PC5 IRQ_TYPE_LEVEL_LOW> |
reset-gpio | <&gpio1 RK_PA0 GPIO_ACTIVE_LOW> | <&gpio3 RK_PC4 GPIO_ACTIVE_HIGH> |
interrupt-parent | <&gpio0> | <&gpio3> |
interrupts | <21 2>(不变) | <21 2>(gpio3 第 21 脚=RK_PC5=GPIO3_C5) |
pinctrlatmel_touch_gpio | <1 RK_PA1>、<1 RK_PA0> | <3 RK_PC5 &pcfg_pull_up>、<3 RK_PC4 &pcfg_pull_none> |
| 文件头接线注释 | gpio1_a0/a1 | gpio3_c4/c5 |
设计考量:
- IRQ 的两条获取路径(vendor 私有
touch-gpio经 gpiod_to_irq,或标准interrupt-parent+interrupts)都指向 GPIO3_C5,无论驱动走哪条都能命中。 reset-gpio极性沿用内联参考块的GPIO_ACTIVE_HIGH(板上有反相转换的可能性);且此前接线全错时芯片仍能被枚举,说明驱动走的是 T6 软复位,该属性大概率未被用到。- 补充保留
clock-frequency = <100000>于&i2c1(maXTouch.dtsi 原本有此设定;因 SoC dtsi 的 i2c1 无默认频率,若两种来源都丢失会回到驱动默认值)。 - maXTouch.dtsi 与内联块此时是"重复定义但取值一致",可正常编译;彻底去重方案见第“方法沉淀论”节。
三、evtest 测试无触摸事件
执行结果
evtest能列出/dev/input/event2(Atmel maXTouch Touchscreen)。- 选择该设备后,触摸屏幕无任何事件输出(无 ABS 或 KEY 报点)。
可能原因(排查方向)
- 中断引脚(INT)配置错误—— 最可能的原因。
- 硬件供电或电平不匹配。
- I2C 通信不稳定(但驱动已 probe 成功,可能性较低)。
- 触摸屏本身硬件故障。
四、定位并确认根本原因
最终确认
“问题出在
interrupts = <1 2>;引脚号配置错了”
解释:
interrupts = <1 2>;中的<1 2>表示GPIO1_1(Bank1,Pin1),触发方式为下降沿(2代表IRQ_TYPE_EDGE_FALLING)。- 实际硬件连接中,触摸屏的 INT 脚并没有接在 GPIO1_1,而是接在其他 GPIO 上。
- 因此触摸中断信号无法送达 CPU,导致无事件上报。
五、解决方案:修正设备树(Device Tree)
推荐做法(使用irq-gpios代替interrupts)
在atmel_mxt_ts节点中,避免直接使用数字编号,改用irq-gpios属性,更清晰且不易出错。
示例修改(假设实际 INT 脚为GPIO3_B2)
&i2c1 { /* 触摸屏所在 I2C 总线,根据日志为 i2c-1 */ atmel_mxt_ts@4a { compatible = "atmel,maxtouch"; reg = <0x4a>; pinctrl-names = "default"; pinctrl-0 = <&touch_int>; /* 若有 pinctrl 定义 */ /* 删除原来的 interrupts = <1 2>; */ // interrupts = <1 2>; /* 使用 irq-gpios 明确指定引脚和触发方式 */ irq-gpios = <&gpio3 RK_PB2 IRQ_TYPE_EDGE_FALLING>; /* 其他属性(reset-gpios, vdd-supply 等)保持不变 */ }; }; /* 在 pinctrl 中将该引脚配置为 GPIO 输入上拉(中断功能) */ &pinctrl { touch { touch_int: touch-int { rockchip,pins = <3 RK_PB2 RK_FUNC_GPIO &pcfg_pull_up>; }; }; };串口调试
查看i2c设备
i2c detect -y 1 # 应看到 0x4a 或 0x4b 显示 UU(表示被驱动占用)。最终要达到的状态是UU查看日志
dmesg | grep -iE "atmel" dmesg | grep -iE "i2c"检查中断是否正确注册:
cat /proc/interrupts | grep mxt # 应能看到一个中断号,并且其后有统计计数。触摸屏幕并观察中断计数是否增加:
cat /proc/interrupts | grep mxt # 触摸屏幕,再次执行,看数字是否增长运行 evtest 测试:
evtest # 触摸时应有 ABS_MT_POSITION_X、ABS_MT_POSITION_Y 等事件输出。可选:测量实际引脚电平:
空闲时 INT 脚应为高电平(3.3V),触摸时出现低电平脉冲。
引脚配置
SCL,SDA,rst,int电平注意要在2.8v以上,不超过3.3v如果电平不对,要么是引脚配置有问题要么是硬件有问题。这个要仔细排查确认。
除此之外还要注意引脚冲突问题,引脚复用问题。
引脚硬件配置:
Int,rst, scl, sda硬件作上拉(4.7k电阻)
引脚软件配置:
int配置上拉,下降沿触发(需要用户配置)
Rst配置上拉或者浮空(需要用户配置)
Scl配置上拉(一般板级驱动已经配置好了,不需要用户再次配置)
sda配置上拉(一般板级驱动已经配置好了,不需要用户再次配置)
遗留与次要事项
maxtouch.cfg failed with error -2(-ENOENT):/lib/firmware/maxtouch.cfg不存在。非致命——芯片使用其 flash 自带配置,自报分辨率与设备树一致。不需要随厂配置就忽略;需要调参再把 cfg 放进根文件系统/lib/firmware/或删除节点里的atmel,cfg_name行。touch-gpio/reset-gpio属私有属性:goodix gt9xx 风格命名,主线 atmel 驱动并不读取(vendor 版可能读)。保留无害,但注意 vendor 驱动版本升级时的兼容差异。- 重复定义治理(可选,非必需):当前"内联块 + maXTouch.dtsi"双份定义、内容一致,能工作但脆弱——将来任何人改其中一份都可能再次引入分裂。彻底做法二选一:
- 保留 maXTouch.dtsi 路线:删掉
.dtsi的#elif TP_ATMEL内联块,并把dsi_touch:标签搬到 maXTouch.dtsi 的节点上(否则lcds.dtsi无条件引用&dsi_touch会报 Label not found); - 或反过来禁用 include(第一轮曾给出的方案),一切以内联块为准。
搬标签前先用grep -rn "dsi_touch" lcds.dtsi复核引用点数量。
- 保留 maXTouch.dtsi 路线:删掉
- i2c3 的归属:
.dtsi:589无条件开启&i2c3挂 LVDS gt911。只要 LCD 宏不选 LVDS,lcds.dtsi 会把 lvds_touch 置 disabled,节点不会被 probe,本次冲突即消(这与日志相符)。若日后真用 LVDS 屏,需重新审视 m0/m1 引脚分配。 - reset 极性:若未来出现"休眠唤醒后触摸失灵需断电重启"类问题,优先尝试把
reset-gpio改回GPIO_ACTIVE_LOW并确认上电时序。
方法论沉淀(下次直接复用)
- DTS 不是"先到先得",是"后来居上":同名节点多次定义按顺序合并、标量属性最后一次赋值生效。判断"哪个值真正进了 dtb",唯一可靠证据是预处理产物
*.dtb.dts.tmp(或dtc -I dtb -O dts反编译成品)。看源码推断不如看产物实证。 - 出问题的总是最后加的那行 include:hxkj 注释标记(
/* hxkj 2026.8.25 */)就是变更路标;联调阶段遇到"昨天还好的今天坏了",先 diff 入口 .dts 的 include 列表。 - pin 冲突日志的正确读法:
pin X already requested by A; cannot claim for B—— 只报第一个失败引脚不代表只有它冲突;要拿 B 的 pin group 成员逐个和 A 的占用比对(本例就是 100% 双重叠)。 -2只是 errno:firmware load 的-ENOENT是文件不存在,优先检查根文件系统而不是怀疑驱动。- 输入子系统排障金字塔(自下而上):
本案中"设备注册完美 + 中断纹丝不动"精确定位到 IRQ 引脚层,避免了乱枪打鸟。evtest 有设备名且范围正确? ──否──> 驱动 probe/DTS 解析层 /proc/interrupts 对应中断计数递增? ──否──> 硬件连接/IRQ 注册引脚层(本案卡在这) 事件坐标正确但 GUI 无反应? ──────> 上层坐标变换/invert 配置层 - 注释说谎要交叉验证:
interrupts = <21 2> /*gpio3*/与interrupt-parent = <&gpio0>并存即互相矛盾——注释与代码不一致时,代码赢,但问题往往藏在注释想表达而代码没做到的地方。 - 宏污染教训延续(承接姊妹篇):DTS 会过 C 预处理器,连字符节点名会被拆 token;常用词做宏名(
gt911/atmel)等于埋雷,一律TP_前缀。