news 2026/10/24 6:47:34

GT9xx触摸屏驱动移植:从I2C、设备树到input多点触控上报

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
GT9xx触摸屏驱动移植:从I2C、设备树到input多点触控上报

简介:面向嵌入式Linux驱动开发者的全志R16平台GT9XX系列触摸屏驱动源码包,聚焦电容触摸控制器在内核中的适配与调试。内容围绕Goodix GT9XX芯片展开,涉及I2C/SPI通信初始化、中断注册、触点数据解析、input子系统事件上报、电源管理以及固件更新等关键环节,并兼顾全志平台中断控制器、时钟与设备树配置的移植要点,适合具备一定内核基础、希望打通TP驱动从硬件到应用链路的工程师参考。压缩包共25个文件、约483KB,以4个C源文件、2个头文件和Makefile、Kconfig为主,同时保留.o、.ko、.cmd等编译中间件与模块产物,便于对照构建流程与排查编译问题。已有1156人学习下载。包内代码按驱动主体、固件更新与工具辅助等模块拆分,目录组织紧凑;读者可从中获得较完整的驱动代码框架、模块编译组织方式与GT9XX调通思路,用于项目移植、触摸坐标校准、异常复位分析与性能优化时作参考。

1. GT9xx 触摸屏驱动的落地边界:它到底接管了哪几层

这份 GT9xx 系列触摸屏驱动面向某国产 SoC 平台的 Linux BSP,核心不是写一个能读坐标的 demo,而是把 tp 驱动完整接进 input 子系统:设备树声明 I2C 地址和 INT/RESET 引脚,probe 里做上电复位、读配置、注册 input_dev,中断线程里按 protocol B 上报多点触控。适合正在调触摸屏 bring-up 的 BSP 工程师、驱动新手,以及遇到坐标跳变、中断风暴、触摸无响应要排查的人。它不是通用 HAL,换平台要改 DTS、引脚和电源名,但寄存器解析和上报框架可以直接复用。先把它当成一条从硬件引脚到/dev/input/eventX的完整链路来看,后面每一步才有落点。

2. 先立住 input 子系统与 I2C 时序:GT9xx 的数据通路怎么选

2.1 GT9xx 的三根线:I2C 传数据,INT 报事件,RESET 定状态

GT9xx 这类触摸控制器,硬件上通常就三组关键信号:I2C 的 SCL/SDA 负责读写寄存器,INT 引脚在触摸状态变化时通知主控,RESET 引脚负责上电复位和地址选择。I2C 是慢速控制通道,不适合在中断里长时间占用,所以常见做法是 INT 触发中断,上半部只确认事件,真正的寄存器读取放到线程化中断或工作队列里。这样做的原因是 GT9xx 一次触摸可能连续上报多个点,读 0x814E 状态寄存器、再读 0x8150 起始的触点数据,全程走 I2C,放在硬中断上下文里容易把系统拖出硬实时问题。

I2C 地址常见是 7 位 0x5D 或 0x14,具体由复位时 INT 引脚电平决定。很多翻车不是驱动写错,而是 DTS 里把 8 位地址 0xBA 填进reg,或者复位时序没给够,芯片进了另一个地址。I2C 频率建议先降到 100kHz 验证,确认通路后再升到 400kHz。上拉电阻、走线长度、电源时序都会影响 ACK,先用 i2c-tools 扫到地址,再谈 probe。

# 确认 I2C 控制器编号和地址,bus 1 只是示例,按实际板子改 i2cdetect -y 1 # 读 GT9xx 产品 ID,寄存器 0x8140,读 4 字节 # w2@0x5d 表示向 0x5d 写 2 字节寄存器地址,r4 表示随后读 4 字节 i2ctransfer -f -y 1 w2@0x5d 0x81 0x40 r4 # 读配置表版本,寄存器 0x8047,读 1 字节 i2ctransfer -f -y 1 w2@0x5d 0x80 0x47 r1

