当前位置: 首页 > news >正文

IMX6ULL开发板GT911触摸屏驱动移植:从内核自带goodix.c到稳定五点触控的实战解析

1. 初识GT911触摸屏驱动移植

最近在玩正点原子的IMX6ULL开发板,发现官方教程主要讲的是FT5426触摸芯片,而新开发板用的是GT911。作为一个嵌入式Linux开发者,遇到这种"教程没覆盖"的情况太常见了。好在Linux内核自带goodix.c驱动支持GT911,这让我少走了不少弯路。

GT911是汇顶科技的一款电容式触摸屏控制器,支持多点触控(最高5点)。在Linux内核中,它的驱动代码位于/drivers/input/touchscreen/goodix.c。这个驱动不仅支持GT911,还兼容GT9110、GT912等多个型号。我查了下兼容列表,确认GT911在支持范围内,这让我对移植工作有了信心。

不过内核自带的驱动往往比较基础,需要根据具体硬件进行调整。我的开发板上GT911通过I2C接口连接,地址是0x14。在开始之前,我建议你先准备好以下材料:

  • 正点原子IMX6ULL开发板
  • 带GT911触摸屏的LCD模块
  • 编译好的Linux内核源码
  • 串口调试工具
  • 万用表(用于检查硬件连接)

2. 设备树配置与驱动使能

2.1 设备树节点编写

设备树是Linux内核识别硬件的关键。我找到了内核文档中关于goodix驱动的说明(Documentation/devicetree/bindings/input/touchscreen/goodix.txt),参考它来配置设备树。

在imx6ull.dtsi文件中添加以下节点:

&i2c1 { clock-frequency = <100000>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; status = "okay"; gt911@14 { compatible = "goodix,gt911"; reg = <0x14>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_tsc>; interrupt-parent = <&gpio1>; interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; reset-gpios = <&gpio5 9 GPIO_ACTIVE_HIGH>; irq-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; }; };

这里有几个关键点需要注意:

  1. 中断引脚必须在iomuxc节点下配置
  2. 复位引脚建议放在SNVS域(我用的GPIO5_9)
  3. I2C地址要正确(0x14)

2.2 内核配置与编译

配置内核启用GT911驱动:

make menuconfig

依次进入:

Device Drivers ---> Input device support ---> Touchscreens ---> <*> Goodix I2C touchscreen

保存配置后编译内核和设备树:

make zImage dtbs -j8

编译完成后,将zImage和.dtb文件拷贝到开发板启动。这时候驱动应该能加载,但触摸屏很可能无法正常工作。

3. 硬件复位时序问题排查

3.1 现象分析

驱动加载后,我用i2c-tools测试I2C通信:

i2cdetect -y 1

发现能检测到0x14地址的设备,说明I2C通信正常。但读取配置寄存器时发现全是0:

i2cdump -f -y 1 0x14

这意味着驱动无法正确读取GT911的配置信息。经过分析,我发现内核自带的goodix.c驱动缺少关键的硬件复位时序。

3.2 复位时序实现

查阅GT911数据手册,复位需要严格按照以下时序:

  1. 复位引脚拉低至少5μs
  2. 等待10ms
  3. 复位引脚拉高
  4. 中断引脚拉低至少50μs
  5. 将中断引脚配置为输入

我参考正点原子的驱动代码,在goodix.c中添加了复位函数:

static int goodix_ts_reset(struct goodix_ts_data *ts) { int ret = 0; /* 申请复位GPIO */ if (gpio_is_valid(ts->reset_pin)) { ret = devm_gpio_request_one(&ts->client->dev, ts->reset_pin, GPIOF_OUT_INIT_HIGH, "goodix_ts_reset"); if (ret) return ret; } /* 申请中断GPIO(先作为输出) */ if (gpio_is_valid(ts->irq_pin)) { ret = devm_gpio_request_one(&ts->client->dev, ts->irq_pin, GPIOF_OUT_INIT_HIGH, "goodix_ts_irq"); if (ret) return ret; } /* 严格按照时序操作 */ gpio_set_value(ts->reset_pin, 0); // 复位GT911 msleep(10); gpio_set_value(ts->reset_pin, 1); // 停止复位 msleep(10); gpio_set_value(ts->irq_pin, 0); // 拉低INT引脚 msleep(50); gpio_direction_input(ts->irq_pin); // INT引脚设为输入 return 0; }

然后在probe函数中调用这个复位函数:

/* 获取设备树中的GPIO配置 */ ts->reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0); ts->irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0); /* 执行复位操作 */ error = goodix_ts_reset(ts); if (error) { printk("reset failed\n"); }

