工业人机界面HMI:触摸屏驱动移植与抗干扰触摸校准流程
工业HMI(基于Linux,如i.MX6ULL/RK3568+Qt)的触摸屏驱动移植,难点不在“点亮”,而在“抗干扰”——车间里变频器、电机、焊机产生的电磁噪声会耦合进触摸屏的I2C/SPI接口,导致坐标跳变、误触发。下面以Goodix GT9271电容触摸屏(I2C接口,5点触控)在i.MX6ULL上的移植和校准为例。
一、驱动移植:设备树配置与内核编译
GT9271是主流工业触控芯片,Linux内核自带了goodix.c驱动。移植只需三步:
1. 设备树节点:在i2c2总线下添加GT9271,配置中断引脚和复位引脚。
&i2c2 {
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c2>;
status = "okay";
gt9271@5d {
compatible = "goodix,gt9271";
reg = <0x5d>;
interrupt-parent = <&gpio1>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
irq-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
touchscreen-size-x = <1024>;
touchscreen-size-y = <600>;
touchscreen-inverted-x;
touchscreen-swapped-xy;
};
};
1. 内核配置:Device Drivers → Input device support → Touchscreens → Goodix GT9xx based touchscreens 设为<*>
2. 编译并替换dtb:make dtbs,拷贝到板子重启。dmesg | grep goodix 看到Goodix GT9271 device found即成功。
二、抗干扰触摸校准:去抖与滤波
工业环境下触摸屏的原始坐标常有毛刺。驱动层可以做两点处理:
1. 硬件滤波(I2C寄存器配置)
GT9271内部有滤波寄存器,上电时写入:
static int gt9271_set_filter(struct i2c_client *client) {
u8 buf[3];
// 配置去抖阈值(0x8047寄存器,值越大去抖越强)
buf[0] = 0x80; buf[1] = 0x47; buf[2] = 0x0A; // 10次连续采样一致才上报
i2c_master_send(client, buf, 3);
// 配置噪声抑制(0x8048)
buf[1] = 0x48; buf[2] = 0x03; // 中等抑制
i2c_master_send(client, buf, 3);
return 0;
}
2. 软件滑动平均(应用层或内核层)
在输入子系统中对坐标做中值滤波,消除单点跳变:
// 触摸点结构体维护最近5个坐标,取中值
#define MEDIAN_WINDOW 5
static int median_filter(int *buffer, int len) {
int tmp[MEDIAN_WINDOW];
memcpy(tmp, buffer, len * sizeof(int));
// 简单排序取中
for (int i = 0; i < len-1; i++)
for (int j = i+1; j < len; j++)
if (tmp[i] > tmp[j]) { int t = tmp[i]; tmp[i] = tmp[j]; tmp[j] = t; }
return tmp[len/2];
}
在goodix_ts_report()函数中调用该滤波,再将结果上报input子系统。
三、校准流程:tslib或手动四点校准
虽然电容屏一般免校准,但工业HMI因面板厚度、贴合误差可能需要校准。使用tslib的ts_calibrate工具,生成pointercal文件。如果不想依赖tslib,可以自己实现四点校准:
// 四点校准:屏幕四个角显示十字,记录触摸坐标与物理坐标的映射
typedef struct { int x, y; } point_t;
point_t screen_pts[4] = {{50,50},{974,50},{50,550},{974,550}}; // 物理坐标
point_t touch_pts[4]; // 用户点击后记录
// 计算仿射变换矩阵(简化:仅缩放和平移)
float scale_x = (float)(screen_pts[3].x - screen_pts[0].x) / (touch_pts[3].x - touch_pts[0].x);
float offset_x = screen_pts[0].x - touch_pts[0].x * scale_x;
// 同理Y
将scale和offset写入配置文件,Qt的QWS_MOUSE_PROTO或libinput可以加载。
四、调试与验证
• 查看原始坐标:evtest /dev/input/event1 观察触摸点,看是否有跳变。如果跳变频繁,增大硬件去抖寄存器值或软件窗口大小。
• 抗干扰测试:在触摸屏附近运行手持电钻(模拟变频器干扰),触摸不应误触发。如果误触,检查I2C走线屏蔽和电源滤波。
• 校准精度:点击屏幕四角和中心,实际坐标与期望坐标偏差应<3mm。
五、三个翻车高发点
• 中断引脚没配上拉:GT9271中断是开漏输出,外部必须上拉(4.7kΩ到3.3V),否则中断丢失导致触摸无响应。
• I2C时钟频率太高:工业环境长走线,400kHz可能通信不稳定。降到100kHz或200kHz,并在SDA/SCL加10pF电容滤波。
• 复位时序不对:GT9271上电后需要先拉低复位引脚>10ms,再拉高,然后等待>100ms才能访问I2C。驱动中goodix_reset()函数必须满足该时序。