上面第一条命令只验证总线上有没有设备响应,第二条才是验证寄存器通路。i2ctransfer的w2@0x5d是写两个字节的寄存器地址,r4是重复起始后读四个字节。读出来如果是全0x00或全0xFF,先别改驱动,回头查 RESET 时序和 INT 电平。产品 ID 和配置版本能稳定读出来,才说明 I2C 层通了。

2.2 为什么用 protocol B:slot 和 tracking_id 是多点触控的骨架

GT9xx 支持多点触控,input 子系统里对应的是 MT protocol B。protocol A 是每次上报所有触点,驱动自己维护状态;protocol B 用 slot 绑定触点,每个 slot 有独立的ABS_MT_TRACKING_ID,手指按下时分配 id,抬起时把 tracking_id 置为 -1。GT9xx 的触点数据里带 track id,天然适合 B 协议。常见做法是input_mt_init_slots()初始化最大触点数,触摸线程里用input_mt_slot()切槽,input_mt_report_slot_state()报按下/抬起,再填ABS_MT_POSITION_X/Y和ABS_MT_TOUCH_MAJOR,最后input_mt_sync_frame()加input_sync()收尾。

选 B 协议的理由很实际:上层手势库、Qt、Android 的 InputReader 都按 slot 取点,A 协议需要额外兼容层;B 协议下每个 slot 的 id 稳定,滑动手势不会因为触点顺序变化而断。参数上要设ABS_MT_POSITION_X的 min/max,max 来自配置表 0x8048 和 0x804A 的 X/Y 分辨率,不要拍脑袋写 1920。ABS_MT_TOUCH_MAJOR对应触点面积,GT9xx 的 size 字段可以直接映射,范围按 0 到 255 或 0 到配置值。slot 数量不要超过芯片配置的触摸点数,否则会出现空 slot 上报。

2.3 设备树先把硬件描述清楚,驱动只做翻译

设备树不是形式主义,它决定 probe 时拿到的client->irq、GPIO 编号、电源名和 I2C 地址。常见写法是把触摸屏挂在 I2C 控制器下,reg用 7 位地址,interrupt-parent指向 GPIO 中断控制器,interrupts写引脚号和触发方式,reset-gpios和int-gpios按实际原理图填。电源名要和 regulator 节点一致,否则devm_regulator_get_optional()拿不到,上电时序就会缺一步。

&i2c1 { status = "okay"; clock-frequency = <400000>; gt9xx: touchscreen@5d { compatible = "vendor,gt9xx"; reg = <0x5d>; interrupt-parent = <&pio>; interrupts = <7 1 IRQ_TYPE_EDGE_FALLING>; reset-gpios = <&pio 7 0 GPIO_ACTIVE_LOW>; int-gpios = <&pio 7 1 GPIO_ACTIVE_LOW>; vdd-supply = <&reg_tp_3v3>; iovdd-supply = <&reg_tp_1v8>; touchscreen-size-x = <1024>; touchscreen-size-y = <600>; touchscreen-swapped-x-y; status = "okay"; }; };

这段 DTS 里reg = <0x5d>是 7 位地址,不是 0xBA;interrupts的触发方式要和硬件一致,GT9xx 的 INT 一般是下降沿有效;reset-gpios用GPIO_ACTIVE_LOW表示低电平复位,驱动里gpiod_set_value_cansleep(reset, 1)是拉低。touchscreen-size-x/y可以先按屏幕分辨率填,但最终要以配置表读出的 max_x/max_y 为准。touchscreen-swapped-x-y这类通用属性用于旋转,不要一上来就在代码里写死坐标变换。

3. 从设备树到 probe:把 GT9xx 挂到国产 SoC 的 I2C 总线上

3.1 probe 的第一件事不是读坐标,而是把电和复位管好

I2C 驱动 probe 时,设备树已经帮你把client建好,但芯片不一定已经上电。顺序通常是:拿 regulator、拿 GPIO、上电、拉复位、等芯片启动、读产品 ID。很多“I2C 能扫到但读寄存器失败”的案例,都是 probe 里只做了i2c_get_clientdata,忘了给vdd和iovdd上电,或者复位释放后延时不够。GT9xx 的复位时序不用追求某个神秘数字,但要有明确的拉低、释放、等待窗口,常见做法是拉低 10ms、释放后等 50 到 100ms,再读寄存器。