4. 实现稳定五点触控

4.1 原始驱动的问题

即使添加了复位时序,触摸屏能工作了,但多点触控效果很差。使用tslib测试时发现:

  • 手指移动时光标不跟随,而是跳到最终位置
  • 只能画两点间的直线,无法实现连续轨迹
  • 多点触控不稳定,经常丢失触点

这是因为内核自带的goodix.c驱动的中断处理函数比较简单,没有优化多点触控的上报机制。

4.2 优化中断处理函数

我参考了社区优化的多点触控处理代码,主要改进点包括:

  1. 更高效的数据读取方式
  2. 完善的触点状态跟踪
  3. 准确的上报机制

新的中断处理函数如下:

static irqreturn_t goodix_ts_multi_touch_irq_handler(int irq, void *dev_id) { int ret; u8 status, large_detect, touch_num = 0; int input_x, input_y, id = 0; u8 data, buf[GOODIX_CONTACT_SIZE * 5]; struct goodix_ts_data *ts = dev_id; int i; u16 touch_index = 0; static u16 last_index = 0; int pos = 0, report_num = 0; /* 读取触摸状态寄存器 */ ret = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, &data, 1); if (data == 0x00) return IRQ_HANDLED; /* 解析触摸信息 */ status = data & 0x80; large_detect = (data & 0x40) >> 6; touch_num = data & 0x0f; if (touch_num) { /* 读取所有触点数据 */ ret = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR+1, buf, GOODIX_CONTACT_SIZE*5); if (ret) return IRQ_HANDLED; id = buf[0]; touch_index |= (0x01 << id); /* 上报每个触点 */ for (i = 0; i < 5; i++) { if (touch_index & (0x01 << i)) { input_x = (buf[pos+1] | (buf[pos+2]<<8)) & 0xfff; input_y = (buf[pos+3] | (buf[pos+4]<<8)) & 0xfff; input_mt_slot(ts->input_dev, id); input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, true); input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x); input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y); report_num++; if (report_num < touch_num) { pos += 8; id = buf[pos]; touch_index |= (0x01 << id); } } else { input_mt_slot(ts->input_dev, i); input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); } } } else if (last_index) { /* 无触摸时清除上次触点 */ for (i = 0; i < 5; i++) { if (last_index & (0x01 << i)) { input_mt_slot(ts->input_dev, i); input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false); } } } last_index = touch_index; input_mt_report_pointer_emulation(ts->input_dev, true); input_sync(ts->input_dev); /* 清除中断标志 */ data = 0x00; goodix_i2c_write(ts->client, GOODIX_READ_COOR_ADDR, &data, 1); return IRQ_HANDLED; }

4.3 测试与验证

修改完成后,重新编译内核并烧写到开发板。使用tslib测试多点触控:

export TSLIB_TSDEVICE=/dev/input/event1 ts_test_mt

现在应该能看到:

  • 五点触控同时工作
  • 手指移动时光标平滑跟随
  • 可以画出连续的曲线
  • 触点识别稳定不跳动

5. 常见问题与解决方案

在实际移植过程中,我遇到了不少坑,这里总结几个典型问题:

5.1 I2C通信失败

现象:i2cdetect检测不到设备可能原因

  1. I2C地址不正确(GT911默认0x14或0x5D)
  2. 硬件连接问题(SDA/SCL接反、上拉电阻缺失)
  3. 设备树中I2C控制器未启用