static int gt9xx_probe(struct i2c_client *client) { struct gt9xx_data *ts; int ret; ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); if (!ts) return -ENOMEM; ts->client = client; ts->dev = &client->dev; i2c_set_clientdata(client, ts); ts->vdd = devm_regulator_get_optional(ts->dev, "vdd"); ts->iovdd = devm_regulator_get_optional(ts->dev, "iovdd"); if (IS_ERR(ts->vdd) || IS_ERR(ts->iovdd)) return -EPROBE_DEFER; ts->reset_gpio = devm_gpiod_get_optional(ts->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ts->reset_gpio)) return PTR_ERR(ts->reset_gpio); if (ts->vdd) regulator_enable(ts->vdd); if (ts->iovdd) regulator_enable(ts->iovdd); msleep(10); if (ts->reset_gpio) { gpiod_set_value_cansleep(ts->reset_gpio, 1); /* 拉低复位 */ msleep(10); gpiod_set_value_cansleep(ts->reset_gpio, 0); /* 释放复位 */ msleep(60); } ret = gt9xx_read_id(ts); if (ret) { dev_err(ts->dev, "read gt9xx id failed: %d\n", ret); return ret; } return gt9xx_register_input(ts); }

这段 probe 的重点是错误路径要能回滚。regulator 用devm_regulator_get_optional()是因为有些板子只给一路电源,拿不到不应该直接失败;但-EPROBE_DEFER要保留,电源节点可能晚于触摸屏加载。GPIOD_OUT_HIGH结合 DTS 的GPIO_ACTIVE_LOW,表示初始状态为无效电平,也就是不复位。msleep(60)是给芯片内部固件启动的时间,具体值可以按手册调整,但不要省。gt9xx_read_id()失败时不要继续注册 input,否则上层会看到一个永远没事件的设备。

3.2 读产品 ID 和配置表:确认 I2C 不是“假通”

I2C 能 ACK 不等于寄存器能读。GT9xx 的产品 ID 在 0x8140,配置表版本在 0x8047,分辨率在 0x8048 到 0x804B。读产品 ID 可以判断芯片是否在正常工作模式;读配置表可以拿到 max_x、max_y、触摸点数。常见做法是 probe 时读 4 字节产品 ID,再读 1 字节配置版本,如果产品 ID 全 0 或全 FF,直接返回-ENODEV。配置表不一定要在 probe 里全读,但分辨率建议读出来,后面注册 input 时用。

static int gt9xx_i2c_read(struct gt9xx_data *ts, u16 reg, u8 *buf, int len) { u8 reg_buf[2] = { reg >> 8, reg & 0xff }; struct i2c_msg msgs[2] = { { .addr = ts->client->addr, .flags = 0, .len = 2, .buf = reg_buf }, { .addr = ts->client->addr, .flags = I2C_M_RD, .len = len, .buf = buf }, }; int ret = i2c_transfer(ts->client->adapter, msgs, 2); return ret == 2 ? 0 : (ret < 0 ? ret : -EIO); } static int gt9xx_read_id(struct gt9xx_data *ts) { u8 id[4]; u8 cfg_ver; int ret; ret = gt9xx_i2c_read(ts, 0x8140, id, sizeof(id)); if (ret) return ret; if ((id[0] == 0x00 && id[1] == 0x00) || (id[0] == 0xff && id[1] == 0xff)) { dev_err(ts->dev, "invalid gt9xx id: %02x %02x\n", id[0], id[1]); return -ENODEV; } ret = gt9xx_i2c_read(ts, 0x8047, &cfg_ver, 1); if (ret) return ret; dev_info(ts->dev, "gt9xx id=%02x%02x cfg_ver=%02x\n", id[0], id[1], cfg_ver); return 0; }

gt9xx_i2c_read()用两个i2c_msg组成“写寄存器地址 + 读数据”的复合传输,i2c_transfer()返回 2 表示两条消息都成功。reg_buf是栈上变量,i2c_transfer()同步执行,生命周期没问题。产品 ID 的判断只是兜底,更严格的做法是对照芯片手册的 ID 范围。配置版本读出来可以打印,后续如果触摸参数不对,先看这个版本和配置文件是否匹配。

3.3 注册 input_dev:把能力集和 slot 数量一次设对

input 设备注册要在中断申请之前或之后都行,但建议先注册 input,再申请中断,避免中断先来、input 还没准备好。能力集要设ABS_MT_POSITION_X/Y、ABS_MT_TOUCH_MAJOR,如果要上报压力可以加ABS_MT_PRESSURE。input_mt_init_slots()的 slot 数量取配置表里的触摸点数,常见是 5 或 10,不要固定写 10。INPUT_MT_DIRECT表示直接触摸设备,上层会按屏幕坐标处理。

static int gt9xx_register_input(struct gt9xx_data *ts) { int ret; ts->input = devm_input_allocate_device(ts->dev); if (!ts->input) return -ENOMEM; ts->input->name = "gt9xx_ts"; ts->input->id.bustype = BUS_I2C; ts->input->dev.parent = ts->dev; input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->max_x, 0, 0); input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->max_y, 0, 0); input_set_abs_params(ts->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); ret = input_mt_init_slots(ts->input, ts->max_touch, INPUT_MT_DIRECT); if (ret) return ret; ret = input_register_device(ts->input); if (ret) return ret; return 0; }

ts->max_x和ts->max_y应该来自配置表 0x8048 到 0x804B,而不是 DTS 里的屏幕分辨率。屏幕分辨率和触摸有效区可能不一致,尤其是带黑边的屏。input_mt_init_slots()返回负数要直接退出,不能忽略。input_register_device()之后设备节点才会出现,后面用evtest验证时看的是这个节点。

4. 中断、坐标解析与 protocol B 上报:手指动作如何变成 input 事件

4.1 中断上半部只做确认,I2C 读取放到线程里

GT9xx 的 INT 是电平/边沿信号,触摸状态变化时拉低,主机读走数据后写 0 到 0x814E 清除。硬中断里不能做长 I2C 传输,常见做法是devm_request_threaded_irq(),primary handler 返回IRQ_WAKE_THREAD,thread handler 里读状态和坐标。触发方式用IRQF_TRIGGER_FALLING | IRQF_ONESHOT,IRQF_ONESHOT保证线程处理完之前中断线不被重复触发,避免中断风暴。如果硬件是电平触发,DTS 和代码要一致,否则会出现“读一次进一次、读不完”的现象。

static irqreturn_t gt9xx_irq_primary(int irq, void *dev_id) { struct gt9xx_data *ts = dev_id; if (gpiod_get_value_cansleep(ts->int_gpio) == 0) return IRQ_WAKE_THREAD; return IRQ_NONE; } static int gt9xx_request_irq(struct gt9xx_data *ts) { return devm_request_threaded_irq(ts->dev, ts->client->irq, gt9xx_irq_primary, gt9xx_irq_thread, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "gt9xx_ts", ts); }

gt9xx_irq_primary()只读一次 INT 引脚电平,低电平才唤醒线程,高电平返回IRQ_NONE。这一步能过滤掉抖动和误触发。IRQF_ONESHOT很重要,线程没处理完之前不会再次进入中断。ts->client->irq来自 DTS 的interrupts,如果 probe 里拿到 0,说明 DTS 中断映射没配好,先别怀疑芯片。

4.2 读 0x814E 和 0x8150:状态位、触点数、8 字节触点

GT9xx 的状态寄存器 0x814E 最高位是 buffer ready,低 4 位是当前触点数。读到 ready 后,从 0x8150 开始每个触点 8 字节:第 1 字节是 track id,第 2 到 3 字节是 X 低/高,第 4 到 5 字节是 Y 低/高,第 6 到 7 字节是 size 低/高,第 8 字节保留。坐标按 16 位拼,实际有效位宽以配置表为准。读完所有触点后,必须向 0x814E 写 0 清状态,否则下一次中断不会来,或者一直重复上报同一帧。