解决方案

  1. 用万用表检查I2C线路
  2. 确认设备树中i2c1节点status = "okay"
  3. 尝试调整I2C地址

5.2 触摸坐标不准

现象:触摸点位置与实际位置偏差大可能原因

  1. 屏幕分辨率配置错误
  2. 坐标轴方向反了
  3. 触摸屏与LCD对齐问题

解决方案

  1. 检查goodix_read_config函数中的分辨率设置
  2. 在input_dev中调整坐标范围
  3. 考虑增加坐标校准功能

5.3 中断不触发

现象:触摸屏无反应,但I2C通信正常可能原因

  1. 中断GPIO配置错误
  2. 中断触发方式不匹配
  3. 中断线路上有干扰

解决方案

  1. 检查设备树中interrupt-gpios配置
  2. 用示波器观察中断信号
  3. 尝试调整中断触发方式(边沿/电平)

移植GT911驱动虽然遇到不少挑战,但最终实现稳定五点触控的效果还是很值得的。这个过程让我对Linux输入子系统、设备树和中断处理有了更深的理解。如果你也遇到类似问题,希望这篇文章能帮你少走弯路。

http://www.jsqmd.com/news/621586/

相关文章:

  • Hive优化参考
  • MOSN负载均衡完全教程:从基础算法到高级策略实战
  • 终极指南:JGrowing服务监控体系如何构建完整的Java应用监控解决方案
  • Autobahn|Python实战:构建高并发WAMP应用组件的10个技巧
  • 【技术底稿 10】16G Ubuntu 服务器手动部署 Ollama 0.20.4 全流程(避坑 HTTP2 错误)
  • 空气质量指数解析:PM10、PM2.5、CO、NO2、SO2的健康影响与防护指南
  • 如何利用Tree of Thoughts提升大语言模型推理能力:完整实现指南
  • 终极指南:探索golang-samples项目的最新功能与实战应用
  • M5NanoC6开发板底层驱动与ESP32-C6多协议工程实践
  • 2026年比较好的风管安装精选厂家推荐 - 品牌宣传支持者
  • 一天一个Python库:oauthlib - 轻松构建OAuth客户端和服务器兜
  • 【SITS2026官方未公开技术白皮书】:AI原生应用性能跃迁的5大硬核优化范式(含实测QPS提升237%数据)
  • 深入解析PCIe LTSSM中的Recovery.Equlization机制与多速率适配
  • Teeworlds游戏引擎架构分析:客户端与服务端核心组件
  • 弦音墨影模型压缩与量化教程:降低部署资源门槛
  • L07A音响系统分析:在尝试固化SSH服务过程中遇到的技术问题
  • Cinny状态管理:Jotai在现代React应用中的应用
  • 【数据解析】深入理解 OpenLane-V2 数据集结构与核心标注
  • Laravel与ThinkPHP5.x核心对比
  • [实战指南]从零构建并发布一款Edge浏览器效率工具插件
  • 2026年Q2农业虫害监测优质品牌推荐:植物补光灯/便携式虫害监测设备/农业虫害监测/可视化虫害监测设备/智能虫害监测设备/选择指南 - 优质品牌商家
  • Aruco_ROS:开启高效AR标记识别的机器人之旅
  • Ruoyi-vue-plus多租户权限设计避坑指南:7个常见问题及解决方案
  • 终极Sugar.js指南:让JavaScript原生对象操作变得简单高效
  • styleguide41/styleguide深度解析:CSS规范与命名约定的完整清单
  • 城通网盘解析技术深度解析:浏览器端直连解决方案实现原理与实践
  • 从SP3232E看现代便携设备RS-232接口的ESD防护与低功耗设计
  • 2024后端开发语言选择指南:Python/Java/Go/JS/Rust终极对比
  • 2026年4月市场头部工业省电空调品牌推荐分析,知名的工业省电空调机构深度剖析助力明智之选 - 品牌推荐师
  • Dify+Ollama模型搭建攻略:本地环境实战指南驼