static irqreturn_t gt9xx_irq_thread(int irq, void *dev_id) { struct gt9xx_data *ts = dev_id; u8 status; u8 zero = 0; int ret, i, num; ret = gt9xx_i2c_read(ts, 0x814E, &status, 1); if (ret) return IRQ_HANDLED; if (!(status & 0x80)) return IRQ_HANDLED; num = status & 0x0f; if (num > ts->max_touch) num = ts->max_touch; for (i = 0; i < ts->max_touch; i++) { u8 point[8]; int id, x, y, w; if (i >= num) { input_mt_slot(ts->input, i); input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, false); continue; } ret = gt9xx_i2c_read(ts, 0x8150 + i * 8, point, 8); if (ret) continue; id = point[0] & 0x0f; x = point[1] | (point[2] << 8); y = point[3] | (point[4] << 8); w = point[5] | (point[6] << 8); input_mt_slot(ts->input, id); input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); input_report_abs(ts->input, ABS_MT_POSITION_X, x); input_report_abs(ts->input, ABS_MT_POSITION_Y, y); input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, w); } input_mt_sync_frame(ts->input); input_sync(ts->input); gt9xx_i2c_write(ts, 0x814E, &zero, 1); return IRQ_HANDLED; }

这段代码里status & 0x80判断有没有新数据,status & 0x0f取触点数。循环用ts->max_touch而不是num,是为了把未按下的 slot 显式上报抬起,避免上层残留触点。id取低 4 位,如果芯片上报的 id 超出 slot 数量,要做取模或丢弃,不能直接越界。input_mt_sync_frame()会处理 slot 状态,input_sync()提交事件帧。最后写 0 清状态,这一步漏了就是血泪教训:看起来能摸,但第二次触摸没反应。

4.3 坐标映射、旋转和边缘抖动:别在中断里写死

坐标映射分两层:硬件配置表给的是触摸有效区,DTS 给的是屏幕方向。常见旋转用touchscreen-swapped-x-y、touchscreen-inverted-x、touchscreen-inverted-y描述,驱动里读这些属性再换算。不要在中断线程里写if (board == xxx),板子一换就翻车。边缘抖动可以用clamp限制到 0 到 max,再用简单的滑动窗口或input_set_abs_params的 fuzz 参数过滤。fuzz 设 2 到 4 个像素,能过滤掉一部分 ADC 噪声,但不要设太大,否则细小的手势会丢。

static void gt9xx_map_point(struct gt9xx_data *ts, int *x, int *y) { if (ts->swap_xy) { int tmp = *x; *x = *y; *y = tmp; } if (ts->invert_x) *x = ts->max_x - *x; if (ts->invert_y) *y = ts->max_y - *y; *x = clamp(*x, 0, ts->max_x); *y = clamp(*y, 0, ts->max_y); }

swap_xy要在invert之前做,顺序反了旋转方向会不对。max_x/max_y用配置表读出的值,不要用屏幕分辨率。clamp放在最后,防止旋转后越界。如果坐标在边缘来回跳,先看evtest里的原始值,再决定是加 fuzz 还是改配置表。不要一上来就在驱动里加平均滤波,触摸响应会变慢。

5. 避坑与排查:GT9xx 在国产 SoC 板子上最容易翻车的五个点

5.1 上电、复位与 INT 电平的坑

现象:i2cdetect能看到 0x5D,但 probe 读 0x8140 全是 0xFF,或者读几次后 I2C 超时。原因:复位时序不对,或者复位时 INT 电平把芯片带进了另一个 I2C 地址;也有可能是vdd和iovdd上电顺序不对,芯片内部还没启动。解决:先用示波器看 RESET 和 INT 的上电波形,确认复位拉低至少 10ms、释放后等 50ms 以上;DTS 里reset-gpios的极性要和原理图一致;如果芯片支持地址选择,复位期间把 INT 拉到确定电平。不要只靠msleep猜,读产品 ID 成功才算过。

现象:冷启动时触摸可用,热重启后 probe 失败。原因:电源没有完全掉电,芯片还在上一次的状态里,复位释放太快。解决:在 probe 里先关一次 regulator 再开,或者加长复位低电平时间;确认reset-gpios初始状态不是释放。热重启的坑很隐蔽,建议在压力测试里加 reboot 循环。

5.2 I2C 读写与配置表的坑

现象:i2c_transfer返回-ENXIO或-EIO,但地址扫描正常。原因:DTS 的reg写成了 8 位地址 0xBA,I2C 框架按 7 位地址发,当然不通;或者 I2C 频率 400kHz 下上升沿太慢,ACK 不稳定。解决:reg = <0x5d>,不是 0xBA;先把clock-frequency降到 100000 验证,再逐级升;检查 SDA/SCL 上拉,常见是 2.2k 到 4.7k,具体看总线电容。i2c-tools 的i2cdetect只能证明地址有 ACK,不能证明寄存器可读。

现象:读配置表分辨率,max_x/max_y 和屏幕分辨率对不上,坐标只在左上角一小块。原因:配置表里的 X/Y 输出最大值不是屏幕分辨率,而是触摸有效区;或者读错了寄存器偏移,0x8048 是 X 低字节,0x8049 是 X 高字节,0x804A/0x804B 是 Y。解决:用i2ctransfer连续读 0x8047 起 8 字节,按小端拼出 max_x/max_y;注册 input 时用这个值,不要用 DTS 的touchscreen-size-x/y硬顶。换屏后一定要重读配置表。

5.3 中断与 input 上报的坑

现象:触摸能用,但手指抬起后evtest里一直有触点,或者第二次触摸没反应。原因:读完 0x814E 没有写 0 清状态,芯片认为 buffer 还没被取走;或者未按下的 slot 没有上报TRACKING_ID = -1。解决:每次线程结束前向 0x814E 写 0;循环覆盖所有 slot,对i >= num的 slot 调用input_mt_report_slot_state(..., false);确认调用了input_mt_sync_frame()。这三个动作缺一个都会出现“幽灵触点”。

现象:中断风暴,CPU 占用飙高,dmesg里能看到中断计数疯涨。原因:触发方式配成了电平触发,但线程里没有清中断源;或者IRQF_ONESHOT没加,线程还没读完又来中断。解决:DTS 用IRQ_TYPE_EDGE_FALLING,代码用IRQF_TRIGGER_FALLING | IRQF_ONESHOT;primary handler 里读 INT 电平,高电平返回IRQ_NONE;线程里确保读状态并写 0。如果硬件是低电平保持,要和硬件同事确认能否改成边沿。

现象:坐标方向反了,或者旋转 90 度后 X/Y 对调但方向不对。原因:touchscreen-swapped-x-y和touchscreen-inverted-x/y的组合顺序错了,或者 max_x/max_y 用错。解决:先在evtest里看原始坐标,确认是交换还是反相;驱动里先 swap 再 invert;max 值用配置表的值。不要在代码里写死x = 1024 - x,换屏就废。

6. 进阶验证与固化:用 evtest、i2c-tools 和压力测试把驱动压稳

6.1 三层验证:从总线到事件节点

我一般分三层验证,不跳步。第一层用i2cdetect和i2ctransfer确认地址和产品 ID;第二层用evtest看原始事件,确认 slot、tracking_id、坐标范围;第三层用压力脚本连续画圈、多点按压、反复插拔,观察dmesg有没有 I2C 超时和中断异常。三层都过,再谈交付。下面这张表是我常用的判据:

验证层命令/工具看什么不通过先查
I2C 通路i2cdetect、i2ctransfer地址 ACK、产品 ID 非全 0/FF地址、复位、上拉
input 事件evtest /dev/input/eventXslot、tracking_id、ABS_MT 坐标状态清 0、slot 上报
稳定性while循环 +dmesg -wI2C 超时、中断计数、丢点中断触发方式、电源
# 找到触摸屏事件节点,名字通常是 gt9xx_ts evtest # 只看指定节点,按 Ctrl+C 退出 evtest /dev/input/event2 # 压力测试:连续读事件,观察有没有卡死 timeout 60 cat /dev/input/event2 > /dev/null

evtest里重点看ABS_MT_SLOT和ABS_MT_TRACKING_ID,手指按下时 tracking_id 应该是一个非负值,抬起时变成 -1。如果只有ABS_MT_POSITION_X/Y没有 slot,说明 protocol B 没配对。timeout 60 cat是最粗糙的压力测试,能暴露中断风暴和 I2C 卡死,但不会模拟多点手势,正式测试还是要用上层应用画圈。

6.2 把参数固化:DTS 管硬件,配置文件管触摸参数

DTS 里只放硬件事实:I2C 地址、中断触发方式、GPIO 极性、电源名、屏幕方向。触摸配置表里的 max_x/max_y、触摸点数、固件版本放在配置文件或驱动内置数组里,不要混进 DTS。这样换屏时只换配置文件,换板时只改 DTS,边界清楚。我吃过一次亏:板子换屏后只改了touchscreen-size-x,忘了改配置表里的分辨率,坐标在右边缘被截断,查了半天才发现 max_x 还是旧值。从那以后我每次 bring-up 都先跑i2ctransfer读 0x8048,再跑evtest看原始值,最后才动映射。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 6:47:34

TOPSIS多指标综合评价实战:正向化、组合赋权与稳健性校验

简介&#xff1a;面向多准则决策方法学习与软件、插件等方案评估场景&#xff0c;这套Topsis综合评价法配套代码与数据适合具备一定MATLAB基础、希望把算法流程落到实处的读者&#xff0c;兼顾方法理解与代码实践。压缩包共2个文件&#xff0c;包含1个xlsx评价数据表与1个m脚本…

作者头像 李华
网站建设 2026/10/24 6:47:07

Win7 64位离线安装.NET Framework 4.0独立包实战指南

简介&#xff1a;这份资源是面向Windows 7 64位系统用户的.NET Framework 4.0独立安装包&#xff0c;主要解决64位环境下部分.NET应用程序因缺少运行时而无法启动、或与32位框架不兼容的问题&#xff0c;适合需要部署和运行基于.NET开发软件的普通用户与初级开发者使用。压缩包…

作者头像 李华
网站建设 2026/10/24 6:46:58

投影仪相机联合标定开源工具procamcalib实战指南

简介&#xff1a;这是一套面向计算机视觉与三维重建研究者的Java开源工具包&#xff0c;专为投影仪-相机&#xff08;ProCam&#xff09;系统几何与颜色联合校准设计&#xff0c;兼顾多相机多投影仪配置需求&#xff0c;也支持纯相机阵列标定&#xff0c;适合具备基础图像处理知…

作者头像 李华
网站建设 2026/10/24 6:43:46

管式墒情监测仪原理与应用全解析

1. 项目概述土壤墒情监测是现代农业、生态研究和环境工程中的基础性工作。记得去年在西北某农业示范基地考察时&#xff0c;当地农技员老张指着干裂的田垄对我说&#xff1a;"现在种地就像医生看病&#xff0c;光靠经验摸不准脉了&#xff0c;得靠这些听诊器。"他说的…

作者头像 李华
网站建设 2026/10/24 6:43:39

从“知道”到“做到”:一套可执行的技能学习框架

看到“skills”这个标题&#xff0c;我第一反应不是“技多不压身”这种漂亮话&#xff0c;而是另一个更扎心的问题&#xff1a;为什么我们断断续续学了不少技能&#xff0c;最后能真正派上用场的却寥寥无几&#xff1f;这些年我见过太多人收藏了一堆教程、买了好几门课&#xf…

作者头像 李华
网站建设 2026/10/24 6:41:18

小爱音箱接入小龙虾 OpenClaw 实战:喊一声「小龙虾」就能干活,附 10 个真实踩坑记录

文章目录 📖 介绍 📖 🏡 演示环境 🏡 📒 从调研到落地:一条语音链路的完整实录 📒 🔍 一、动手之前:两个关键认知 📦 明星项目已经归档了 🔄 小爱「入站」是轮询,不是 webhook ⚖️ 二、方案选型:四条路,为什么选桥接容器 🅰️ 方案 A:直接用小爱 ⇄…

作者头像 李华